[flang-commits] [flang] [flang][OpenMP] Fix USE-associated declare reduction symbol resolution (PR #200328)

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


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-openmp

Author: Matt (MattPD)

<details>
<summary>Changes</summary>

When a declare reduction is accessed via USE association, the symbol in
the consuming scope has `UseDetails` rather than `UserReductionDetails`.
Calling `detailsIf<UserReductionDetails>()` directly on such a symbol
returns nullptr. This causes two distinct failure modes:

1. **Operator/identifier validation** (`CheckReductionOperator`): named
   reductions and defined operators are rejected with "Invalid reduction
   identifier" or "Invalid reduction operator".

2. **Type validation** (`CheckSymbolSupportsType`, `IsReductionAllowedForType`):
   the type compatibility check cannot find `UserReductionDetails` for the
   reduction, producing "The type of 'x' is incompatible with the
   reduction operator".

This bug has existed since `UserReductionDetails` was introduced (June
2025). Only intrinsic operator reductions (like `+`) worked via USE,
because they bypass the operator validation check and their type checking
was handled by a global module scan workaround (added Feb 2026).

**Fix:** Add `GetUltimate()` at 4 locations in `check-omp-structure.cpp` to resolve
through `UseDetails` chains before checking for `UserReductionDetails`:
two in `CheckReductionOperator` (validation paths 1 and 2 above), one in
`CheckSymbolSupportsType`, and one in `IsReductionAllowedForType`.

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

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


2 Files Affected:

- (modified) flang/lib/Semantics/check-omp-structure.cpp (+5-4) 
- (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..c450c3fbfeb43 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,8 +3948,9 @@ 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);
     }
   }
@@ -4063,7 +4064,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-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/200328


More information about the flang-commits mailing list