Skip to content

default clause replaced by otherwise clause for metadirective in OpenMP 5.2 #128640

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

ravurvi20
Copy link
Contributor

This PR replaces the default clause with the otherwise clause for the metadirective in OpenMP. The otherwise clause serves as a fallback condition when no directive from the when clauses is selected. In the when clause, context selectors define traits evaluated to determine the directive to be applied.
The previous merge was reverted due to a failing test case, which has now been resolved.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openmp OpenMP related changes to Clang labels Feb 25, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 25, 2025

@llvm/pr-subscribers-clang

Author: Urvi Rav (ravurvi20)

Changes

This PR replaces the default clause with the otherwise clause for the metadirective in OpenMP. The otherwise clause serves as a fallback condition when no directive from the when clauses is selected. In the when clause, context selectors define traits evaluated to determine the directive to be applied.
The previous merge was reverted due to a failing test case, which has now been resolved.


Full diff: https://github.com/llvm/llvm-project/pull/128640.diff

3 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+4)
  • (modified) clang/lib/Parse/ParseOpenMP.cpp (+20)
  • (modified) clang/test/OpenMP/metadirective_messages.cpp (+44-17)
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c513dab810d1f..4b8449e9ee9b6 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1657,6 +1657,10 @@ def err_omp_expected_colon : Error<"missing ':' in %0">;
 def err_omp_missing_comma : Error< "missing ',' after %0">;
 def err_omp_expected_context_selector
     : Error<"expected valid context selector in %0">;
+def err_omp_unknown_clause
+    : Error<"unknown clause '%0' in %1">;
+def warn_omp_default_deprecated : Warning<"'default' clause for"
+  " 'metadirective' is deprecated; use 'otherwise' instead">, InGroup<Deprecated>;
 def err_omp_requires_out_inout_depend_type : Error<
   "reserved locator 'omp_all_memory' requires 'out' or 'inout' "
   "dependency types">;
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 42e6aac681c1c..3b86847e937a2 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2759,6 +2759,19 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       OpenMPClauseKind CKind = Tok.isAnnotation()
                                    ? OMPC_unknown
                                    : getOpenMPClauseKind(PP.getSpelling(Tok));
+      // Check if the clause is unrecognized.
+      if (getLangOpts().OpenMP < 52 &&
+          (CKind == OMPC_unknown || CKind == OMPC_otherwise)) {
+        Diag(Tok, diag::err_omp_unknown_clause)
+            << PP.getSpelling(Tok) << "metadirective";
+      }
+      if (getLangOpts().OpenMP >= 52 && CKind == OMPC_unknown) {
+        Diag(Tok, diag::err_omp_unknown_clause)
+            << PP.getSpelling(Tok) << "metadirective";
+      }
+      if (CKind == OMPC_default && getLangOpts().OpenMP >= 52) {
+        Diag(Tok, diag::warn_omp_default_deprecated);
+      }
       SourceLocation Loc = ConsumeToken();
 
       // Parse '('.
@@ -2785,6 +2798,13 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
           return Directive;
         }
       }
