Skip to content

Commit eecd903

Browse files
author
Your Name
committed
Simplify
1 parent 2c68b09 commit eecd903

1 file changed

Lines changed: 80 additions & 76 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 80 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
11461162
static 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.
11821198
static 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.)
12141231
static 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

13211321
static 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|.
13241336
static 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

Comments
 (0)