in absl/debugging/internal/demangle.cc [1161:1233]
static bool ParseType(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
// We should check CV-qualifers, and PRGC things first.
//
// CV-qualifiers overlap with some operator names, but an operator name is not
// valid as a type. To avoid an ambiguity that can lead to exponential time
// complexity, refuse to backtrack the CV-qualifiers.
//
// _Z4aoeuIrMvvE
// => _Z 4aoeuI rM v v E
// aoeu<operator%=, void, void>
// => _Z 4aoeuI r Mv v E
// aoeu<void void::* restrict>
//
// By consuming the CV-qualifiers first, the former parse is disabled.
if (ParseCVQualifiers(state)) {
const bool result = ParseType(state);
if (!result) state->parse_state = copy;
return result;
}
state->parse_state = copy;
// Similarly, these tag characters can overlap with other <name>s resulting in
// two different parse prefixes that land on <template-args> in the same
// place, such as "C3r1xI...". So, disable the "ctor-name = C3" parse by
// refusing to backtrack the tag characters.
if (ParseCharClass(state, "OPRCG")) {
const bool result = ParseType(state);
if (!result) state->parse_state = copy;
return result;
}
state->parse_state = copy;
if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
return true;
}
state->parse_state = copy;
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
}
state->parse_state = copy;
if (ParseBuiltinType(state) || ParseFunctionType(state) ||
ParseClassEnumType(state) || ParseArrayType(state) ||
ParsePointerToMemberType(state) || ParseDecltype(state) ||
// "std" on its own isn't a type.
ParseSubstitution(state, /*accept_std=*/false)) {
return true;
}
if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
return true;
}
state->parse_state = copy;
// Less greedy than <template-template-param> <template-args>.
if (ParseTemplateParam(state)) {
return true;
}
if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
ParseOneCharToken(state, '_')) {
return true;
}
state->parse_state = copy;
return false;
}