+      if (CKind == OMPC_otherwise) {
+        // Check for 'otherwise' keyword.
+        if (Tok.is(tok::identifier) &&
+            Tok.getIdentifierInfo()->getName() == "otherwise") {
+          ConsumeToken(); // Consume 'otherwise'
+        }
+      }
       // Skip Directive for now. We will parse directive in the second iteration
       int paren = 0;
       while (Tok.isNot(tok::r_paren) || paren != 0) {
diff --git a/clang/test/OpenMP/metadirective_messages.cpp b/clang/test/OpenMP/metadirective_messages.cpp
index 7fce9fa446058..40ea37845fdff 100644
--- a/clang/test/OpenMP/metadirective_messages.cpp
+++ b/clang/test/OpenMP/metadirective_messages.cpp
@@ -2,21 +2,48 @@
 
 // RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -verify -fopenmp-simd -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s
 
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -verify=expected,omp52 -fopenmp -fopenmp-version=52 -ferror-limit 100 -o - %s -Wuninitialized
+
 void foo() {
-#pragma omp metadirective // expected-error {{expected expression}}
-  ;
-#pragma omp metadirective when() // expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'target_device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
-  ;
-#pragma omp metadirective when(device{}) // expected-warning {{expected '=' after the context set name "device"; '=' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'kind' 'arch' 'isa'}} expected-note {{the ignored selector spans until here}} expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}}
-  ;
-#pragma omp metadirective when(device{arch(nvptx)}) // expected-error {{missing ':' in when clause}} expected-error {{expected expression}} expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
-  ;
-#pragma omp metadirective when(device{arch(nvptx)}: ) default() // expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
-  ;
-#pragma omp metadirective when(device = {arch(nvptx)} : ) default(xyz) // expected-error {{expected an OpenMP directive}} expected-error {{use of undeclared identifier 'xyz'}}
-  ;
-#pragma omp metadirective when(device = {arch(nvptx)} : parallel default() // expected-error {{expected ',' or ')' in 'when' clause}} expected-error {{expected expression}}
-  ;
-#pragma omp metadirective when(device = {isa("some-unsupported-feature")} : parallel) default(single) // expected-warning {{isa trait 'some-unsupported-feature' is not known to the current target; verify the spelling or consider restricting the context selector with the 'arch' selector further}}
-  ;
-}
+  #if _OPENMP >= 202111
+    #pragma omp metadirective // omp52-error {{expected expression}}
+      ;
+    #pragma omp metadirective when() // omp52-error {{expected valid context selector in when clause}} expected-error {{expected expression}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'target_device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
+      ;
+    #pragma omp metadirective when(device{}) // omp52-warning {{expected '=' after the context set name "device"; '=' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'kind' 'arch' 'isa'}} expected-note {{the ignored selector spans until here}} expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}}
+      ;
+    #pragma omp metadirective when(device{arch(nvptx)}) // omp52-error {{missing ':' in when clause}} expected-error {{expected expression}} expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
+      ;
+    #pragma omp metadirective when(device{arch(nvptx)}: ) otherwise() // omp52-warning {{expected '=' after the context set name "device"; '=' assumed}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : ) otherwise(xyz) // omp52-error {{expected an OpenMP directive}} expected-error {{use of undeclared identifier 'xyz'}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : parallel otherwise() // omp52-error {{expected ',' or ')' in 'when' clause}} expected-error {{expected expression}}
+      ;
+    #pragma omp metadirective when(device = {isa("some-unsupported-feature")} : parallel) otherwise(single) // omp52-warning {{isa trait 'some-unsupported-feature' is not known to the current target; verify the spelling or consider restricting the context selector with the 'arch' selector further}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : parallel) default() // omp52-warning {{'default' clause for 'metadirective' is deprecated; use 'otherwise' instead}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : parallel) xyz() //omp52-error {{unknown clause 'xyz' in metadirective}} 
+      ;
+  #else
+    #pragma omp metadirective // expected-error {{expected expression}}
+      ;
+    #pragma omp metadirective when() // expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'target_device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
+      ;
+    #pragma omp metadirective when(device{}) // expected-warning {{expected '=' after the context set name "device"; '=' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'kind' 'arch' 'isa'}} expected-note {{the ignored selector spans until here}} expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}}
+      ;
+    #pragma omp metadirective when(device{arch(nvptx)}) // expected-error {{missing ':' in when clause}} expected-error {{expected expression}} expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
+      ;
+    #pragma omp metadirective when(device{arch(nvptx)}: ) default() // expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : ) default(xyz) // expected-error {{expected an OpenMP directive}} expected-error {{use of undeclared identifier 'xyz'}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : parallel default() // expected-error {{expected ',' or ')' in 'when' clause}} expected-error {{expected expression}}
+      ;
+    #pragma omp metadirective when(device = {isa("some-unsupported-feature")} : parallel) default(single) // expected-warning {{isa trait 'some-unsupported-feature' is not known to the current target; verify the spelling or consider restricting the context selector with the 'arch' selector further}}
+      ;
+    #pragma omp metadirective when(device = {arch(nvptx)} : parallel) xyz() //expected-error {{unknown clause 'xyz' in metadirective}} 
+      ;
+  #endif
+  }
\ No newline at end of file

@ravurvi20
Copy link
Contributor Author

Previous commit was reverted due to a failing test case, which has been resolved now. Parsing changes have been approved in the previous PR.
125648

