aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseStmt.cpp
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2023-11-20 10:52:11 -0500
committerGitHub <noreply@github.com>2023-11-20 10:52:11 -0500
commit8bd06d5b65845e5e01dd899a2deb773580460b89 (patch)
tree6db45ced0f70be52f81ee5f26ee32c7cb7075495 /clang/lib/Parse/ParseStmt.cpp
parent37fa32785e23198fc9585296e990b18abfd2ba90 (diff)
downloadllvm-8bd06d5b65845e5e01dd899a2deb773580460b89.zip
llvm-8bd06d5b65845e5e01dd899a2deb773580460b89.tar.gz
llvm-8bd06d5b65845e5e01dd899a2deb773580460b89.tar.bz2
[C23] Complete support for WG14 N2508 (#71398)
In Clang 16, we implemented the ability to add a label at the end of a compound statement. These changes complete the implementation by allowing a label to be followed by a declaration in C. Note, this seems to have fixed an issue with some OpenMP stand-alone directives not being properly diagnosed as per: https://www.openmp.org/spec-html/5.1/openmpsu19.html#x34-330002.1.3 (The same requirement exists in OpenMP 5.2 as well.)
Diffstat (limited to 'clang/lib/Parse/ParseStmt.cpp')
-rw-r--r--clang/lib/Parse/ParseStmt.cpp42
1 files changed, 29 insertions, 13 deletions
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 924f27d..918afdc 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -235,10 +235,7 @@ Retry:
auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) &&
llvm::all_of(GNUAttrs, IsStmtAttr);
- if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
- (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
- ParsedStmtContext()) &&
- ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
+ if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl;
@@ -701,6 +698,18 @@ StmtResult Parser::ParseSEHLeaveStatement() {
return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope());
}
+static void DiagnoseLabelFollowedByDecl(Parser &P, const Stmt *SubStmt) {
+ // When in C mode (but not Microsoft extensions mode), diagnose use of a
+ // label that is followed by a declaration rather than a statement.
+ if (!P.getLangOpts().CPlusPlus && !P.getLangOpts().MicrosoftExt &&
+ isa<DeclStmt>(SubStmt)) {
+ P.Diag(SubStmt->getBeginLoc(),
+ P.getLangOpts().C23
+ ? diag::warn_c23_compat_label_followed_by_declaration
+ : diag::ext_c_label_followed_by_declaration);
+ }
+}
+
/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
/// label:
@@ -715,9 +724,10 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
+ // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a
+ // substatement in a selection statement, in place of the loop body in an
+ // iteration statement, or in place of the statement that follows a label.
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
Token IdentTok = Tok; // Save the whole token.
ConsumeToken(); // eat the identifier.
@@ -766,6 +776,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ DiagnoseLabelFollowedByDecl(*this, SubStmt.get());
+
LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
IdentTok.getLocation());
Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
@@ -784,9 +796,10 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
bool MissingCase, ExprResult Expr) {
assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
+ // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a
+ // substatement in a selection statement, in place of the loop body in an
+ // iteration statement, or in place of the statement that follows a label.
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
// It is very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -912,6 +925,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// Broken sub-stmt shouldn't prevent forming the case statement properly.
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(SourceLocation());
+ DiagnoseLabelFollowedByDecl(*this, SubStmt.get());
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
}
@@ -927,9 +941,10 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
+ // [OpenMP 5.1] 2.1.3: A stand-alone directive may not be used in place of a
+ // substatement in a selection statement, in place of the loop body in an
+ // iteration statement, or in place of the statement that follows a label.
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -963,6 +978,7 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ DiagnoseLabelFollowedByDecl(*this, SubStmt.get());
return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
SubStmt.get(), getCurScope());
}