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.imschwei...@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@+1 {{expected expression}} expected-error@+1 {{expected 
')'}} expected-warning@+1 {{missing terminating '"' character}} 
expected-note@+1 {{to match this '('}}
+  #pragma omp parallel message("unterminated
+
+  // Unterminated clause
+  // expected-error@+1 {{expected ')'}} expected-note@+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@+1 {{expected ')'}} expected-note@+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;

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to