@ravurvi20
Copy link
Contributor Author

@mjklemm could you please approve this PR. There was minor change which has been fixed now.

Copy link
Contributor

@mjklemm mjklemm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines 1660 to 1661
def err_omp_unknown_clause
: Error<"unknown clause '%0' in %1">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a message for a wrong clause for a directive: err_omp_unexpected_clause. This does not apply when we have some unknown string where a clause is expected.

Comment on lines 2763 to 2771
if (getLangOpts().OpenMP < 52 &&
(CKind == OMPC_unknown || CKind == OMPC_otherwise)) {
Diag(Tok, diag::err_omp_unknown_clause)
<< PP.getSpelling(Tok) << "metadirective";
}
if (getLangOpts().OpenMP >= 52 && CKind == OMPC_unknown) {
Diag(Tok, diag::err_omp_unknown_clause)
<< PP.getSpelling(Tok) << "metadirective";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please treat OMPC_unknown and OMPC_otherwise separately: in the former case the message should be something like "expected an OpenMP clause" (see err_omp_unknown_directive for reference). The latter case should use err_omp_unexpected_clause.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kparzysz I have made the requested modifications to the code based on your suggestions. Please review it and provide your feedback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @kparzysz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @kparzysz

Copy link

github-actions bot commented Apr 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@ravurvi20
Copy link
Contributor Author

@alexey-bataev I have pushed the requested changes. Could you please approve this PR.

@@ -1660,6 +1660,10 @@ def err_omp_expected_colon : Error<"missing ':' in %0">;
def err_omp_missing_comma : Error< "missing ',' after %0">;
def err_omp_expected_context_selector
: Error<"expected valid context selector in %0">;
def err_omp_unknown_clause
: Error<"expected an OpenMP clause">;
def warn_omp_default_deprecated : Warning<"'default' clause for"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use err_omp_deprecate_old_syntax

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since default is being deprecated not disallowed in metadirective I had put a warning instead on using an error (err_omp_deprecate_old_syntax).

Comment on lines 2771 to 2773
if (CKind == OMPC_default && getLangOpts().OpenMP >= 52) {
Diag(Tok, diag::warn_omp_default_deprecated);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop braces

@@ -1660,6 +1660,10 @@ def err_omp_expected_colon : Error<"missing ':' in %0">;
def err_omp_missing_comma : Error< "missing ',' after %0">;
def err_omp_expected_context_selector
: Error<"expected valid context selector in %0">;
def err_omp_unknown_clause
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use err_omp_expected_clause instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I've already used err_omp_unexpected_clause for the OMPC_otherwise case in OpenMP versions prior to 5.2, as suggested earlier. For OMPC_unknown, I'm using err_omp_unknown_clause, which aligns with the guidance to treat OMPC_unknown and OMPC_otherwise separately.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is wrong. If the wrong clause is used, it should be reported automatically. If none was specified, err_omp_expected_clause should be used

Comment on lines 2803 to 2805
Tok.getIdentifierInfo()->getName() == "otherwise") {
ConsumeToken(); // Consume 'otherwise'
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop braces

Comment on lines 2802 to 2803
if (Tok.is(tok::identifier) &&
Tok.getIdentifierInfo()->getName() == "otherwise") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why need to double check here?

: parallel for) otherwise()
for (int i=0; i<10; i++)
;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why moved the test cases? and why a guard is required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since for versions prior to 5.2 default is valid so moved it in a way that if the version is 5.2 or greater otherwise condition should run else the default condition.

@@ -1660,6 +1660,10 @@ def err_omp_expected_colon : Error<"missing ':' in %0">;
def err_omp_missing_comma : Error< "missing ',' after %0">;
def err_omp_expected_context_selector
: Error<"expected valid context selector in %0">;
def err_omp_unknown_clause
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is wrong. If the wrong clause is used, it should be reported automatically. If none was specified, err_omp_expected_clause should be used

// Check if the clause is unrecognized.
if (CKind == OMPC_unknown) {
Diag(Tok, diag::err_omp_unknown_clause)
<< PP.getSpelling(Tok) << "metadirective";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message does not accept any parameters

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openmp OpenMP related changes to Clang clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants