[llvm-branch-commits] [flang] [flang][OpenMP] Improve diagnosing invalid operators in DECLARE_REDUCTION (PR #232353)

Krzysztof Parzyszek via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Oct 22 05:50:52 PDT 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/232353

>From a9150019c6614205856b47b946222df095c4c686 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 15 Oct 2026 08:14:08 -0500
Subject: [PATCH 1/5] [flang][OpenMP] Improve diagnosing invalid operators in
 DECLARE_REDUCTION

Move the check out of the common MakeNameFromOperator function and
into OmpStructureChecker. Remove the no longer needed SemanticsContext
parameter in MakeNameFromOperator.

This will allow reusing at least some parts of the the name-mangling
code in DECLARE_INDUCTION.
---
 flang/include/flang/Semantics/tools.h         |  3 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  3 +-
 .../lib/Lower/Support/ReductionProcessor.cpp  |  2 +-
 flang/lib/Semantics/check-omp-structure.cpp   | 70 ++++++++++++++-----
 flang/lib/Semantics/check-omp-structure.h     |  2 +
 flang/lib/Semantics/resolve-names.cpp         |  3 +-
 flang/lib/Semantics/tools.cpp                 |  8 +--
 .../OpenMP/declare-reduction-bad-operator.f90 |  4 +-
 flang/test/Semantics/OpenMP/in-reduction.f90  |  2 +-
 .../Semantics/OpenMP/reduction-subtract.f90   |  5 +-
 flang/test/Semantics/OpenMP/reduction01.f90   |  2 +-
 flang/test/Semantics/OpenMP/reduction14.f90   |  3 +-
 .../test/Semantics/OpenMP/task-reduction.f90  |  2 +-
 13 files changed, 70 insertions(+), 39 deletions(-)

diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index bd2cb0780de9bd..eb8bc762aa1a06 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -791,8 +791,7 @@ bool HadUseError(SemanticsContext &, SourceName at, const Symbol *);
 bool AreSameModuleSymbol(const Symbol &, const Symbol &);
 
 parser::CharBlock MakeNameFromOperator(
-    const parser::DefinedOperator::IntrinsicOperator &op,
-    SemanticsContext &context);
+    const parser::DefinedOperator::IntrinsicOperator &op);
 parser::CharBlock MangleSpecialFunctions(parser::CharBlock name);
 std::string MangleDefinedOperator(parser::CharBlock name);
 
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 7aa11e3bc776ad..4769b098a064da 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -6678,8 +6678,7 @@ static void genOpenMPDeclareReductionImpl(
                           parser::CharBlock mangledOpName =
                               semantics::MakeNameFromOperator(
                                   ReductionProcessor::toParserIntrinsicOperator(
-                                      intrOp),
-                                  semaCtx);
+                                      intrOp));
                           redSymPtr = semantics::omp::FindUserReductionSymbol(
                               converter.getCurrentScope(), mangledOpName);
                         }
diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp
index 25f62cd8e0f0bf..f318b2d3c4f1b4 100644
--- a/flang/lib/Lower/Support/ReductionProcessor.cpp
+++ b/flang/lib/Lower/Support/ReductionProcessor.cpp
@@ -1207,7 +1207,7 @@ bool ReductionProcessor::processReductionArguments(
           const semantics::DeclTypeSpec *opVarType =
               reductionSymbols[idx]->GetUltimate().GetType();
           parser::CharBlock mangledOpName = semantics::MakeNameFromOperator(
-              toParserIntrinsicOperator(intrinsicOp), *semaCtx);
+              toParserIntrinsicOperator(intrinsicOp));
           if (const semantics::Symbol *userSym =
                   semantics::omp::FindUserReductionSymbol(
                       converter.getCurrentScope(), mangledOpName, opVarType)) {
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 7376a05d5c2ae9..010fcaa0820412 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2756,17 +2756,32 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareMapperDirective &x) {
 }
 
 void OmpStructureChecker::Enter(const parser::OmpDeclareReductionDirective &x) {
+  llvm::omp::Version version{context_.langOptions().getOpenMPVersion()};
+  std::string dirName{
+      GetUpperName(llvm::omp::Directive::OMPD_declare_reduction, version)};
+
   const parser::OmpArgumentList &args{x.v.Arguments()};
   if (args.v.size() != 1) {
     context_.Say(args.source,
-        "DECLARE_REDUCTION directive should have a single argument"_err_en_US);
+        "%s directive should have a single argument"_err_en_US, dirName);
     return;
   }
 
   const parser::OmpArgument &arg{args.v.front()};
