Skip to content

[flang][OpenMP] Properly resolve CRITICAL construct names#205904

Merged
kparzysz merged 6 commits into
mainfrom
users/kparzysz/unresolved-critical
Jun 26, 2026
Merged

[flang][OpenMP] Properly resolve CRITICAL construct names#205904
kparzysz merged 6 commits into
mainfrom
users/kparzysz/unresolved-critical

Conversation

@kparzysz

@kparzysz kparzysz commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Resolve the names of CRITICAL constructs even if they are reserved names.
This also limits locator parsing to known reserved names.

Fixes #205855

Resolve the names of CRITICAL constructs even if they are reserved names.

Fixes #205855
@kparzysz
kparzysz requested review from Saieiei and sscalpone June 25, 2026 20:10
@llvmorg-github-actions llvmorg-github-actions Bot added flang Flang issues not falling into any other category flang:openmp flang:semantics labels Jun 25, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-flang-parser

@llvm/pr-subscribers-flang-semantics

Author: Krzysztof Parzyszek (kparzysz)

Changes

Resolve the names of CRITICAL constructs even if they are reserved names.

Fixes #205855


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

4 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+6-1)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+31-21)
  • (added) flang/test/Semantics/OpenMP/critical-reserved-name.f90 (+8)
  • (modified) flang/test/Semantics/OpenMP/reserved-locator.f90 (+1-1)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 061b2bdf775d0..fcd5e884db18d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -649,7 +649,7 @@ void OmpStructureChecker::Enter(const parser::OmpLocator &x) {
   if (auto *reserved{parser::Unwrap<parser::OmpReservedIdentifier>(x.u)}) {
     std::string name{parser::ToLowerCaseLetters(reserved->v.source.ToString())};
     if (!llvm::is_contained(llvm::omp::getReservedLocatorNames(), name)) {
-      context_.Say(reserved->v.source, "'%s' is not a valid locator"_err_en_US,
+      context_.Say(reserved->v.source, "Invalid use of a reserved name '%s'"_err_en_US,
           parser::ToUpperCaseLetters(name));
     }
   }
@@ -3099,6 +3099,11 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
     if (auto *object{parser::Unwrap<parser::OmpObject>(arg.u)}) {
       if (auto *designator{GetDesignatorFromObj(*object)}) {
         return parser::GetDesignatorNameIfDataRef(*designator);
+      } else if (auto *locator{std::get_if<parser::OmpLocator>(&object->u)}) {
+        if (auto *res{
+                std::get_if<parser::OmpReservedIdentifier>(&locator->u)}) {
+          return &res->v;
+        }
       }
     }
     return static_cast<const parser::Name *>(nullptr);
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 11e24a5e1cccb..8f7d5f0d3f959 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2168,29 +2168,39 @@ void OmpVisitor::ProcessReductionSpecifier(
 }
 
 void OmpVisitor::ResolveCriticalName(const parser::OmpArgument &arg) {
-  auto &globalScope{[&]() -> Scope & {
-    for (Scope *s{&currScope()};; s = &s->parent()) {
-      if (s->IsTopLevel()) {
-        return *s;
-      }
-    }
-    llvm_unreachable("Cannot find global scope");
-  }()};
+  auto *object{parser::Unwrap<parser::OmpObject>(arg.u)};
+  if (!object) {
+    return;
+  }
 
-  if (auto *object{parser::Unwrap<parser::OmpObject>(arg.u)}) {
-    if (auto *desg{parser::omp::GetDesignatorFromObj(*object)}) {
-      if (auto *name{parser::GetDesignatorNameIfDataRef(*desg)}) {
-        if (auto *symbol{FindInScope(globalScope, *name)}) {
-          if (!symbol->test(Symbol::Flag::OmpCriticalLock)) {
-            SayWithDecl(*name, *symbol,
-                "CRITICAL construct name '%s' conflicts with a previous declaration"_warn_en_US,
-                name->ToString());
-          }
-        } else {
-          name->symbol = &MakeSymbol(globalScope, name->source, Attrs{});
-          name->symbol->set(Symbol::Flag::OmpCriticalLock);
-        }
+  const parser::Name *name{common::visit( //
+      common::visitors{//
+          [&](const parser::Designator &x) -> const parser::Name * {
+            return parser::GetDesignatorNameIfDataRef(x);
+          },
+          [&](const parser::OmpLocator &x) -> const parser::Name * {
+            if (auto *res{std::get_if<parser::OmpReservedIdentifier>(&x.u)}) {
+              return &res->v;
+            }
+            return nullptr;
+          },
+          [&](const parser::Name &) -> const parser::Name * { return nullptr; },
+          [&](const parser::OmpObject::Invalid &) -> const parser::Name * {
+            return nullptr;
+          }},
+      object->u)};
+
+  if (name) {
+    if (auto *symbol{FindInScope(context().globalScope(), *name)}) {
+      if (!symbol->test(Symbol::Flag::OmpCriticalLock)) {
+        SayWithDecl(*name, *symbol,
+            "CRITICAL construct name '%s' conflicts with a previous declaration"_warn_en_US,
+            name->ToString());
       }
+    } else {
+      name->symbol =
+          &MakeSymbol(context().globalScope(), name->source, Attrs{});
+      name->symbol->set(Symbol::Flag::OmpCriticalLock);
     }
   }
 }
diff --git a/flang/test/Semantics/OpenMP/critical-reserved-name.f90 b/flang/test/Semantics/OpenMP/critical-reserved-name.f90
new file mode 100644
index 0000000000000..9516f0c07d7b7
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/critical-reserved-name.f90
@@ -0,0 +1,8 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine f
+  !ERROR: Invalid use of a reserved name 'OMP_C'
+  !$omp critical(omp_c)
+  !ERROR: Invalid use of a reserved name 'OMP_C'
+  !$omp end critical(omp_c)
+end
diff --git a/flang/test/Semantics/OpenMP/reserved-locator.f90 b/flang/test/Semantics/OpenMP/reserved-locator.f90
index 3fc45ffa0f54c..ae2a6d59f4c74 100644
--- a/flang/test/Semantics/OpenMP/reserved-locator.f90
+++ b/flang/test/Semantics/OpenMP/reserved-locator.f90
@@ -1,6 +1,6 @@
 !RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=60
 
 subroutine f
-!ERROR: 'OMP_SOME_MEMORY' is not a valid locator
+!ERROR: Invalid use of a reserved name 'OMP_SOME_MEMORY'
   !$omp target update from(omp_some_memory)
 end

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-flang-openmp

Author: Krzysztof Parzyszek (kparzysz)

Changes

Resolve the names of CRITICAL constructs even if they are reserved names.

Fixes #205855


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

4 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+6-1)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+31-21)
  • (added) flang/test/Semantics/OpenMP/critical-reserved-name.f90 (+8)
  • (modified) flang/test/Semantics/OpenMP/reserved-locator.f90 (+1-1)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 061b2bdf775d0..fcd5e884db18d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -649,7 +649,7 @@ void OmpStructureChecker::Enter(const parser::OmpLocator &x) {
   if (auto *reserved{parser::Unwrap<parser::OmpReservedIdentifier>(x.u)}) {
     std::string name{parser::ToLowerCaseLetters(reserved->v.source.ToString())};
     if (!llvm::is_contained(llvm::omp::getReservedLocatorNames(), name)) {
-      context_.Say(reserved->v.source, "'%s' is not a valid locator"_err_en_US,
+      context_.Say(reserved->v.source, "Invalid use of a reserved name '%s'"_err_en_US,
           parser::ToUpperCaseLetters(name));
     }
   }
@@ -3099,6 +3099,11 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
     if (auto *object{parser::Unwrap<parser::OmpObject>(arg.u)}) {
       if (auto *designator{GetDesignatorFromObj(*object)}) {
         return parser::GetDesignatorNameIfDataRef(*designator);
+      } else if (auto *locator{std::get_if<parser::OmpLocator>(&object->u)}) {
+        if (auto *res{
+                std::get_if<parser::OmpReservedIdentifier>(&locator->u)}) {
+          return &res->v;
+        }
       }
     }
     return static_cast<const parser::Name *>(nullptr);
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 11e24a5e1cccb..8f7d5f0d3f959 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2168,29 +2168,39 @@ void OmpVisitor::ProcessReductionSpecifier(
 }
 
 void OmpVisitor::ResolveCriticalName(const parser::OmpArgument &arg) {
-  auto &globalScope{[&]() -> Scope & {
-    for (Scope *s{&currScope()};; s = &s->parent()) {
-      if (s->IsTopLevel()) {
-        return *s;
-      }
-    }
-    llvm_unreachable("Cannot find global scope");
-  }()};
+  auto *object{parser::Unwrap<parser::OmpObject>(arg.u)};
+  if (!object) {
+    return;
+  }
 
-  if (auto *object{parser::Unwrap<parser::OmpObject>(arg.u)}) {
-    if (auto *desg{parser::omp::GetDesignatorFromObj(*object)}) {
-      if (auto *name{parser::GetDesignatorNameIfDataRef(*desg)}) {
-        if (auto *symbol{FindInScope(globalScope, *name)}) {
-          if (!symbol->test(Symbol::Flag::OmpCriticalLock)) {
-            SayWithDecl(*name, *symbol,
-                "CRITICAL construct name '%s' conflicts with a previous declaration"_warn_en_US,
-                name->ToString());
-          }
-        } else {
-          name->symbol = &MakeSymbol(globalScope, name->source, Attrs{});
-          name->symbol->set(Symbol::Flag::OmpCriticalLock);
-        }
+  const parser::Name *name{common::visit( //
+      common::visitors{//
+          [&](const parser::Designator &x) -> const parser::Name * {
+            return parser::GetDesignatorNameIfDataRef(x);
+          },
+          [&](const parser::OmpLocator &x) -> const parser::Name * {
+            if (auto *res{std::get_if<parser::OmpReservedIdentifier>(&x.u)}) {
+              return &res->v;
+            }
+            return nullptr;
+          },
+          [&](const parser::Name &) -> const parser::Name * { return nullptr; },
+          [&](const parser::OmpObject::Invalid &) -> const parser::Name * {
+            return nullptr;
+          }},
+      object->u)};
+
+  if (name) {
+    if (auto *symbol{FindInScope(context().globalScope(), *name)}) {
+      if (!symbol->test(Symbol::Flag::OmpCriticalLock)) {
+        SayWithDecl(*name, *symbol,
+            "CRITICAL construct name '%s' conflicts with a previous declaration"_warn_en_US,
+            name->ToString());
       }
+    } else {
+      name->symbol =
+          &MakeSymbol(context().globalScope(), name->source, Attrs{});
+      name->symbol->set(Symbol::Flag::OmpCriticalLock);
     }
   }
 }
diff --git a/flang/test/Semantics/OpenMP/critical-reserved-name.f90 b/flang/test/Semantics/OpenMP/critical-reserved-name.f90
new file mode 100644
index 0000000000000..9516f0c07d7b7
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/critical-reserved-name.f90
@@ -0,0 +1,8 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine f
+  !ERROR: Invalid use of a reserved name 'OMP_C'
+  !$omp critical(omp_c)
+  !ERROR: Invalid use of a reserved name 'OMP_C'
+  !$omp end critical(omp_c)
+end
diff --git a/flang/test/Semantics/OpenMP/reserved-locator.f90 b/flang/test/Semantics/OpenMP/reserved-locator.f90
index 3fc45ffa0f54c..ae2a6d59f4c74 100644
--- a/flang/test/Semantics/OpenMP/reserved-locator.f90
+++ b/flang/test/Semantics/OpenMP/reserved-locator.f90
@@ -1,6 +1,6 @@
 !RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=60
 
 subroutine f
-!ERROR: 'OMP_SOME_MEMORY' is not a valid locator
+!ERROR: Invalid use of a reserved name 'OMP_SOME_MEMORY'
   !$omp target update from(omp_some_memory)
 end

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 4762 tests passed
  • 206 tests skipped

✅ The build succeeded and all tests passed.

@Saieiei

Saieiei commented Jun 26, 2026

Copy link
Copy Markdown
Member

This looks correct to me, and the cleanup is a real improvement. Replacing the previous Internal: no symbol found / CRITICAL argument should be a name / is not a valid locator cascade with a single diagnostic, and resolving the lock symbol in ResolveCriticalName, both look right.

One optional consistency/severity question, not a blocker: OpenMP 5.2 §4 does reserve names beginning with omp_ / ompx_, so the diagnostic is spec-backed. But under the same rule, ordinary declarations like integer :: omp_c / logical :: omp_available would also be non-conforming, and Flang appears to accept those today. So this currently enforces the prefix rule for critical names but not for ordinary declarations.

Given that, and given the compatibility concern in #205855, do we intentionally want this as a hard error here, or would a warning/portability diagnostic be a better fit until reserved-name checking is applied more uniformly? The existing CRITICAL construct name ... conflicts with a previous declaration case is also a warning, so I wanted to ask before approving the severity choice.

@eugeneepshteyn

Copy link
Copy Markdown
Contributor

I strongly recommend that these kinds of errors should be a warning, so that the user could promote them to errors or turn them off, depending on their needs. This behavior could be documented as OpenMP extension.

@kparzysz

Copy link
Copy Markdown
Contributor Author

I strongly recommend that these kinds of errors should be a warning, so that the user could promote them to errors or turn them off, depending on their needs. This behavior could be documented as OpenMP extension.

The original fix actually did that, but since I had to make changes to lowering to handle reserved identifiers where only a designator was expected before, I was worried that allowing this could open some unforeseen can of worms.

I can come up with a solution that improves how we deal with reserved names (and emits a warning instead) if you're willing to wait until next week.

@kparzysz

Copy link
Copy Markdown
Contributor Author

This is a quick fix that ignores reserved names except for predefined locator names. It won't emit any diagnostics for the testcase in the issue, but a future PR will add those as warnings.

@kparzysz
kparzysz requested a review from eugeneepshteyn June 26, 2026 14:01
@Saieiei

Saieiei commented Jun 26, 2026

Copy link
Copy Markdown
Member

Thanks for reworking this. The new direction looks good to me.

One small request before I approve: since the previous reserved-name tests were removed when the behavior changed, could we keep/add a direct regression test showing that critical(omp_c) / end critical(omp_c) is accepted now? That would lock in the actual fix for #205855.

@sscalpone

Copy link
Copy Markdown
Contributor

Thanks for the quick action! We are seeing similar errors pop up in a few more contexts in real applications and in lots of test cases. @scamp-nvidia will file a few more issues to track in case you'd like to expand this PR. We're committed to informing our upstream users and modifying our tests to comply with the OpenMP standard but the quick relief proposed in this PR is very welcome!

@kparzysz

Copy link
Copy Markdown
Contributor Author

One small request before I approve: since the previous reserved-name tests were removed when the behavior changed, could we keep/add a direct regression test showing that critical(omp_c) / end critical(omp_c) is accepted now? That would lock in the actual fix for #205855.

I'd rather not add a test that checks for behavior that's strictly speaking incorrect. I'll add checks for diagnostics in the PR that shows them.

@kparzysz

Copy link
Copy Markdown
Contributor Author

I'm going to merge this, since it fixes the biggest problem.

@kparzysz
kparzysz merged commit 5113f6d into main Jun 26, 2026
11 checks passed
@kparzysz
kparzysz deleted the users/kparzysz/unresolved-critical branch June 26, 2026 16:45
LouisLu060211 pushed a commit to LouisLu060211/llvm-project that referenced this pull request Jun 30, 2026
Resolve the names of CRITICAL constructs even if they are reserved
names.
This also limits locator parsing to known reserved names.

Fixes llvm#205855
maarcosrmz pushed a commit to maarcosrmz/llvm-project that referenced this pull request Jul 1, 2026
Resolve the names of CRITICAL constructs even if they are reserved
names.
This also limits locator parsing to known reserved names.

Fixes llvm#205855
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:openmp flang:parser flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Flang][OpenMP] critical region with "omp_" leading name regression.

4 participants