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