-
Notifications
You must be signed in to change notification settings - Fork 18.6k
[clang][Parser] Warn when the body of expansion statement is not a compound statement #209229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6858ff8
fac01ce
6e840d8
4079c4f
7b10efe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whelp, I think this logic is correct but I really don't agree with the design in the standard and think there's another extension hiding in here: That's invalid per the standard because the standard requires a compound-statement and that grammar production cannot have a leading attribute. If WG21 used statement instead, then a leading attribute would be accepted as you'd expect. I think the diagnostic text will be confusing in that situation because there is a compound statement. That suggests we want to handle attributes with their own diagnostic, but that would mean we'd need to get much better about recognizing attributes instead of looking for a single token. Ideally, we'd have a Other test cases to consider would be Objective-C++ or lambdas in C++, so it's not just attributes:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean, our logic could actually warn by checking the next token is
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly. The cases I was worried about for token lookahead also involved lexer stuff like and whether anything can usefully produce an annotation token before the compound statement.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I also think we should just check if the next token is
Code completion maybe? |
||
| 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()); | ||
| } | ||
|
|
||
|
|
||
| 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}} | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.