Skip to content

Commit a6857a5

Browse files
committed
Some parsing improvements
1 parent 899a83b commit a6857a5

File tree

6 files changed

+51
-15
lines changed

6 files changed

+51
-15
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,10 @@ def err_expansion_stmt_requires_range : Error<
457457
"expansion statement must be a range-based for loop">;
458458
def err_expansion_stmt_requires_cxx2c : Error<
459459
"expansion statements are only supported in C++2c">;
460+
def err_for_template : Error<
461+
"'for template' is invalid; use 'template for' instead">;
462+
def err_expansion_stmt_invalid_kw : Error<
463+
"'template %0' is invalid">;
460464

461465
def err_expected_case_before_expression: Error<
462466
"expected 'case' keyword before expression">;

clang/include/clang/Parse/Parser.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4189,7 +4189,7 @@ class Parser : public CodeCompletionHandler {
41894189
llvm::function_ref<void()> ExpressionStarts =
41904190
llvm::function_ref<void()>(),
41914191
bool FailImmediatelyOnInvalidExpr = false,
4192-
bool StopAtRBraceAfterComma = false);
4192+
bool ParsingExpansionInitList = false);
41934193

41944194
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
41954195
/// used for misc language extensions.
@@ -7531,7 +7531,8 @@ class Parser : public CodeCompletionHandler {
75317531
/// expansion-init-list
75327532
/// \endverbatim
75337533
StmtResult ParseExpansionStatement(SourceLocation *TrailingElseLoc,
7534-
LabelDecl *PrecedingLabel);
7534+
LabelDecl *PrecedingLabel,
7535+
SourceLocation TemplateLoc);
75357536

75367537
StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
75377538
SourceLocation *TrailingElseLoc,

clang/lib/Parse/ParseExpr.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3167,7 +3167,7 @@ void Parser::injectEmbedTokens() {
31673167
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
31683168
llvm::function_ref<void()> ExpressionStarts,
31693169
bool FailImmediatelyOnInvalidExpr,
3170-
bool StopAtRBraceAfterComma) {
3170+
bool ParsingExpansionInitList) {
31713171
bool SawError = false;
31723172
while (true) {
31733173
if (ExpressionStarts)
@@ -3197,10 +3197,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
31973197
if (FailImmediatelyOnInvalidExpr)
31983198
break;
31993199

3200-
if (StopAtRBraceAfterComma)
3201-
SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch);
3202-
else
3203-
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
3200+
// We expect '}' rather than ')' at the end of an expansion-init-list.
3201+
SkipUntil(tok::comma,
3202+
ParsingExpansionInitList ? tok::r_brace : tok::r_paren,
3203+
StopAtSemi | StopBeforeMatch);
32043204
} else {
32053205
Exprs.push_back(Expr.get());
32063206
}
@@ -3211,7 +3211,8 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
32113211
Token Comma = Tok;
32123212
ConsumeToken();
32133213

3214-
if (StopAtRBraceAfterComma && Tok.is(tok::r_brace))
3214+
// CWG 3061: Trailing commas are allowed in expansion-init-lists.
3215+
if (ParsingExpansionInitList && Tok.is(tok::r_brace))
32153216
break;
32163217

32173218
checkPotentialAngleBracketDelimiter(Comma);

clang/lib/Parse/ParseInit.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,10 @@ ExprResult Parser::ParseExpansionInitList() {
522522

523523
ExprVector InitExprs;
524524

525-
// CWG 3061: Accept a trailing comma here.
526525
if (!Tok.is(tok::r_brace) &&
527526
ParseExpressionList(InitExprs, /*ExpressionStarts=*/{},
528527
/*FailImmediatelyOnInvalidExpr=*/false,
529-
/*StopAtRBraceAfterComma=*/true)) {
528+
/*ParsingExpansionInitList=*/true)) {
530529
T.consumeClose();
531530
return ExprError();
532531
}

clang/lib/Parse/ParseStmt.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,23 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
271271
return ParseForStatement(TrailingElseLoc, PrecedingLabel);
272272
}
273273

274-
return ParseExpansionStatement(TrailingElseLoc, PrecedingLabel);
274+
SourceLocation TemplateLoc = ConsumeToken();
275+
return ParseExpansionStatement(TrailingElseLoc, PrecedingLabel,
276+
TemplateLoc);
277+
}
278+
279+
// Since 'template for' is a thing, users might reasonably try to write
280+
// 'template while' or something like that; diagnose that here for better
281+
// QOI (and basically just ignore the 'template' token for error recovery).
282+
if (NextToken().isOneOf(tok::kw_while, tok::kw_do)) {
283+
bool IsWhile = NextToken().is(tok::kw_while);
284+
Diag(Tok.getLocation(), diag::err_expansion_stmt_invalid_kw)
285+
<< (IsWhile ? "while" : "do");
286+
287+
ConsumeToken();
288+
if (IsWhile)
289+
return ParseWhileStatement(TrailingElseLoc, PrecedingLabel);
290+
return ParseDoStatement(PrecedingLabel);
275291
}
276292

277293
SourceLocation DeclEnd;
@@ -304,6 +320,19 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
304320
SemiError = "do/while";
305321
break;
306322
case tok::kw_for: // C99 6.8.5.3: for-statement
323+
// Correct 'for template' to 'template for'.
324+
if (NextToken().is(tok::kw_template)) {
325+
Diag(Tok.getLocation(), diag::err_for_template)
326+
<< FixItHint::CreateReplacement(
327+
SourceRange(Tok.getLocation(), NextToken().getEndLoc()),
328+
"template for");
329+
Tok.setKind(tok::kw_template);
330+
SourceLocation TemplateLoc = ConsumeToken();
331+
Tok.setKind(tok::kw_for);
332+
return ParseExpansionStatement(TrailingElseLoc, PrecedingLabel,
333+
TemplateLoc);
334+
}
335+
307336
return ParseForStatement(TrailingElseLoc, PrecedingLabel);
308337

309338
case tok::kw_goto: // C99 6.8.6.1: goto-statement
@@ -2706,9 +2735,9 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
27062735
}
27072736

27082737
StmtResult Parser::ParseExpansionStatement(SourceLocation *TrailingElseLoc,
2709-
LabelDecl *PrecedingLabel) {
2710-
assert(Tok.is(tok::kw_template) && NextToken().is(tok::kw_for));
2711-
SourceLocation TemplateLoc = ConsumeToken();
2738+
LabelDecl *PrecedingLabel,
2739+
SourceLocation TemplateLoc) {
2740+
assert(Tok.is(tok::kw_for));
27122741
DiagCompat(TemplateLoc, diag_compat::expansion_statements);
27132742

27142743
CXXExpansionStmtDecl *ExpansionDecl =

clang/test/Parser/cxx2c-expansion-statements.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ void bad() {
4040
template for (3 : "error") // expected-error {{expansion statement declaration must declare a variable}} \
4141
expected-error {{expansion statement must be a range-based for loop}} expected-error {{TODO (expansion statements)}}
4242
;
43-
template while (true) {} // expected-error {{expected '<' after 'template'}}
43+
template while (true) {} // expected-error {{'template while' is invalid}}
44+
template do {} while (true); // expected-error {{'template do' is invalid}}
45+
for template (int x : {}) {} // expected-error {{'for template' is invalid; use 'template for' instead}} expected-error {{TODO (expansion statements)}}
4446
}
4547

4648
void good() {

0 commit comments

Comments
 (0)