Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">;
def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
def EmptyInitStatement : DiagGroup<"empty-init-stmt">;
def ExpansionStmtBody : DiagGroup<"expansion-stmt-missing-braces">;
def ExportUnnamed : DiagGroup<"export-unnamed">;
def ExtraSemiStmt : DiagGroup<"extra-semi-stmt", [EmptyInitStatement]>;
def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi,
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ def err_expansion_stmt_requires_cxx2c : Error<
"expansion statements are only supported in C++2c">;
def err_for_template : Error<
"'for template' is invalid; use 'template for' instead">;
def ext_expansion_stmt_body_not_compound_stmt : Extension<
"ISO C++ requires the body of an expansion statement to be a compound statement">,
InGroup<ExpansionStmtBody>;
def ext_expansion_stmt_body_attr : Extension<
"ISO C++ forbids attributes before the compound statement of an expansion statement">,
InGroup<ExpansionStmtBody>;

def err_expected_case_before_expression: Error<
"expected 'case' keyword before expression">;
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
// the other parts.
getCurScope()->EnterLoopBody(PrecedingLabel);

bool BodyStartsWithAttr = Tok.isOneOf(tok::l_square, tok::kw___attribute);
SourceLocation BodyBeginLoc = Tok.getLocation();

// C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
Expand Down Expand Up @@ -2379,6 +2382,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
return StmtError();
}

// attribute-specifier without attribute (`[[]]`) isn't in AST.
// `__declspec()` is only applied to declarations, so we can ignore it.
if (!isa<CompoundStmt>(Body.get()) || BodyStartsWithAttr)
Diag(BodyBeginLoc,
isa<CompoundStmt>(Body.get()->stripLabelLikeStatements())
? diag::ext_expansion_stmt_body_attr
: diag::ext_expansion_stmt_body_not_compound_stmt);

return Actions.FinishCXXExpansionStmt(ForRangeStmt.get(), Body.get());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -Wexpansion-stmt-missing-braces -verify
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -Wpedantic -verify

void f() {
template for (int x : {1})
template for (int y : {1}) // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
; // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
template for (int x : {1})
if (x) // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
;
template for (int x : {1})
switch (x) // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
;
template for (int x : {1})
for (;;) // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
;
template for (int x : {1})
while (x) // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
;
template for (int x : {1})
do // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
;
while (x);
template for (int x : {1})
return; // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
template for (int x : {1})
[] {}(); // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
template for (int x : {1})
[ // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
[]] if (x)
;
template for (int x : {1})
[ // expected-warning {{ISO C++ requires the body of an expansion statement to be a compound statement}}
[likely]] if (x)
;
template for (int x : {1})
[ // expected-warning {{ISO C++ forbids attributes before the compound statement of an expansion statement}}
[]] {}
template for (int x : {1})
[ // expected-warning {{ISO C++ forbids attributes before the compound statement of an expansion statement}}
[likely]] {}
template for (int x : {1})
__attribute__ // expected-warning {{ISO C++ forbids attributes before the compound statement of an expansion statement}}
(()) {}
template for (int x : {1})
foo: {} // expected-error {{labels are not allowed in expansion statements}}
}
Loading