@@ -1026,6 +1026,18 @@ static const Token *findDeclarationTypeStart(const DeductionContext &ctx, const
10261026 return start;
10271027}
10281028
1029+ // Consume any run of 'const' tokens in [tok, end), advancing tok. Returns
1030+ // whether at least one 'const' was seen.
1031+ static bool skipConst (const Token *&tok, const Token *end)
1032+ {
1033+ bool seen = false ;
1034+ while (tok && tok != end && tok->str () == " const" ) {
1035+ seen = true ;
1036+ tok = tok->next ();
1037+ }
1038+ return seen;
1039+ }
1040+
10291041// Parse a type in [tok, end). Returns the token following the type or
10301042// nullptr. When |builtinOnly|, only arithmetic types are accepted (used for
10311043// C style casts where a name would be ambiguous). When |templateParams| is
@@ -1045,11 +1057,7 @@ static const Token *parseType(const DeductionContext &ctx, const Token *tok, con
10451057 while (tok && tok != end && Token::Match (tok, " static|extern|constexpr|mutable" ))
10461058 tok = tok->next ();
10471059
1048- bool constFlag = false ;
1049- while (tok && tok != end && tok->str () == " const" ) {
1050- constFlag = true ;
1051- tok = tok->next ();
1052- }
1060+ bool constFlag = skipConst (tok, end);
10531061 if (!tok || tok == end)
10541062 return nullptr ;
10551063
@@ -1109,24 +1117,18 @@ static const Token *parseType(const DeductionContext &ctx, const Token *tok, con
11091117 return nullptr ;
11101118
11111119 // trailing const of the base type ("char const")
1112- while ( tok && tok != end && tok-> str () == " const " ) {
1120+ if ( skipConst ( tok, end))
11131121 constFlag = true ;
1114- tok = tok->next ();
1115- }
11161122
11171123 // pointers
11181124 while (tok && tok != end && tok->str () == " *" ) {
11191125 if (type.pointer == 0 )
11201126 type.baseConst = constFlag;
11211127 else if (constFlag)
11221128 return nullptr ; // const between two '*' is not supported
1123- constFlag = false ;
11241129 ++type.pointer ;
11251130 tok = tok->next ();
1126- while (tok && tok != end && tok->str () == " const" ) {
1127- constFlag = true ;
1128- tok = tok->next ();
1129- }
1131+ constFlag = skipConst (tok, end);
11301132 }
11311133 type.topConst = constFlag;
11321134
@@ -1141,6 +1143,20 @@ static const Token *parseType(const DeductionContext &ctx, const Token *tok, con
11411143 return tok ? tok : end;
11421144}
11431145
1146+ // Apply array-to-pointer decay to |type| in place. Returns false when the
1147+ // result cannot be represented (a const-qualified pointer array element).
1148+ static bool decayArrayToPointer (ExprType &type)
1149+ {
1150+ if (type.pointer > 0 && type.topConst )
1151+ return false ;
1152+ if (type.pointer == 0 ) {
1153+ type.baseConst = type.topConst ;
1154+ type.topConst = false ;
1155+ }
1156+ ++type.pointer ;
1157+ return true ;
1158+ }
1159+
11441160// Check whether |nameTok| is the name of a variable declaration (looking at
11451161// the tokens before and after it) and parse the declared type.
11461162static bool parseVariableDeclaration (const DeductionContext &ctx, const Token *nameTok, ParsedType &result)
@@ -1163,27 +1179,27 @@ static bool parseVariableDeclaration(const DeductionContext &ctx, const Token *n
11631179 const Token *rbracket = nameTok->next ()->link ();
11641180 if (!rbracket || Token::simpleMatch (rbracket->next (), " [" ))
11651181 return false ;
1166- if (parsed.type . pointer > 0 && parsed. type . topConst )
1182+ if (! decayArrayToPointer ( parsed.type ) )
11671183 return false ;
1168- if (parsed.type .pointer == 0 ) {
1169- parsed.type .baseConst = parsed.type .topConst ;
1170- parsed.type .topConst = false ;
1171- }
1172- ++parsed.type .pointer ;
11731184 parsed.type .fromArray = true ;
11741185 }
11751186 result = parsed;
11761187 return true ;
11771188}
11781189
1190+ // Upper bound on how far the backward declaration/return-type search walks.
1191+ // This is a safety valve against pathological inputs, not a semantic limit: a
1192+ // declaration farther back than this is conservatively treated as not found.
1193+ constexpr int maxBackwardScanTokens = 10000 ;
1194+
11791195// Search backwards from |useTok| (which names a variable) for its
11801196// declaration, honoring scopes. Variable ids are not set yet when templates
11811197// are simplified so the search is name based and deliberately conservative.
11821198static bool findVariableType (const DeductionContext &ctx, const Token *useTok, ParsedType &result)
11831199{
11841200 int count = 0 ;
11851201 for (const Token *tok = useTok->previous (); tok; tok = tok->previous ()) {
1186- if (++count > 10000 )
1202+ if (++count > maxBackwardScanTokens )
11871203 return false ;
11881204 if (Token::Match (tok, " )|}|]" )) {
11891205 // a complete group before the current position: skip over it
@@ -1210,43 +1226,27 @@ static bool findVariableType(const DeductionContext &ctx, const Token *useTok, P
12101226}
12111227
12121228// render the tokens of an arithmetic type; the "unsigned"/"signed"/"long
1213- // long" parts are represented with token flags like the tokenizer does
1229+ // long" parts are represented with token flags like the tokenizer does.
1230+ // (isSigned is only ever set for Char, so it can be passed through uniformly.)
12141231static void renderArithType (const ExprType &type, std::vector<DeducedToken> &tokens)
12151232{
1216- switch (type.arith ) {
1217- case ArithCat::Bool:
1218- tokens.emplace_back (" bool" );
1219- break ;
1220- case ArithCat::Char:
1221- tokens.emplace_back (" char" , type.isUnsigned , false , type.isSigned );
1222- break ;
1223- case ArithCat::WChar:
1224- tokens.emplace_back (" wchar_t" );
1225- break ;
1226- case ArithCat::Short:
1227- tokens.emplace_back (" short" , type.isUnsigned );
1228- break ;
1229- case ArithCat::Int:
1230- tokens.emplace_back (" int" , type.isUnsigned );
1231- break ;
1232- case ArithCat::Long:
1233- tokens.emplace_back (" long" , type.isUnsigned );
1234- break ;
1235- case ArithCat::LongLong:
1236- tokens.emplace_back (" long" , type.isUnsigned , true );
1237- break ;
1238- case ArithCat::Float:
1239- tokens.emplace_back (" float" );
1240- break ;
1241- case ArithCat::Double:
1242- tokens.emplace_back (" double" );
1243- break ;
1244- case ArithCat::LongDouble:
1245- tokens.emplace_back (" double" , false , true );
1246- break ;
1247- default :
1248- break ;
1249- }
1233+ // indexed by ArithCat: token string, isLong flag, whether it may be unsigned
1234+ static const struct { const char *name; bool longFlag; bool canUnsigned; } info[] = {
1235+ { nullptr , false , false }, // None
1236+ { " bool" , false , false },
1237+ { " char" , false , true },
1238+ { " wchar_t" , false , false },
1239+ { " short" , false , true },
1240+ { " int" , false , true },
1241+ { " long" , false , true },
1242+ { " long" , true , true }, // LongLong
1243+ { " float" , false , false },
1244+ { " double" , false , false },
1245+ { " double" , true , false }, // LongDouble
1246+ };
1247+ const auto &e = info[static_cast <int >(type.arith )];
1248+ if (e.name )
1249+ tokens.emplace_back (e.name , e.canUnsigned && type.isUnsigned , e.longFlag , type.isSigned );
12501250}
12511251
12521252// Render the tokens of a deduced template argument. The top level const is
@@ -1290,7 +1290,7 @@ static bool findFunctionReturnType(const DeductionContext &ctx, const Token *cal
12901290 ParsedType common;
12911291 int count = 0 ;
12921292 for (const Token *tok = callTok->previous (); tok; tok = tok->previous ()) {
1293- if (++count > 10000 )
1293+ if (++count > maxBackwardScanTokens )
12941294 return false ;
12951295 if (Token::Match (tok, " )|}|]" )) {
12961296 if (!tok->link ())
@@ -1320,6 +1320,18 @@ static bool findFunctionReturnType(const DeductionContext &ctx, const Token *cal
13201320
13211321static ExprType evalExpressionType (const DeductionContext &ctx, const Token *start, const Token *end);
13221322
1323+ static bool isIntegralType (const ExprType &type)
1324+ {
1325+ return type.isIntegral ();
1326+ }
1327+
1328+ // An operand in [.., end) followed by one of these is a postfix/member/call
1329+ // expression that the flat evaluator does not model, so it bails out.
1330+ static bool stopsAtPostfix (const Token *tok, const Token *end)
1331+ {
1332+ return tok && tok != end && Token::Match (tok, " (|[|.|->|++|--" );
1333+ }
1334+
13231335// Parse one operand (including unary operators and casts); advances |tok|.
13241336static ExprType parseOperandType (const DeductionContext &ctx, const Token *&tok, const Token *end)
13251337{
@@ -1350,7 +1362,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
13501362 if (!type.valid )
13511363 return ExprType ();
13521364 tok = rpar->next ();
1353- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|-- " ))
1365+ if (stopsAtPostfix (tok, end ))
13541366 return ExprType ();
13551367 }
13561368 } else if (Token::Match (tok, " static_cast|const_cast|reinterpret_cast|dynamic_cast <" )) {
@@ -1364,7 +1376,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
13641376 return ExprType ();
13651377 tok = closing->next ()->link ()->next ();
13661378 type = castType.type ;
1367- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|-- " ))
1379+ if (stopsAtPostfix (tok, end ))
13681380 return ExprType ();
13691381 } else if (tok->str () == " sizeof" ) {
13701382 if (!Token::simpleMatch (tok->next (), " (" ) || !tok->next ()->link ())
@@ -1389,7 +1401,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
13891401 if (!type.valid )
13901402 return ExprType ();
13911403 tok = tok->next ();
1392- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|-- " ))
1404+ if (stopsAtPostfix (tok, end ))
13931405 return ExprType ();
13941406 } else if (Token::Match (tok, " bool|char|short|int|long|float|double|wchar_t (" )) {
13951407 // functional cast: int(x)
@@ -1400,7 +1412,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
14001412 return ExprType ();
14011413 tok = tok->next ()->link ()->next ();
14021414 type = castType.type ;
1403- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|-- " ))
1415+ if (stopsAtPostfix (tok, end ))
14041416 return ExprType ();
14051417 } else if (ctx.isIdentifier (tok)) {
14061418 if (tok->next () != end && Token::simpleMatch (tok->next (), " (" )) {
@@ -1412,7 +1424,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
14121424 return ExprType ();
14131425 tok = tok->next ()->link ()->next ();
14141426 type = returnType.type ;
1415- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|-- " ))
1427+ if (stopsAtPostfix (tok, end ))
14161428 return ExprType ();
14171429 } else {
14181430 // variable
@@ -1421,7 +1433,7 @@ static ExprType parseOperandType(const DeductionContext &ctx, const Token *&tok,
14211433 return ExprType ();
14221434 type = variableType.type ;
14231435 tok = tok->next ();
1424- if (tok && tok != end && Token::Match (tok, " (|[|.|->|++|--| ::|<" ))
1436+ if (stopsAtPostfix ( tok, end) || (tok && tok != end && Token::Match (tok, " ::|<" ) ))
14251437 return ExprType ();
14261438 }
14271439 } else
@@ -1559,12 +1571,8 @@ static ExprType evalExpressionType(const DeductionContext &ctx, const Token *sta
15591571 return result;
15601572 }
15611573
1562- const auto isIntegral = [](const ExprType &operand) {
1563- return operand.isIntegral ();
1564- };
1565-
15661574 if (hasShift) {
1567- if (!std::all_of (operands.cbegin (), operands.cend (), isIntegral ))
1575+ if (!std::all_of (operands.cbegin (), operands.cend (), isIntegralType ))
15681576 return ExprType ();
15691577 // the result is the promoted type of the sub expression left of the
15701578 // first shift operator
@@ -1577,7 +1585,7 @@ static ExprType evalExpressionType(const DeductionContext &ctx, const Token *sta
15771585 return promoteType (ctx.settings , result);
15781586 }
15791587
1580- if (hasBit && !std::all_of (operands.cbegin (), operands.cend (), isIntegral ))
1588+ if (hasBit && !std::all_of (operands.cbegin (), operands.cend (), isIntegralType ))
15811589 return ExprType ();
15821590
15831591 ExprType result = operands[0 ];
@@ -1679,12 +1687,7 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token *tok, const std::
16791687 // an array parameter is a pointer
16801688 const Token *rbracket = afterType->link ();
16811689 if (rbracket && !Token::simpleMatch (rbracket->next (), " [" ) && !param.isReference &&
1682- !(param.type .pointer > 0 && param.type .topConst )) {
1683- if (param.type .pointer == 0 ) {
1684- param.type .baseConst = param.type .topConst ;
1685- param.type .topConst = false ;
1686- }
1687- ++param.type .pointer ;
1690+ decayArrayToPointer (param.type )) {
16881691 afterType = rbracket->next ();
16891692 } else
16901693 parseable = false ;
@@ -1724,9 +1727,10 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token *tok, const std::
17241727 slot = tokens;
17251728 else if (slot != tokens)
17261729 failed = true ; // inconsistent deduction
1727- } else if (argTypes[i].valid ) {
1730+ } else if (candidates. size () > 1 && argTypes[i].valid ) {
17281731 // concrete parameter: count exact type matches to
1729- // disambiguate overloads
1732+ // disambiguate overloads (only needed when there is more than
1733+ // one candidate to choose between)
17301734 std::vector<DeducedToken> argTokens;
17311735 std::vector<DeducedToken> paramTokens;
17321736 if (renderDeducedType (argTypes[i], false , argTokens) &&
0 commit comments