[flang-commits] [flang] [flang][OpenMP] Remove over-broad global scan for declare reduction symbols (PR #200329)

via flang-commits flang-commits at lists.llvm.org
Thu May 28 22:36:16 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Matt (MattPD)

<details>
<summary>Changes</summary>

`CheckSymbolSupportsType` walked all module scopes in the global scope to
find reduction declarations. This incorrectly matched reductions from
modules that were never `USE`'d by the current scope, or reductions that
were excluded via `USE...ONLY`.

Now that #<!-- -->200328 added `GetUltimate()` resolution, `FindSymbol` correctly
resolves USE-associated reductions through their `UseDetails` chains. The
global scan workaround is no longer needed.

Depends on #<!-- -->200328.

Fixes https://github.com/llvm/llvm-project/issues/200300

Assisted-by: Claude Opus 4.6.

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


3 Files Affected:

- (modified) flang/lib/Semantics/check-omp-structure.cpp (+5-22) 
- (added) flang/test/Semantics/OpenMP/declare-reduction-overbroad-lookup.f90 (+32) 
- (added) flang/test/Semantics/OpenMP/declare-reduction-use-assoc-named.f90 (+82) 


``````````diff
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index ff41f49d88b32..96c4e84bd8963 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -3847,7 +3847,7 @@ bool OmpStructureChecker::CheckReductionOperator(
       std::string mangled{MangleDefinedOperator(definedOp->v.symbol->name())};
       const Scope &scope{definedOp->v.symbol->owner()};
       if (const Symbol *symbol{scope.FindSymbol(mangled)}) {
-        if (symbol->detailsIf<UserReductionDetails>()) {
+        if (symbol->GetUltimate().detailsIf<UserReductionDetails>()) {
           return true;
         }
       }
@@ -3865,7 +3865,7 @@ bool OmpStructureChecker::CheckReductionOperator(
       valid =
           llvm::is_contained({"max", "min", "iand", "ior", "ieor"}, realName);
       if (!valid) {
-        valid = name->symbol->detailsIf<UserReductionDetails>();
+        valid = name->symbol->GetUltimate().detailsIf<UserReductionDetails>();
       }
     }
     if (!valid) {
@@ -3948,29 +3948,12 @@ void OmpStructureChecker::CheckReductionObjects(
 static bool CheckSymbolSupportsType(const Scope &scope,
     const parser::CharBlock &name, const DeclTypeSpec &type) {
   if (const auto *symbol{scope.FindSymbol(name)}) {
+    const auto &ultimate{symbol->GetUltimate()};
     if (const auto *reductionDetails{
-            symbol->detailsIf<UserReductionDetails>()}) {
+            ultimate.detailsIf<UserReductionDetails>()}) {
       return reductionDetails->SupportsType(type);
     }
   }
-  // Look through module scopes in the global scope.
-  // This covers reductions declared in a module and used via USE association.
-  const SemanticsContext &semCtx{scope.context()};
-  Scope &global = const_cast<SemanticsContext &>(semCtx).globalScope();
-  for (const Scope &child : global.children()) {
-    if (child.kind() == Scope::Kind::Module) {
-      if (const auto *symbol{child.FindSymbol(name)}) {
-        // Skip PRIVATE reductions that aren't visible in the current scope.
-        if (symbol->attrs().test(Attr::PRIVATE)) {
-          continue;
-        }
-        if (const auto *reductionDetails{
-                symbol->detailsIf<UserReductionDetails>()}) {
-          return reductionDetails->SupportsType(type);
-        }
-      }
-    }
-  }
   return false;
 }
 
@@ -4063,7 +4046,7 @@ static bool IsReductionAllowedForType(
       // if the symbol has UserReductionDetails, and if so, the type is
       // supported.
       if (const auto *reductionDetails{
-              name->symbol->detailsIf<UserReductionDetails>()}) {
+              name->symbol->GetUltimate().detailsIf<UserReductionDetails>()}) {
         return reductionDetails->SupportsType(type);
       }
 
diff --git a/flang/test/Semantics/OpenMP/declare-reduction-overbroad-lookup.f90 b/flang/test/Semantics/OpenMP/declare-reduction-overbroad-lookup.f90
new file mode 100644
index 0000000000000..1db247b4eaff5
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-reduction-overbroad-lookup.f90
@@ -0,0 +1,32 @@
+! RUN: not %flang_fc1 -fopenmp -fopenmp-version=52 %s 2>&1 | FileCheck %s
+
+! Test that a declare reduction from a module that was not USE'd (or only
+! partially USE'd) is not incorrectly found during type checking.
+! Related: https://github.com/llvm/llvm-project/issues/200300
+
+module m_with_reduction
+  type :: t
+    integer :: val = 0
+  end type
+  !$omp declare reduction(+:t:omp_out%val=omp_out%val+omp_in%val) &
+  !$omp   initializer(omp_priv=t(0))
+end module
+
+! proxy re-exports only the type, not the reduction
+module m_proxy
+  use m_with_reduction, only: t
+end module
+
+program test_overbroad_lookup
+  use m_proxy
+  type(t) :: x
+  integer :: i
+  x = t(0)
+  !CHECK: error: The type of 'x' is incompatible with the reduction operator.
+  !$omp parallel do reduction(+:x)
+  do i = 1, 10
+    x%val = x%val + 1
+  end do
+  !$omp end parallel do
+  print *, x%val
+end program
diff --git a/flang/test/Semantics/OpenMP/declare-reduction-use-assoc-named.f90 b/flang/test/Semantics/OpenMP/declare-reduction-use-assoc-named.f90
new file mode 100644
index 0000000000000..2b7b3864bdef2
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-reduction-use-assoc-named.f90
@@ -0,0 +1,82 @@
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -fsyntax-only %s
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -fdebug-dump-symbols %s 2>&1 | FileCheck %s
+
+! Test that USE-associated named reductions and user-defined operator
+! reductions are correctly resolved through UseDetails.
+
+module m_named_reduction
+  type :: t
+    integer :: val = 0
+  end type
+  !$omp declare reduction(myred:t:omp_out%val=omp_out%val+omp_in%val) &
+  !$omp   initializer(omp_priv=t(0))
+end module
+
+module m_defined_op_reduction
+  type :: dt
+    real :: x = 0.0
+  end type
+  interface operator(.combine.)
+    module procedure combine_fn
+  end interface
+  !$omp declare reduction(.combine.:dt:omp_out%x=omp_out%x+omp_in%x) &
+  !$omp   initializer(omp_priv=dt(0.0))
+contains
+  type(dt) function combine_fn(a, b)
+    type(dt), intent(in) :: a, b
+    combine_fn%x = a%x + b%x
+  end function
+end module
+
+program test_use_assoc_reductions
+  use m_named_reduction
+  use m_defined_op_reduction
+  type(t) :: x
+  type(dt) :: y
+  integer :: i
+  x = t(0)
+  y = dt(0.0)
+  ! Both should compile without error: reductions are accessible via USE.
+  !$omp parallel do reduction(myred:x)
+  do i = 1, 10
+    x%val = x%val + 1
+  end do
+  !$omp end parallel do
+  !$omp parallel do reduction(.combine.:y)
+  do i = 1, 10
+    y%x = y%x + 1.0
+  end do
+  !$omp end parallel do
+  print *, x%val, y%x
+end program
+
+! Test defined operator with external interface via USE (issue #184932 pattern).
+! Uses !$omp parallel (not parallel do) to cover that variant.
+module m_external_op
+  type :: ty
+    integer :: ii
+  end type
+  interface operator(.x.)
+    function h(a, b)
+      import :: ty
+      type(ty), intent(in) :: a, b
+    end function
+  end interface
+  !$omp declare reduction(.x.:ty:omp_out=ty(1)) initializer(omp_priv=ty(0))
+end module
+
+subroutine test_external_op_reduction
+  use m_external_op
+  type(ty) :: v
+  v = ty(0)
+  !$omp parallel reduction(.x.:v)
+  v = ty(1)
+  !$omp end parallel
+end subroutine
+
+!CHECK: Module scope: m_named_reduction
+!CHECK: myred, PUBLIC: UserReductionDetails TYPE(t)
+!CHECK: Module scope: m_defined_op_reduction
+!CHECK: op.combine., PUBLIC: UserReductionDetails TYPE(dt)
+!CHECK: Module scope: m_external_op
+!CHECK: op.x., PUBLIC: UserReductionDetails TYPE(ty)

``````````

</details>


https://github.com/llvm/llvm-project/pull/200329


More information about the flang-commits mailing list