[clang] [llvm] [OpenMP][clang] 6.0: parsing/sema for message/severity for parallel (PR #146093)
Robert Imschweiler via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 27 08:27:24 PDT 2025
https://github.com/ro-i created https://github.com/llvm/llvm-project/pull/146093
Implement parsing and semantic analysis support for the message and severity clauses that have been added to the parallel directive in OpenMP 6.0, 12.1.
>From b01bdf107f80f0f023270326e4a16b1dcadd69d8 Mon Sep 17 00:00:00 2001
From: Robert Imschweiler <robert.imschweiler at amd.com>
Date: Fri, 27 Jun 2025 10:07:01 -0500
Subject: [PATCH] [OpenMP][clang] 6.0: parsing/sema for message/severity for
parallel
Implement parsing and semantic analysis support for the message and
severity clauses that have been added to the parallel directive in
OpenMP 6.0, 12.1.
---
clang/include/clang/AST/OpenMPClause.h | 6 +-
clang/lib/Sema/SemaOpenMP.cpp | 4 +-
clang/test/OpenMP/parallel_ast_print.cpp | 24 ++---
.../test/OpenMP/parallel_message_messages.cpp | 89 +++++++++++++++++++
.../OpenMP/parallel_severity_messages.cpp | 70 +++++++++++++++
llvm/include/llvm/Frontend/OpenMP/OMP.td | 2 +
6 files changed, 179 insertions(+), 16 deletions(-)
create mode 100644 clang/test/OpenMP/parallel_message_messages.cpp
create mode 100644 clang/test/OpenMP/parallel_severity_messages.cpp
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index c6f99fb21a0f0..8b602f49aefde 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -1775,7 +1775,8 @@ class OMPAtClause final : public OMPClause {
}
};
-/// This represents 'severity' clause in the '#pragma omp error' directive
+/// This represents the 'severity' clause in the '#pragma omp error' and the
+/// '#pragma omp parallel' directives.
///
/// \code
/// #pragma omp error severity(fatal)
@@ -1855,7 +1856,8 @@ class OMPSeverityClause final : public OMPClause {
}
};
-/// This represents 'message' clause in the '#pragma omp error' directive
+/// This represents the 'message' clause in the '#pragma omp error' and the
+/// '#pragma omp parallel' directives.
///
/// \code
/// #pragma omp error message("GNU compiler required.")
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a30acbe9a4bca..4ecc9b0d4c5c8 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6620,6 +6620,8 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
case OMPC_affinity:
case OMPC_bind:
case OMPC_filter:
+ case OMPC_severity:
+ case OMPC_message:
continue;
case OMPC_allocator:
case OMPC_flush:
@@ -6637,8 +6639,6 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
case OMPC_match:
case OMPC_when:
case OMPC_at:
- case OMPC_severity:
- case OMPC_message:
default:
llvm_unreachable("Unexpected clause");
}
diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp
index 948baaff30d89..15439ea31215a 100644
--- a/clang/test/OpenMP/parallel_ast_print.cpp
+++ b/clang/test/OpenMP/parallel_ast_print.cpp
@@ -173,13 +173,13 @@ T tmain(T argc, T *argv) {
foo();
#endif
#ifdef OMP60
-#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(strict: C) copyin(S<T>::TS, thrp) proc_bind(primary) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10])
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(strict: C) copyin(S<T>::TS, thrp) proc_bind(primary) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10]) message("msg") severity(fatal)
foo();
#endif
#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) reduction(task,+:argc)
foo();
#ifdef OMP60
-#pragma omp parallel if (C) num_threads(strict: s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) reduction(task,+:argc)
+#pragma omp parallel if (C) num_threads(strict: s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) reduction(task,+:argc) message("msg") severity(warning)
foo();
#endif
return 0;
@@ -196,11 +196,11 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(C) copyin(S<T>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10])
// OMP51-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: C) copyin(S<T>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10])
+// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: C) copyin(S<T>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10]) message("msg") severity(fatal)
// OMP60-NEXT: foo()
// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) reduction(task, +: argc)
// CHECK-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel if(C) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) reduction(task, +: argc)
+// OMP60-NEXT: #pragma omp parallel if(C) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) reduction(task, +: argc) message("msg") severity(warning)
// OMP60-NEXT: foo()
// CHECK: template<> int tmain<int, 5>(int argc, int *argv) {
// CHECK-NEXT: int b = argc, c, d, e, f, g;
@@ -213,11 +213,11 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(5) copyin(S<int>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10])
// OMP51-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 5) copyin(S<int>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10])
+// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 5) copyin(S<int>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10]) message("msg") severity(fatal)
// OMP60-NEXT: foo()
// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) reduction(task, +: argc)
// CHECK-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel if(5) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) reduction(task, +: argc)
+// OMP60-NEXT: #pragma omp parallel if(5) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) reduction(task, +: argc) message("msg") severity(warning)
// OMP60-NEXT: foo()
// CHECK: template<> long tmain<long, 1>(long argc, long *argv) {
// CHECK-NEXT: long b = argc, c, d, e, f, g;
@@ -230,11 +230,11 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// OMP51-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(1) copyin(S<long>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10])
// OMP51-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 1) copyin(S<long>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10])
+// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(strict: 1) copyin(S<long>::TS,thrp) proc_bind(primary) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10]) message("msg") severity(fatal)
// OMP60-NEXT: foo()
// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) reduction(task, +: argc)
// CHECK-NEXT: foo()
-// OMP60-NEXT: #pragma omp parallel if(1) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) reduction(task, +: argc)
+// OMP60-NEXT: #pragma omp parallel if(1) num_threads(strict: s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) reduction(task, +: argc) message("msg") severity(warning)
// OMP60-NEXT: foo()
enum Enum { };
@@ -256,8 +256,8 @@ int main (int argc, char **argv) {
foo();
// CHECK-NEXT: foo();
#ifdef OMP60
-#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(| : c, d, arr1[argc]) reduction(* : e, arr[:10][0:argc]) allocate(e)
-// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(|: c,d,arr1[argc]) reduction(*: e,arr[:10][0:argc]) allocate(e)
+#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(| : c, d, arr1[argc]) reduction(* : e, arr[:10][0:argc]) allocate(e) message("msg") severity(fatal)
+// OMP60-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(parallel: argc > 0) num_threads(strict: ee) copyin(a) proc_bind(spread) reduction(|: c,d,arr1[argc]) reduction(*: e,arr[:10][0:argc]) allocate(e) message("msg") severity(fatal)
foo();
// OMP60-NEXT: foo();
#endif
@@ -266,8 +266,8 @@ int main (int argc, char **argv) {
foo();
// CHECK-NEXT: foo()
#ifdef OMP60
-#pragma omp parallel allocate(e) if (b) num_threads(strict: c) proc_bind(close) reduction(^:e, f) reduction(&& : g, arr[0:argc][:10])
-// OMP60-NEXT: #pragma omp parallel allocate(e) if(b) num_threads(strict: c) proc_bind(close) reduction(^: e,f) reduction(&&: g,arr[0:argc][:10])
+#pragma omp parallel allocate(e) if (b) num_threads(strict: c) proc_bind(close) reduction(^:e, f) reduction(&& : g, arr[0:argc][:10]) message("msg") severity(warning)
+// OMP60-NEXT: #pragma omp parallel allocate(e) if(b) num_threads(strict: c) proc_bind(close) reduction(^: e,f) reduction(&&: g,arr[0:argc][:10]) message("msg") severity(warning)
foo();
// OMP60-NEXT: foo()
#endif
diff --git a/clang/test/OpenMP/parallel_message_messages.cpp b/clang/test/OpenMP/parallel_message_messages.cpp
new file mode 100644
index 0000000000000..470fadc032280
--- /dev/null
+++ b/clang/test/OpenMP/parallel_message_messages.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -verify=expected -fopenmp -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected -fopenmp-simd -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized
+
+void foo() {}
+
+template <class T, typename S, int N>
+T tmain(T argc, S **argv) {
+ // Correct usage
+ #pragma omp parallel message("correct message")
+
+ // Missing parentheses
+ #pragma omp parallel message // expected-error {{expected '(' after 'message'}}
+
+ // Empty parentheses
+ #pragma omp parallel message() // expected-error {{expected expression}}
+
+ // Non-string literal
+ #pragma omp parallel message(123) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+ #pragma omp parallel message(argc) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+ #pragma omp parallel message(argv[0]) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+
+ // Multiple arguments
+ #pragma omp parallel message("msg1", "msg2") // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+ // Unterminated string
+ // expected-error at +1 {{expected expression}} expected-error at +1 {{expected ')'}} expected-warning at +1 {{missing terminating '"' character}} expected-note at +1 {{to match this '('}}
+ #pragma omp parallel message("unterminated
+
+ // Unterminated clause
+ // expected-error at +1 {{expected ')'}} expected-note at +1 {{to match this '('}}
+ #pragma omp parallel message("msg"
+
+ // Extra tokens after clause
+ #pragma omp parallel message("msg") extra // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
+
+ // Multiple message clauses
+ #pragma omp parallel message("msg1") message("msg2") // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'message' clause}}
+
+ // Message clause with other clauses (should be valid, but test for interaction)
+ #pragma omp parallel message("msg") num_threads(2)
+
+ // Message clause with invalid clause
+ #pragma omp parallel message("msg") invalid_clause // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
+
+ // Message clause with missing string and other clause
+ #pragma omp parallel message() num_threads(2) // expected-error {{expected expression}}
+
+ // Message clause with macro that is not a string
+ #define NOT_A_STRING 123
+ #pragma omp parallel message(NOT_A_STRING) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+
+ // Message clause with template parameter that is not a string
+ #pragma omp parallel message(N) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+
+ // Message clause with macro that is a string
+ #define A_STRING "macro string"
+ #pragma omp parallel message(A_STRING)
+
+ // Message clause with concatenated string literals
+ #pragma omp parallel message("hello" " world")
+
+ // Message clause with wide string literal
+ #pragma omp parallel message(L"wide string")
+
+ // Message clause with UTF-8 string literal
+ #pragma omp parallel message(u8"utf8 string")
+
+ // Message clause with raw string literal
+ #pragma omp parallel message(R"(raw string)")
+
+ foo();
+
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ // Correct usage
+ #pragma omp parallel message("main correct")
+
+ // Invalid: missing string
+ #pragma omp parallel message() // expected-error {{expression}}
+
+ // Invalid: non-string
+ #pragma omp parallel message(argc) // expected-warning {{expected string literal in 'clause message' - ignoring}}
+
+ foo();
+
+ return tmain<int, char, 3>(argc, argv);
+}
diff --git a/clang/test/OpenMP/parallel_severity_messages.cpp b/clang/test/OpenMP/parallel_severity_messages.cpp
new file mode 100644
index 0000000000000..b1cff762d9bd8
--- /dev/null
+++ b/clang/test/OpenMP/parallel_severity_messages.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -verify=expected -fopenmp -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected -fopenmp-simd -fopenmp-version=60 -ferror-limit 100 %s -Wuninitialized
+
+void foo() {}
+
+template <class T, typename S, int N>
+T tmain(T argc, S **argv) {
+ // Correct usages
+ #pragma omp parallel severity(fatal)
+ #pragma omp parallel severity(warning)
+
+ // Missing parentheses
+ #pragma omp parallel severity // expected-error {{expected '(' after 'severity'}}
+
+ // Empty parentheses
+ #pragma omp parallel severity() // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ // Invalid value
+ #pragma omp parallel severity(error) // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+ #pragma omp parallel severity(unknown) // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ // Multiple arguments
+ #pragma omp parallel severity(fatal, warning) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+ // Unterminated clause
+ // expected-error at +1 {{expected ')'}} expected-note at +1 {{to match this '('}}
+ #pragma omp parallel severity(fatal
+
+ // Extra tokens after clause
+ #pragma omp parallel severity(fatal) extra // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
+
+ // Multiple severity clauses
+ #pragma omp parallel severity(fatal) severity(warning) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'severity' clause}}
+
+ // Severity clause with other clauses (should be valid)
+ #pragma omp parallel severity(warning) num_threads(2)
+
+ // Severity clause with invalid clause
+ #pragma omp parallel severity(fatal) invalid_clause // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
+
+ // Severity clause with macro that is not a valid value
+ #define NOT_A_SEVERITY 123
+ #pragma omp parallel severity(NOT_A_SEVERITY) // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ // Severity clause with macro that is a valid value
+ #define FATAL fatal
+ #pragma omp parallel severity(FATAL)
+
+ // Severity clause with template parameter that is not a valid value
+ #pragma omp parallel severity(N) // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ foo();
+
+ return argc;
+}
+
+int main(int argc, char **argv) {
+ // Correct usage
+ #pragma omp parallel severity(fatal)
+
+ // Invalid: missing value
+ #pragma omp parallel severity() // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ // Invalid: non-keyword
+ #pragma omp parallel severity(argc) // expected-error {{expected 'fatal' or 'warning' in OpenMP clause 'severity'}}
+
+ foo();
+
+ return tmain<int, char, 3>(argc, argv);
+}
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index f2610011a7e04..f218d1f813533 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -960,6 +960,8 @@ def OMP_Parallel : Directive<[Spelling<"parallel">]> {
VersionedClause<OMPC_If>,
VersionedClause<OMPC_NumThreads>,
VersionedClause<OMPC_ProcBind>,
+ VersionedClause<OMPC_Message>,
+ VersionedClause<OMPC_Severity>,
];
let association = AS_Block;
let category = CA_Executable;
More information about the llvm-commits
mailing list