diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2023-11-20 10:52:11 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-20 10:52:11 -0500 |
commit | 8bd06d5b65845e5e01dd899a2deb773580460b89 (patch) | |
tree | 6db45ced0f70be52f81ee5f26ee32c7cb7075495 /clang/lib/Parse/ParseStmt.cpp | |
parent | 37fa32785e23198fc9585296e990b18abfd2ba90 (diff) | |
download | llvm-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.cpp | 42 |
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()); } |