-  if (!std::holds_alternative<parser::OmpReductionSpecifier>(arg.u)) {
+  if (auto *spec{std::get_if<parser::OmpReductionSpecifier>(&arg.u)}) {
+    auto &ident{std::get<parser::OmpReductionIdentifier>(spec->t)};
+    using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
+    if (auto *intOp{parser::Unwrap<IntrinsicOperator>(ident)}) {
+      if (!CheckReductionIntrinsicOperator(*intOp, arg.source)) {
+        context_.Say(arg.source,
+            "Invalid reduction intrinsic operator in %s directive"_err_en_US,
+            dirName);
+      }
+    }
+  } else {
     context_.Say(arg.source,
-        "The argument to the DECLARE_REDUCTION directive should be a reduction-specifier"_err_en_US);
+        "The argument to the %s directive should be a reduction-specifier"_err_en_US,
+        dirName);
   }
 }
 
@@ -4161,6 +4176,32 @@ void OmpStructureChecker::Enter(const parser::OmpClause::TaskReduction &x) {
   CheckReductionObjects(objects, llvm::omp::Clause::OMPC_task_reduction);
 }
 
+bool OmpStructureChecker::CheckReductionIntrinsicOperator(
+    parser::DefinedOperator::IntrinsicOperator op, parser::CharBlock source) {
+  llvm::omp::Version version{context_.langOptions().getOpenMPVersion()};
+  switch (op) {
+  case parser::DefinedOperator::IntrinsicOperator::Add:
+  case parser::DefinedOperator::IntrinsicOperator::Multiply:
+  case parser::DefinedOperator::IntrinsicOperator::AND:
+  case parser::DefinedOperator::IntrinsicOperator::OR:
+  case parser::DefinedOperator::IntrinsicOperator::EQV:
+  case parser::DefinedOperator::IntrinsicOperator::NEQV:
+    return true;
+  case parser::DefinedOperator::IntrinsicOperator::Subtract:
+    if (llvm::omp::Version v52(52); version >= v52) {
+      context_.Say(source,
+          "The minus reduction operator is deprecated since %s"_err_en_US,
+          ThisVersion(v52));
+    } else {
+      context_.Say(source,
+          "The minus operator is not supported as a reduction operator"_err_en_US);
+    }
+    return false;
+  default:
+    return false;
+  }
+}
+
 bool OmpStructureChecker::CheckReductionOperator(
     const parser::OmpReductionIdentifier &ident, parser::CharBlock source,
     llvm::omp::Clause clauseId) {
@@ -4169,22 +4210,13 @@ bool OmpStructureChecker::CheckReductionOperator(
   auto visitOperator{[&](const parser::DefinedOperator &dOpr) {
     if (const auto *intrinsicOp{
             std::get_if<parser::DefinedOperator::IntrinsicOperator>(&dOpr.u)}) {
-      switch (*intrinsicOp) {
-      case parser::DefinedOperator::IntrinsicOperator::Add:
-      case parser::DefinedOperator::IntrinsicOperator::Multiply:
-      case parser::DefinedOperator::IntrinsicOperator::AND:
-      case parser::DefinedOperator::IntrinsicOperator::OR:
-      case parser::DefinedOperator::IntrinsicOperator::EQV:
-      case parser::DefinedOperator::IntrinsicOperator::NEQV:
-        return true;
-      case parser::DefinedOperator::IntrinsicOperator::Subtract:
-        context_.Say(GetContext().clauseSource,
-            "The minus reduction operator is deprecated since OpenMP 5.2 and is not supported in the REDUCTION clause."_err_en_US,
-            ContextDirectiveAsFortran());
+      if (!CheckReductionIntrinsicOperator(*intrinsicOp, source)) {
+        context_.Say(source,
+            "Invalid reduction operator in %s clause"_err_en_US,
+            GetUpperName(clauseId, version));
         return false;
-      default:
-        break;
       }
+      return true;
     }
     // User-defined operators are OK if there has been a declared reduction
     // for that. We mangle those names to store the user details.
@@ -4304,7 +4336,7 @@ static std::optional<parser::CharBlock> MangledReductionIdentifier(
             if (const auto *intrinsicOp{
                     std::get_if<parser::DefinedOperator::IntrinsicOperator>(
                         &dOpr.u)}) {
-              return MakeNameFromOperator(*intrinsicOp, context);
+              return MakeNameFromOperator(*intrinsicOp);
             }
             if (const auto *definedOp{
                     std::get_if<parser::DefinedOpName>(&dOpr.u)};
@@ -4389,7 +4421,7 @@ static bool IsReductionAllowedForType(
         DIE("This should have been caught in CheckIntrinsicOperator");
         return false;
       }
-      parser::CharBlock name{MakeNameFromOperator(*intrinsicOp, context)};
+      parser::CharBlock name{MakeNameFromOperator(*intrinsicOp)};
       return CheckSymbolSupportsType(scope, name, type);
     } else if (const auto *definedOp{
                    std::get_if<parser::DefinedOpName>(&dOpr.u)}) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 530ad90abcefc6..39652012714191 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -487,6 +487,8 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
       const parser::CharBlock &source, llvm::omp::Directive type);
   void CheckReductionObjects(
       const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
+  bool CheckReductionIntrinsicOperator(
+      parser::DefinedOperator::IntrinsicOperator op, parser::CharBlock source);
   bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
       parser::CharBlock source, llvm::omp::Clause clauseId);
   void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index f67f567578e906..562d290240b77f 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2181,8 +2181,7 @@ void OmpVisitor::ProcessReductionSpecifier(
       mangledName = context().SaveTempName(MangleDefinedOperator(name->source));
     } else {
       mangledName = MakeNameFromOperator(
-          std::get<parser::DefinedOperator::IntrinsicOperator>(defOp.u),
-          context());
+          std::get<parser::DefinedOperator::IntrinsicOperator>(defOp.u));
     }
   }
 
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index ce5c72a481c78b..32aa55c5bd73ab 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -1995,8 +1995,7 @@ bool AreSameModuleSymbol(const Symbol &symbol, const Symbol &other) {
 }
 
 parser::CharBlock MakeNameFromOperator(
-    const parser::DefinedOperator::IntrinsicOperator &op,
-    SemanticsContext &context) {
+    const parser::DefinedOperator::IntrinsicOperator &op) {
   switch (op) {
   case parser::DefinedOperator::IntrinsicOperator::Multiply:
     return parser::CharBlock{"op.*", 4};
@@ -2015,7 +2014,6 @@ parser::CharBlock MakeNameFromOperator(
     return parser::CharBlock{"op.NEQV", 7};
 
   default:
-    context.Say("Unsupported operator in DECLARE REDUCTION"_err_en_US);
     return parser::CharBlock{"op.?", 4};
   }
 }
@@ -2031,8 +2029,8 @@ parser::CharBlock MangleSpecialFunctions(parser::CharBlock name) {
 }
 
 std::string MangleDefinedOperator(parser::CharBlock name) {
-  CHECK(name[0] == '.' && name[name.size() - 1] == '.');
-  return "op" + name.ToString();
+  CHECK(name.starts_with('.') && name.ends_with('.'));
+  return "op" + name.str();
 }
 
 std::string GetReductionFortranId(parser::CharBlock mangledName) {
diff --git a/flang/test/Semantics/OpenMP/declare-reduction-bad-operator.f90 b/flang/test/Semantics/OpenMP/declare-reduction-bad-operator.f90
index 1d1d2903a2780c..ce93b640f237bf 100644
--- a/flang/test/Semantics/OpenMP/declare-reduction-bad-operator.f90
+++ b/flang/test/Semantics/OpenMP/declare-reduction-bad-operator.f90
@@ -1,6 +1,6 @@
-! RUN: not %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s
+!RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
 
 function func(n)
+!ERROR: Invalid reduction intrinsic operator in DECLARE REDUCTION directive
     !$omp declare reduction(/:integer:omp_out=omp_out+omp_in)
-!CHECK: error: Unsupported operator in DECLARE REDUCTION
 end function func
diff --git a/flang/test/Semantics/OpenMP/in-reduction.f90 b/flang/test/Semantics/OpenMP/in-reduction.f90
index 0472774704334c..54d11028f8e45e 100644
--- a/flang/test/Semantics/OpenMP/in-reduction.f90
+++ b/flang/test/Semantics/OpenMP/in-reduction.f90
@@ -9,7 +9,7 @@ subroutine f00
 
 subroutine f01
   real :: x
-!ERROR: Invalid reduction operator in IN_REDUCTION clause.
+!ERROR: Invalid reduction operator in IN_REDUCTION clause
 !$omp target in_reduction(.not.: x)
 !$omp end target
 end
diff --git a/flang/test/Semantics/OpenMP/reduction-subtract.f90 b/flang/test/Semantics/OpenMP/reduction-subtract.f90
index d4034743a14dc7..129a5c6f076948 100644
--- a/flang/test/Semantics/OpenMP/reduction-subtract.f90
+++ b/flang/test/Semantics/OpenMP/reduction-subtract.f90
@@ -1,10 +1,11 @@
-! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=52
 ! OpenMP Version 5.2
 ! Minus operation is deprecated in reduction
 
 subroutine reduction_subtract
   integer :: x
-  !ERROR: The minus reduction operator is deprecated since OpenMP 5.2 and is not supported in the REDUCTION clause.
+  !ERROR: The minus reduction operator is deprecated since OpenMP v5.2
+  !ERROR: Invalid reduction operator in REDUCTION clause
   !$omp do reduction(-:x)
   do i=1, 100
     x = x - i
diff --git a/flang/test/Semantics/OpenMP/reduction01.f90 b/flang/test/Semantics/OpenMP/reduction01.f90
index 0e1a8a571c5847..d08b55c4b92141 100644
--- a/flang/test/Semantics/OpenMP/reduction01.f90
+++ b/flang/test/Semantics/OpenMP/reduction01.f90
@@ -5,7 +5,7 @@ program omp_reduction
   integer :: i
   integer :: k = 10
 
-  !ERROR: Invalid reduction operator in REDUCTION clause.
+  !ERROR: Invalid reduction operator in REDUCTION clause
   !$omp parallel do reduction(**:k)
   do i = 1, 10
     k = k ** 1
diff --git a/flang/test/Semantics/OpenMP/reduction14.f90 b/flang/test/Semantics/OpenMP/reduction14.f90
index 7d3f8d468f7652..f0b6ff283f2b06 100644
--- a/flang/test/Semantics/OpenMP/reduction14.f90
+++ b/flang/test/Semantics/OpenMP/reduction14.f90
@@ -23,7 +23,8 @@ program omp_reduction
   !$omp end parallel
 
   ! - is deprecated for all types
-  ! ERROR: The minus reduction operator is deprecated since OpenMP 5.2 and is not supported in the REDUCTION clause.
+  ! ERROR: The minus operator is not supported as a reduction operator
+  ! ERROR: Invalid reduction operator in REDUCTION clause
   !$omp parallel reduction(-:i,r,c,z,l)
   !$omp end parallel
 
diff --git a/flang/test/Semantics/OpenMP/task-reduction.f90 b/flang/test/Semantics/OpenMP/task-reduction.f90
index 7e43332d53fe1e..efbfa6ba199f5f 100644
--- a/flang/test/Semantics/OpenMP/task-reduction.f90
+++ b/flang/test/Semantics/OpenMP/task-reduction.f90
@@ -9,7 +9,7 @@ subroutine f00
 
 subroutine f01
   real :: x
-!ERROR: Invalid reduction operator in TASK_REDUCTION clause.
+!ERROR: Invalid reduction operator in TASK_REDUCTION clause
 !$omp taskgroup task_reduction(.not.: x)
 !$omp end taskgroup
 end

>From c0150301cf2a37413d78b3cb6ace53bb49e38f57 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 16 Oct 2026 09:58:27 -0500
Subject: [PATCH 2/5] Verify DECLARE_REDUCTION in METADIRECTIVE

---
 flang/lib/Semantics/check-omp-structure.cpp         |  9 +++++++--
 flang/lib/Semantics/check-omp-structure.h           |  1 +
 flang/lib/Semantics/check-omp-variant.cpp           | 13 +++++++++++++
 .../OpenMP/metadirective-declare-reduction.f90      |  9 +++++++++
 4 files changed, 30 insertions(+), 2 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 010fcaa0820412..35cbb4e6081fb2 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2755,12 +2755,13 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareMapperDirective &x) {
   }
 }
 
-void OmpStructureChecker::Enter(const parser::OmpDeclareReductionDirective &x) {
+void OmpStructureChecker::CheckDeclareReduction(
+    const parser::OmpDirectiveSpecification &x) {
   llvm::omp::Version version{context_.langOptions().getOpenMPVersion()};
   std::string dirName{
       GetUpperName(llvm::omp::Directive::OMPD_declare_reduction, version)};
 
-  const parser::OmpArgumentList &args{x.v.Arguments()};
+  const parser::OmpArgumentList &args{x.Arguments()};
   if (args.v.size() != 1) {
     context_.Say(args.source,
         "%s directive should have a single argument"_err_en_US, dirName);
@@ -2785,6 +2786,10 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareReductionDirective &x) {
   }
 }
 
+void OmpStructureChecker::Enter(const parser::OmpDeclareReductionDirective &x) {
+  CheckDeclareReduction(x.v);
+}
+
 void OmpStructureChecker::Enter(const parser::OmpDeclareTargetDirective &x) {
   const parser::OmpDirectiveName &dirName{x.v.DirName()};
 
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 39652012714191..a32f917a033fe7 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -467,6 +467,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   void CheckIndividualAllocateDirective(
       const parser::OmpAllocateDirective &x, bool isExecutable);
   void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
+  void CheckDeclareReduction(const parser::OmpDirectiveSpecification &x);
 
   void CheckUsesAllocatorsSpec(
       const parser::OmpUsesAllocatorsClause::AllocatorSpec &spec);
diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp
index 7add875c96d883..127a912a10485a 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -772,6 +772,19 @@ void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
 }
 
 void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &) {
+  // Perform semantic checks on declarative variants.
+  if (!partStack_.empty() && partStack_.back() == PartKind::SpecificationPart) {
+    OmpVariantMatchContext matchContext{context_};
+    for (const MetadirectiveLoopVariant &variant : metadirectiveLoopVariants_) {
+      if (!MayVariantBeSelected(variant.selector, context_, matchContext)) {
+        continue;
+      }
+      llvm::omp::Directive dirId{variant.spec->DirId()};
+      if (dirId == llvm::omp::Directive::OMPD_declare_reduction) {
+        CheckDeclareReduction(*variant.spec);
+      }
+    }
+  }
   ExitDirectiveNest(MetadirectiveNest);
 }
 
diff --git a/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90 b/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90
new file mode 100644
index 00000000000000..24aa50b0b45cb0
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90
@@ -0,0 +1,9 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine s
+  !$omp metadirective &
+  !$omp& when(implementation={vendor(llvm)}: &
+!ERROR: Invalid reduction intrinsic operator in DECLARE REDUCTION directive
+  !$omp& declare reduction(/ : integer : omp_out = omp_out + omp_in))
+end subroutine
+

>From 8241fa0b96113ff69d341b86554e7afdaa9cf855 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 21 Oct 2026 08:58:19 -0500
Subject: [PATCH 3/5] Limit checks to current METADIRECTIVE

---
 flang/lib/Semantics/check-omp-variant.cpp | 24 ++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp
index 127a912a10485a..e90a81e0653ff2 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -771,17 +771,27 @@ void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
   EnterDirectiveNest(MetadirectiveNest);
 }
 
-void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &) {
-  // Perform semantic checks on declarative variants.
+void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &x) {
+  // Perform semantic checks on declarative variants on this METADIRECTIVE.
   if (!partStack_.empty() && partStack_.back() == PartKind::SpecificationPart) {
     OmpVariantMatchContext matchContext{context_};
-    for (const MetadirectiveLoopVariant &variant : metadirectiveLoopVariants_) {
-      if (!MayVariantBeSelected(variant.selector, context_, matchContext)) {
+    for (const parser::OmpClause &clause : x.v.Clauses().v) {
+      auto *when{parser::Unwrap<parser::OmpWhenClause>(clause)};
+      if (!when) {
         continue;
       }
-      llvm::omp::Directive dirId{variant.spec->DirId()};
-      if (dirId == llvm::omp::Directive::OMPD_declare_reduction) {
-        CheckDeclareReduction(*variant.spec);
+      const auto &modifiers{OmpGetModifiers(*when)};
+      auto *selector{OmpGetUniqueModifier<parser::OmpContextSelector>(modifiers)};
+      if (!MayVariantBeSelected(selector, context_, matchContext)) {
+        continue;
+      }
+      using DirSpecType = common::Indirection<parser::OmpDirectiveSpecification>;
+      if (auto &maybeSpec{std::get<std::optional<DirSpecType>>(when->t)}) {
+        const parser::OmpDirectiveSpecification &spec{maybeSpec->value()};
+        llvm::omp::Directive dirId{spec.DirId()};
+        if (dirId == llvm::omp::Directive::OMPD_declare_reduction) {
+          CheckDeclareReduction(spec);
+        }
       }
     }
   }

>From 199dac7f34d5358c16a5403062e4fa60ea3fbafd Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 21 Oct 2026 09:38:19 -0500
Subject: [PATCH 4/5] format

---
 flang/lib/Semantics/check-omp-variant.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp
index e90a81e0653ff2..ddc2f8ea061c7d 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -781,11 +781,13 @@ void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &x) {
         continue;
       }
       const auto &modifiers{OmpGetModifiers(*when)};
-      auto *selector{OmpGetUniqueModifier<parser::OmpContextSelector>(modifiers)};
+      auto *selector{
+          OmpGetUniqueModifier<parser::OmpContextSelector>(modifiers)};
       if (!MayVariantBeSelected(selector, context_, matchContext)) {
         continue;
       }
-      using DirSpecType = common::Indirection<parser::OmpDirectiveSpecification>;
+      using DirSpecType =
+          common::Indirection<parser::OmpDirectiveSpecification>;
       if (auto &maybeSpec{std::get<std::optional<DirSpecType>>(when->t)}) {
         const parser::OmpDirectiveSpecification &spec{maybeSpec->value()};
         llvm::omp::Directive dirId{spec.DirId()};

>From fef929af4106161fc6099adc59de08b152081c67 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 22 Oct 2026 07:41:27 -0500
Subject: [PATCH 5/5] Verify selectorless clauses as well

---
 flang/include/flang/Semantics/openmp-utils.h  |  5 ++
 flang/lib/Semantics/check-omp-variant.cpp     | 24 +++-----
 flang/lib/Semantics/openmp-utils.cpp          | 55 ++++++++++++-------
 .../metadirective-declare-reduction.f90       | 10 +++-
 4 files changed, 58 insertions(+), 36 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index f5708b9a76600e..fcea723ca78a19 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -276,6 +276,11 @@ struct MetadirectiveCandidateSet {
   const parser::OmpDirectiveSpecification *fallback{nullptr};
 };
 
+const parser::OmpContextSelector *GetContextSelector(
+    const parser::OmpClause &clause);
+const parser::OmpDirectiveSpecification *GetDirectiveVariant(
+    const parser::OmpClause &clause);
+
 /// Build the statically applicable candidates for a METADIRECTIVE.
 ///
 /// Returns std::nullopt when a selector is malformed or uses a feature that
diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp
index ddc2f8ea061c7d..ae6a609fbdae6e 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -771,33 +771,27 @@ void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
   EnterDirectiveNest(MetadirectiveNest);
 }
 
+
 void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &x) {
   // Perform semantic checks on declarative variants on this METADIRECTIVE.
   if (!partStack_.empty() && partStack_.back() == PartKind::SpecificationPart) {
     OmpVariantMatchContext matchContext{context_};
     for (const parser::OmpClause &clause : x.v.Clauses().v) {
-      auto *when{parser::Unwrap<parser::OmpWhenClause>(clause)};
-      if (!when) {
+      auto *variant{GetDirectiveVariant(clause)};
+      if (!variant) {
         continue;
       }
-      const auto &modifiers{OmpGetModifiers(*when)};
-      auto *selector{
-          OmpGetUniqueModifier<parser::OmpContextSelector>(modifiers)};
-      if (!MayVariantBeSelected(selector, context_, matchContext)) {
+      if (!MayVariantBeSelected(
+              GetContextSelector(clause), context_, matchContext)) {
         continue;
       }
-      using DirSpecType =
-          common::Indirection<parser::OmpDirectiveSpecification>;
-      if (auto &maybeSpec{std::get<std::optional<DirSpecType>>(when->t)}) {
-        const parser::OmpDirectiveSpecification &spec{maybeSpec->value()};
-        llvm::omp::Directive dirId{spec.DirId()};
-        if (dirId == llvm::omp::Directive::OMPD_declare_reduction) {
-          CheckDeclareReduction(spec);
-        }
+      llvm::omp::Directive dirId{variant->DirId()};
+      if (dirId == llvm::omp::Directive::OMPD_declare_reduction) {
+        CheckDeclareReduction(*variant);
       }
     }
+    ExitDirectiveNest(MetadirectiveNest);
   }
-  ExitDirectiveNest(MetadirectiveNest);
 }
 
 // Check a loop-associated metadirective's variants against the loop nest they
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 893eb49ff90b0d..6bd15a45861f29 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -2549,31 +2549,49 @@ std::optional<DynamicUserCondition> MakeVariantMatchInfo(
   return dynamicCond;
 }
 
+const parser::OmpContextSelector *GetContextSelector(
+    const parser::OmpClause &clause) {
+  if (auto *when{parser::Unwrap<parser::OmpWhenClause>(clause)}) {
+    const auto &modifiers{OmpGetModifiers(*when)};
+    return OmpGetUniqueModifier<parser::OmpContextSelector>(modifiers);
+  }
+  return nullptr;
+}
+
+const parser::OmpDirectiveSpecification *GetDirectiveVariant(
+    const parser::OmpClause &clause) {
+  using DirectiveSpecification =
+      common::Indirection<parser::OmpDirectiveSpecification>;
+  if (auto *when{parser::Unwrap<parser::OmpWhenClause>(clause)}) {
+    if (auto &spec{std::get<std::optional<DirectiveSpecification>>(when->t)}) {
+      return &spec->value();
+    }
+  } else if (auto *other{parser::Unwrap<parser::OmpOtherwiseClause>(clause)}) {
+    if (auto &spec{other->v}) {
+      return &spec->value();
+    }
+  } else if (auto *def{
+                 parser::Unwrap<parser::OmpDefaultVariantClause>(clause)}) {
+    return &def->v.value();
+  }
+  return nullptr;
+}
+
 std::optional<MetadirectiveCandidateSet> BuildMetadirectiveCandidateSet(
     const parser::OmpClauseList &clauses, SemanticsContext &context,
     const OmpVariantMatchContext &matchContext) {
   MetadirectiveCandidateSet result;
 
-  auto getContextSelector = [](const parser::OmpClause::When &whenClause)
-      -> const parser::modifier::OmpContextSelector * {
-    const auto &modifiers{std::get<0>(whenClause.v.t)};
-    if (!modifiers || modifiers->size() != 1) {
-      return nullptr;
-    }
-    return std::get_if<parser::modifier::OmpContextSelector>(
-        &modifiers->front().u);
-  };
-
-  auto getDirectiveVariant = [](const parser::OmpClause::When &whenClause)
+  auto getDirectiveVariant = [](const parser::OmpClause &clause)
       -> std::pair<const parser::OmpDirectiveSpecification *, bool> {
-    const auto &optionalSpec{std::get<1>(whenClause.v.t)};
-    if (!optionalSpec) {
+    auto *variant{GetDirectiveVariant(clause)};
+    if (!variant) {
       return {nullptr, false};
     }
-    if (optionalSpec->value().DirId() == llvm::omp::Directive::OMPD_nothing) {
+    if (variant->DirId() == llvm::omp::Directive::OMPD_nothing) {
       return {nullptr, true};
     }
-    return {&optionalSpec->value(), true};
+    return {variant, true};
   };
 
   auto getFallbackVariant = [](const parser::OmpDirectiveSpecification &spec) {
@@ -2581,16 +2599,15 @@ std::optional<MetadirectiveCandidateSet> BuildMetadirectiveCandidateSet(
   };
 
   for (const parser::OmpClause &clause : clauses.v) {
-    if (const auto *whenClause{
-            std::get_if<parser::OmpClause::When>(&clause.u)}) {
-      const auto *ctxSel{getContextSelector(*whenClause)};
+    if (clause.Id() == llvm::omp::Clause::OMPC_when) {
+      const auto *ctxSel{GetContextSelector(clause)};
       if (!ctxSel ||
           FindUnsupportedSelectorFeature(*ctxSel, context) !=
               UnsupportedSelectorFeature::None) {
         return std::nullopt;
       }
 
-      auto [spec, isExplicit]{getDirectiveVariant(*whenClause)};
+      auto [spec, isExplicit]{getDirectiveVariant(clause)};
       llvm::omp::VariantMatchInfo rawVMI;
       std::optional<DynamicUserCondition> dynamicCondition{
           MakeVariantMatchInfo(rawVMI, *ctxSel, context)};
diff --git a/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90 b/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90
index 24aa50b0b45cb0..1004dad02683de 100644
--- a/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90
+++ b/flang/test/Semantics/OpenMP/metadirective-declare-reduction.f90
@@ -1,9 +1,15 @@
 !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
 
-subroutine s
+subroutine f01
   !$omp metadirective &
   !$omp& when(implementation={vendor(llvm)}: &
 !ERROR: Invalid reduction intrinsic operator in DECLARE REDUCTION directive
   !$omp& declare reduction(/ : integer : omp_out = omp_out + omp_in))
-end subroutine
+end
 
+subroutine f02
+  !$omp metadirective &
+  !$omp& otherwise(
+!ERROR: Invalid reduction intrinsic operator in DECLARE REDUCTION directive
+  !$omp& declare reduction(/ : integer : omp_out = omp_out + omp_in))
+end



More information about the llvm-branch-commits mailing list