-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[C23] Complete support for WG14 N2508 #71398
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
Conversation
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.)
@llvm/pr-subscribers-clang @llvm/pr-subscribers-openmp Author: Aaron Ballman (AaronBallman) ChangesIn 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: Patch is 26.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71398.diff 17 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5e19dbea6608486..ae851d754c84831 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -209,6 +209,12 @@ C23 Feature Support
- Clang now supports ``<stdckdint.h>`` which defines several macros for performing
checked integer arithmetic. It is also exposed in pre-C23 modes.
+- Completed the implementation of
+ `N2508 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf>`_. We
+ previously implemented allowing a label at the end of a compound statement,
+ and now we've implemented allowing a label to be followed by a declaration
+ instead of a statement.
+
Non-comprehensive list of changes in this release
-------------------------------------------------
@@ -545,6 +551,22 @@ Bug Fixes in This Version
Fixes (`#67687 <https://github.com/llvm/llvm-project/issues/67687>`_)
- Fix crash from constexpr evaluator evaluating uninitialized arrays as rvalue.
Fixes (`#67317 <https://github.com/llvm/llvm-project/issues/67317>`_)
+- Clang now properly diagnoses use of stand-alone OpenMP directives after a
+ label (including ``case`` or ``default`` labels).
+
+ Before:
+
+ .. code-block:: c++
+
+ label:
+ #pragma omp barrier // ok
+
+ After:
+
+ .. code-block:: c++
+
+ label:
+ #pragma omp barrier // error: '#pragma omp barrier' cannot be an immediate substatement
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index de180344fcc5c74..2bc72acc1375143 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -299,6 +299,12 @@ def note_missing_selector_name : Note<
def note_force_empty_selector_name : Note<
"or insert whitespace before ':' to use %0 as parameter name "
"and have an empty entry in the selector">;
+def ext_c_label_followed_by_declaration : ExtWarn<
+ "label followed by a declaration is a C23 extension">,
+ InGroup<C23>;
+def warn_c23_compat_label_followed_by_declaration : Warning<
+ "label followed by a declaration is incompatible with C standards before "
+ "C23">, InGroup<CPre23Compat>, DefaultIgnore;
def ext_c_label_end_of_compound_statement : ExtWarn<
"label at end of compound statement is a C23 extension">,
InGroup<C23>;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 30e0352c868637b..22e8c4ceea39cd6 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -410,18 +410,15 @@ class Parser : public CodeCompletionHandler {
/// Flags describing a context in which we're parsing a statement.
enum class ParsedStmtContext {
- /// This context permits declarations in language modes where declarations
- /// are not statements.
- AllowDeclarationsInC = 0x1,
/// This context permits standalone OpenMP directives.
- AllowStandaloneOpenMPDirectives = 0x2,
+ AllowStandaloneOpenMPDirectives = 0x1,
/// This context is at the top level of a GNU statement expression.
- InStmtExpr = 0x4,
+ InStmtExpr = 0x2,
/// The context of a regular substatement.
SubStmt = 0,
/// The context of a compound-statement.
- Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
+ Compound = AllowStandaloneOpenMPDirectives,
LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr)
};
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 3e7d8274aeefc52..9b47ec4fbbc51f1 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2670,7 +2670,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
case OMPD_threadprivate: {
// FIXME: Should this be permitted in C++?
- if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
+ if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
@@ -2689,7 +2689,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
case OMPD_allocate: {
// FIXME: Should this be permitted in C++?
- if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
+ if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2531147c23196ae..da991c641130921 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -235,10 +235,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
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;
@@ -698,6 +695,19 @@ 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)) {
+ if (P.getLangOpts().C23)
+ P.Diag(SubStmt->getBeginLoc(),
+ diag::warn_c23_compat_label_followed_by_declaration);
+ else
+ P.Diag(SubStmt->getBeginLoc(), diag::ext_c_label_followed_by_declaration);
+ }
+}
+
/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
/// label:
@@ -712,9 +722,7 @@ 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;
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
Token IdentTok = Tok; // Save the whole token.
ConsumeToken(); // eat the identifier.
@@ -763,6 +771,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);
@@ -781,9 +791,7 @@ 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;
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
// It is very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -909,6 +917,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());
}
@@ -924,9 +933,7 @@ 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;
+ StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives;
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -960,6 +967,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());
}
diff --git a/clang/test/C/C2x/n2508.c b/clang/test/C/C2x/n2508.c
index 2dee0b668cb4e8c..b47c1274aab965c 100644
--- a/clang/test/C/C2x/n2508.c
+++ b/clang/test/C/C2x/n2508.c
@@ -21,3 +21,14 @@ void test() {
final:
}
+void test_labels() {
+label:
+ int i = 0;
+
+ switch (i) {
+ case 1:
+ _Static_assert(true);
+ default:
+ _Static_assert(true);
+ }
+}
diff --git a/clang/test/OpenMP/barrier_ast_print.cpp b/clang/test/OpenMP/barrier_ast_print.cpp
index a8db2172c19289d..9b7398b3d5b4324 100644
--- a/clang/test/OpenMP/barrier_ast_print.cpp
+++ b/clang/test/OpenMP/barrier_ast_print.cpp
@@ -17,13 +17,13 @@ T tmain(T argc) {
static T a;
#pragma omp barrier
switch (argc) {
- case 0:
+ case 0: {
#pragma omp barrier
- break;
- default:
+ } break;
+ default: {
#pragma omp barrier
#pragma omp barrier
- break;
+ } break;
}
return a + argc;
}
@@ -35,11 +35,15 @@ T tmain(T argc) {
// CHECK-NEXT: #pragma omp barrier
// CHECK-NEXT: switch (argc) {
// CHECK-NEXT: case 0:
+// CHECK-NEXT: {
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: }
// CHECK-NEXT: break;
// CHECK-NEXT: default:
+// CHECK-NEXT: {
// CHECK-NEXT: #pragma omp barrier
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: }
// CHECK-NEXT: break;
// CHECK-NEXT: }
@@ -49,21 +53,25 @@ int main(int argc, char **argv) {
#pragma omp barrier
// CHECK-NEXT: #pragma omp barrier
switch (argc) {
- case 0:
+ case 0: {
#pragma omp barrier
#pragma omp barrier
- break;
- default:
+ } break;
+ default: {
#pragma omp barrier
- break;
+ } break;
}
// CHECK-NEXT: switch (argc) {
// CHECK-NEXT: case 0:
+// CHECK-NEXT: {
// CHECK-NEXT: #pragma omp barrier
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: }
// CHECK-NEXT: break;
// CHECK-NEXT: default:
+// CHECK-NEXT: {
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: }
// CHECK-NEXT: break;
// CHECK-NEXT: }
return tmain(argc) + tmain(argv[0][0]) + a;
diff --git a/clang/test/OpenMP/barrier_messages.cpp b/clang/test/OpenMP/barrier_messages.cpp
index 589b9c711aaae95..1dda66b9b242592 100644
--- a/clang/test/OpenMP/barrier_messages.cpp
+++ b/clang/test/OpenMP/barrier_messages.cpp
@@ -38,7 +38,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier
+#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
break;
default: {
#pragma omp barrier
@@ -50,7 +50,7 @@ T tmain(T argc) {
#pragma omp barrier
}
label:
-#pragma omp barrier
+#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
label1 : {
#pragma omp barrier
}
@@ -92,7 +92,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier
+#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
break;
default: {
#pragma omp barrier
@@ -104,7 +104,7 @@ int main(int argc, char **argv) {
#pragma omp barrier
}
label:
-#pragma omp barrier
+#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
label1 : {
#pragma omp barrier
}
diff --git a/clang/test/OpenMP/cancel_messages.cpp b/clang/test/OpenMP/cancel_messages.cpp
index fd19f1f373ef9b1..0c96beecc04b04e 100644
--- a/clang/test/OpenMP/cancel_messages.cpp
+++ b/clang/test/OpenMP/cancel_messages.cpp
@@ -71,7 +71,8 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp cancel taskgroup // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
case 1:
-#pragma omp cancel parallel // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
+#pragma omp cancel parallel // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}} \
+ expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
break;
default: {
#pragma omp cancel sections // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
@@ -83,7 +84,8 @@ int main(int argc, char **argv) {
#pragma omp cancel taskgroup // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
}
label:
-#pragma omp cancel parallel // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
+#pragma omp cancel parallel // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}} \
+ expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
label1 : {
#pragma omp cancel sections // expected-error {{orphaned 'omp cancel' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
}
diff --git a/clang/test/OpenMP/cancellation_point_messages.cpp b/clang/test/OpenMP/cancellation_point_messages.cpp
index 268cab2d80a6e40..e928449ff57a980 100644
--- a/clang/test/OpenMP/cancellation_point_messages.cpp
+++ b/clang/test/OpenMP/cancellation_point_messages.cpp
@@ -71,7 +71,8 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp cancellation point taskgroup // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
case 1:
-#pragma omp cancellation point parallel // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
+#pragma omp cancellation point parallel // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}} \
+ expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
break;
default: {
#pragma omp cancellation point sections // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
@@ -83,7 +84,8 @@ int main(int argc, char **argv) {
#pragma omp cancellation point taskgroup // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
}
label:
-#pragma omp cancellation point parallel // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
+#pragma omp cancellation point parallel // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}} \
+ expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
label1 : {
#pragma omp cancellation point sections // expected-error {{orphaned 'omp cancellation point' directives are prohibited; perhaps you forget to enclose the directive into a region?}}
}
diff --git a/clang/test/OpenMP/depobj_messages.cpp b/clang/test/OpenMP/depobj_messages.cpp
index 38617e16cab9c9a..9d750f651d81f39 100644
--- a/clang/test/OpenMP/depobj_messages.cpp
+++ b/clang/test/OpenMP/depobj_messages.cpp
@@ -59,7 +59,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp depobj(x) depend(in:s)
case 1:
-#pragma omp depobj(x) depend(in:s)
+#pragma omp depobj(x) depend(in:s) // expected-error {{'#pragma omp depobj' cannot be an immediate substatement}}
break;
default: {
#pragma omp depobj(x) depend(in:s)
@@ -71,7 +71,7 @@ T tmain(T argc) {
#pragma omp depobj(x) depend(in:s)
}
label:
-#pragma omp depobj(x) depend(in:s)
+#pragma omp depobj(x) depend(in:s) // expected-error {{'#pragma omp depobj' cannot be an immediate substatement}}
label1 : {
#pragma omp depobj(x) depend(in:s)
}
@@ -124,7 +124,7 @@ omp_depend_t x;
switch (argc) {
#pragma omp depobj(x) depend(in:s)
case 1:
-#pragma omp depobj(x) depend(in:s)
+#pragma omp depobj(x) depend(in:s) // expected-error {{'#pragma omp depobj' cannot be an immediate substatement}}
break;
default: {
#pragma omp depobj(x) depend(in:s)
@@ -136,7 +136,7 @@ omp_depend_t x;
#pragma omp depobj(x) depend(in:s)
}
label:
-#pragma omp depobj(x) depend(in:s)
+#pragma omp depobj(x) depend(in:s) // expected-error {{'#pragma omp depobj' cannot be an immediate substatement}}
label1 : {
#pragma omp depobj(x) depend(in:s)
}
diff --git a/clang/test/OpenMP/error_message.cpp b/clang/test/OpenMP/error_message.cpp
index 40f1db40fb63af2..9796a6443c0100f 100644
--- a/clang/test/OpenMP/error_message.cpp
+++ b/clang/test/OpenMP/error_message.cpp
@@ -32,8 +32,8 @@ T tmain(T argc) {
}
switch (argc) {
#pragma omp error // expected-error {{ERROR}}
- case 1:
-#pragma omp error // expected-error {{ERROR}}
+ case 1: // FIXME: error without 'at execution' is not a stand-alone directive and so this should be accepted.
+#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
break;
default: {
#pragma omp error // expected-error {{ERROR}}
@@ -45,7 +45,7 @@ T tmain(T argc) {
#pragma omp error // expected-error {{ERROR}}
}
label:
-#pragma omp error // expected-error {{ERROR}}
+#pragma omp error // expected-error {{'#pragma omp error' cannot be an immediate substatement}}
label1 : {
#pragma omp error // expected-error {{ERROR}}
}
@@ -168,7 +168,7 @@ int main(int argc, char **argv) {
// expected-error@+1 {{ERROR}}
#pragma omp error
case 1:
-// expected-error@+1 {{ERROR}}
+// expected-error@+1 {{'#pragma omp error' cannot be an immediate substatement}}
#pragma omp error
break;
default: {
@@ -183,7 +183,7 @@ int main(int argc, char **argv) {
#pragma omp error
}
label:
-// expected-error@+1 {{ERROR}}
+// expected-error@+1 {{'#pragma omp error' cannot be an immediate substatement}}
#pragma omp error
label1 : {
// expected-error@+1 {{ERROR}}
diff --git a/clang/test/OpenMP/flush_messages.cpp b/clang/test/OpenMP/flush_messages.cpp
index 1be0fb8d590adc3..ad4830b5bf94f96 100644
--- a/clang/test/OpenMP/flush_messages.cpp
+++ b/clang/test/OpenMP/flush_messages.cpp
@@ -43,7 +43,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush
+#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
break;
default: {
#pragma omp flush
@@ -55,7 +55,7 @@ T tmain(T argc) {
#pragma omp flush
}
label:
-#pragma omp flush
+#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
label1 : {
#pragma omp flush
}
@@ -107,7 +107,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush
+#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
break;
default: {
#pragma omp flush
@@ -119,7 +119,7 @@ int main(int argc, char **argv) {
#pragma omp flush
}
l...
[truncated]
|
clang/test/OpenMP/error_message.cpp
Outdated
@@ -32,8 +32,8 @@ T tmain(T argc) { | |||
} | |||
switch (argc) { | |||
#pragma omp error // expected-error {{ERROR}} | |||
case 1: | |||
#pragma omp error // expected-error {{ERROR}} | |||
case 1: // FIXME: error without 'at execution' is not a stand-alone directive and so this should be accepted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove this FIXME. I think we want 'error' to be diagnosed. The original meaning of stand-alone was directives that did not has associated user statements. This was before utility/informational directives existed. I think the intention is we only allow executable statements with associated user statements here, not declarative, utility, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM, thank you! This should be done now.
// The substatement is always a 'statement', not a 'declaration', but is | ||
// otherwise in the same context as the labeled-statement. | ||
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; | ||
StmtCtx &= ~ParsedStmtContext::AllowStandaloneOpenMPDirectives; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this deserves a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
clang/lib/Parse/ParseStmt.cpp
Outdated
if (P.getLangOpts().C23) | ||
P.Diag(SubStmt->getBeginLoc(), | ||
diag::warn_c23_compat_label_followed_by_declaration); | ||
else | ||
P.Diag(SubStmt->getBeginLoc(), diag::ext_c_label_followed_by_declaration); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (P.getLangOpts().C23) | |
P.Diag(SubStmt->getBeginLoc(), | |
diag::warn_c23_compat_label_followed_by_declaration); | |
else | |
P.Diag(SubStmt->getBeginLoc(), diag::ext_c_label_followed_by_declaration); | |
} | |
P.Diag(SubStmt->getBeginLoc(), P.getLangOpts().C23 ? | |
diag::warn_c23_compat_label_followed_by_declaration | |
: diag::ext_c_label_followed_by_declaration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but someone else must approve.
Ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
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.)