[flang-commits] [flang] [flang] Implement conditional expressions parser/semantics (F2023) (PR #186489)

via flang-commits flang-commits at lists.llvm.org
Fri Mar 13 11:47:27 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-parser

@llvm/pr-subscribers-flang-fir-hlfir

Author: Caroline Newcombe (cenewcombe)

<details>
<summary>Changes</summary>

## Implement Fortran 2023 Conditional Expressions (R1002)

***This PR contains the implementation for parsing and semantic analysis. Lowering is implemented in a separate PR (to be posted soon)***

Implements Fortran 2023 conditional expressions with syntax: `result = (condition ? value1 : condition2 ? value2 : ... : elseValue)`

Issue: #<!-- -->176999
Discourse: https://discourse.llvm.org/t/rfc-adding-conditional-expressions-in-flang-f2023/89869/1 -- note that some of the details provided in the RFC post are no longer accurate

### Implementation Details
**Parser:**
- Added ConditionalExpr as primary expression (F2023 R1002)  
- Right-associative chaining for multi-way conditionals
 
**Semantics:**
- Expression tree node ConditionalExpr<T> with N conditions and N+1 values
- Strict type checking: all values must have identical type, kind, and rank
- Conditions must be scalar LOGICAL

**LIT Testing:**
- Parser tests: Syntax validation, precedence, nesting
- Semantic tests: Type checking, error messages
- Note: Executable tests will be added to the llvm-test-suite repo (PR to be posted soon)

**Limitations**
- Conditional arguments are not yet supported. This work is planned 
    - #<!-- -->180592
- Polymorphic types (CLASS) not yet supported in lowering
- Both limitations will emit clear error message if encountered

### Examples
```
! Simple conditional
x = (flag ? 10 : 20)

! Chained
result = (x > 0 ? 1 : x < 0 ? -1 : 0)

! Examples from F2023
( ABS (RESIDUAL)<=TOLERANCE ? ’ok’ : ’did not converge’ )
( I>0 .AND. I<=SIZE (A) ? A (I) : PRESENT (VAL) ? VAL : 0.0 )
```

AI Usage Disclosure: AI tools (Claude Sonnet 4.5) were used to assist with implementation of this feature and test code generation. I have reviewed, modified, and tested all AI-generated code.

---

Patch is 74.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/186489.diff


31 Files Affected:

- (modified) flang/examples/FeatureList/FeatureList.cpp (+1) 
- (modified) flang/include/flang/Evaluate/expression.h (+41-8) 
- (modified) flang/include/flang/Evaluate/shape.h (+10) 
- (modified) flang/include/flang/Evaluate/tools.h (+28) 
- (modified) flang/include/flang/Evaluate/traverse.h (+4) 
- (modified) flang/include/flang/Parser/characters.h (+1) 
- (modified) flang/include/flang/Parser/dump-parse-tree.h (+2) 
- (modified) flang/include/flang/Parser/parse-tree.h (+19-5) 
- (modified) flang/include/flang/Semantics/dump-expr.h (+22) 
- (modified) flang/include/flang/Semantics/expression.h (+1) 
- (modified) flang/lib/Evaluate/check-expression.cpp (+139) 
- (modified) flang/lib/Evaluate/expression.cpp (+23) 
- (modified) flang/lib/Evaluate/formatting.cpp (+14) 
- (modified) flang/lib/Evaluate/shape.cpp (+56-7) 
- (modified) flang/lib/Evaluate/tools.cpp (+121) 
- (modified) flang/lib/Lower/ConvertExpr.cpp (+10) 
- (modified) flang/lib/Lower/ConvertExprToHLFIR.cpp (+6) 
- (modified) flang/lib/Lower/IterationSpace.cpp (+11) 
- (modified) flang/lib/Lower/Support/Utils.cpp (+32) 
- (modified) flang/lib/Parser/basic-parsers.h (+32) 
- (modified) flang/lib/Parser/expr-parsers.cpp (+12) 
- (modified) flang/lib/Parser/unparse.cpp (+12) 
- (modified) flang/lib/Semantics/check-cuda.cpp (+30) 
- (modified) flang/lib/Semantics/check-data.cpp (+15) 
- (modified) flang/lib/Semantics/check-do-forall.cpp (+11) 
- (modified) flang/lib/Semantics/definable.cpp (+14) 
- (modified) flang/lib/Semantics/expression.cpp (+216) 
- (modified) flang/lib/Semantics/openmp-utils.cpp (+25) 
- (modified) flang/lib/Semantics/resolve-names-utils.cpp (+14) 
- (added) flang/test/Parser/conditional-expr.f90 (+261) 
- (added) flang/test/Semantics/conditional-expr.f90 (+365) 


``````````diff
diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 355d79a04e4ba..bee18096f9fb2 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -311,6 +311,7 @@ struct NodeVisitor {
   READ_FEATURE(Expr::NEQV)
   READ_FEATURE(Expr::DefinedBinary)
   READ_FEATURE(Expr::ComplexConstructor)
+  READ_FEATURE(ConditionalExpr)
   READ_FEATURE(External)
   READ_FEATURE(ExternalStmt)
   READ_FEATURE(FailImageStmt)
diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h
index f7a1f9b955181..d46699cb7ac2c 100644
--- a/flang/include/flang/Evaluate/expression.h
+++ b/flang/include/flang/Evaluate/expression.h
@@ -390,6 +390,36 @@ struct LogicalOperation
   LogicalOperator logicalOperator;
 };
 
+// Fortran 2023 conditional expression: (cond ? val : cond ? val : ... : else)
+// All branches have the same type and rank (verified during semantic analysis).
+template <typename T> class ConditionalExpr {
+public:
+  using Result = T;
+  CLASS_BOILERPLATE(ConditionalExpr)
+  ConditionalExpr(
+      std::vector<Expr<SomeLogical>> &&conds, std::vector<Expr<Result>> &&vals)
+      : conditions_{std::move(conds)}, values_{std::move(vals)} {
+    CHECK(values_.size() == conditions_.size() + 1);
+  }
+  bool operator==(const ConditionalExpr &) const;
+  const std::vector<Expr<SomeLogical>> &conditions() const {
+    return conditions_;
+  }
+  std::vector<Expr<SomeLogical>> &conditions() { return conditions_; }
+  const std::vector<Expr<Result>> &values() const { return values_; }
+  std::vector<Expr<Result>> &values() { return values_; }
+  int Rank() const { return values_.empty() ? 0 : values_.front().Rank(); }
+  std::optional<DynamicType> GetType() const {
+    return values_.empty() ? std::nullopt : values_.front().GetType();
+  }
+  static constexpr int Corank() { return 0; }
+  llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
+
+private:
+  std::vector<Expr<SomeLogical>> conditions_; // size N
+  std::vector<Expr<Result>> values_; // size N+1 (includes else)
+};
+
 // Array constructors
 template <typename RESULT> class ArrayConstructorValues;
 
@@ -536,7 +566,7 @@ class Expr<Type<TypeCategory::Integer, KIND>>
       Convert<Result, TypeCategory::Unsigned>>;
   using Operations = std::tuple<Parentheses<Result>, Negate<Result>,
       Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
-      Power<Result>, Extremum<Result>>;
+      Power<Result>, Extremum<Result>, ConditionalExpr<Result>>;
   using Indices = std::conditional_t<KIND == ImpliedDoIndex::Result::kind,
       std::tuple<ImpliedDoIndex>, std::tuple<>>;
   using TypeParamInquiries =
@@ -568,7 +598,7 @@ class Expr<Type<TypeCategory::Unsigned, KIND>>
       Convert<Result, TypeCategory::Unsigned>>;
   using Operations = std::tuple<Parentheses<Result>, Negate<Result>,
       Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
-      Power<Result>, Extremum<Result>>;
+      Power<Result>, Extremum<Result>, ConditionalExpr<Result>>;
   using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
       Designator<Result>, FunctionRef<Result>>;
 
@@ -594,7 +624,8 @@ class Expr<Type<TypeCategory::Real, KIND>>
       Convert<Result, TypeCategory::Unsigned>>;
   using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>,
       Negate<Result>, Add<Result>, Subtract<Result>, Multiply<Result>,
-      Divide<Result>, Power<Result>, RealToIntPower<Result>, Extremum<Result>>;
+      Divide<Result>, Power<Result>, RealToIntPower<Result>, Extremum<Result>,
+      ConditionalExpr<Result>>;
   using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
       Designator<Result>, FunctionRef<Result>>;
 
@@ -612,7 +643,7 @@ class Expr<Type<TypeCategory::Complex, KIND>>
   using Operations = std::variant<Parentheses<Result>, Negate<Result>,
       Convert<Result, TypeCategory::Complex>, Add<Result>, Subtract<Result>,
       Multiply<Result>, Divide<Result>, Power<Result>, RealToIntPower<Result>,
-      ComplexConstructor<KIND>>;
+      ComplexConstructor<KIND>, ConditionalExpr<Result>>;
   using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
       Designator<Result>, FunctionRef<Result>>;
 
@@ -638,7 +669,7 @@ class Expr<Type<TypeCategory::Character, KIND>>
 
   std::variant<Constant<Result>, ArrayConstructor<Result>, Designator<Result>,
       FunctionRef<Result>, Parentheses<Result>, Convert<Result>, Concat<KIND>,
-      Extremum<Result>, SetLength<KIND>>
+      Extremum<Result>, SetLength<KIND>, ConditionalExpr<Result>>
       u;
 };
 
@@ -710,7 +741,7 @@ class Expr<Type<TypeCategory::Logical, KIND>>
 
 private:
   using Operations = std::tuple<Convert<Result>, Parentheses<Result>, Not<KIND>,
-      LogicalOperation<KIND>>;
+      LogicalOperation<KIND>, ConditionalExpr<Result>>;
   using Relations = std::conditional_t<KIND == LogicalResult::kind,
       std::tuple<Relational<SomeType>>, std::tuple<>>;
   using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
@@ -788,7 +819,8 @@ template <> class Expr<SomeDerived> : public ExpressionBase<SomeDerived> {
   using Result = SomeDerived;
   EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
   std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor,
-      Designator<Result>, FunctionRef<Result>, Parentheses<Result>>
+      Designator<Result>, FunctionRef<Result>, Parentheses<Result>,
+      ConditionalExpr<Result>>
       u;
 };
 
@@ -929,6 +961,7 @@ FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor, )
   template class Relational<SomeType>; \
   FOR_EACH_TYPE_AND_KIND(template class ExpressionBase, ) \
   FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues, ) \
-  FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor, )
+  FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor, ) \
+  FOR_EACH_INTRINSIC_KIND(template class ConditionalExpr, )
 } // namespace Fortran::evaluate
 #endif // FORTRAN_EVALUATE_EXPRESSION_H_
diff --git a/flang/include/flang/Evaluate/shape.h b/flang/include/flang/Evaluate/shape.h
index f0505cfcdf2d7..3af78820f6c66 100644
--- a/flang/include/flang/Evaluate/shape.h
+++ b/flang/include/flang/Evaluate/shape.h
@@ -189,6 +189,16 @@ class GetShapeHelper
   Result operator()(const ArrayConstructor<T> &aconst) const {
     return Shape{GetArrayConstructorExtent(aconst)};
   }
+  template <typename T>
+  Result operator()(const ConditionalExpr<T> &conditional) const {
+    // Per F2023 10.1.4(7), the shape is determined by the selected branch,
+    // so return unknown extents for the rank.
+    if (!conditional.values().empty()) {
+      int rank{conditional.values().front().Rank()};
+      return Shape(rank, std::nullopt);
+    }
+    return ScalarShape();
+  }
   template <typename D, typename R, typename LO, typename RO>
   Result operator()(const Operation<D, R, LO, RO> &operation) const {
     if (int rr{operation.right().Rank()}; rr > 0) {
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 0fded08456bcf..9ba29a5a2879c 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -50,6 +50,9 @@ struct IsVariableHelper
   Result operator()(const CoarrayRef &) const { return true; }
   Result operator()(const ComplexPart &) const { return true; }
   Result operator()(const ProcedureDesignator &) const;
+  template <typename T> Result operator()(const ConditionalExpr<T> &) const {
+    return false;
+  }
   template <typename T> Result operator()(const Expr<T> &x) const {
     if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
         std::is_same_v<T, SomeDerived>) {
@@ -1071,6 +1074,16 @@ struct GetSymbolVectorHelper
   Result operator()(const Component &) const;
   Result operator()(const ArrayRef &) const;
   Result operator()(const CoarrayRef &) const;
+  template <typename T> Result operator()(const ConditionalExpr<T> &x) {
+    Result result;
+    for (const auto &cond : x.conditions()) {
+      result = Combine(std::move(result), (*this)(cond));
+    }
+    for (const auto &val : x.values()) {
+      result = Combine(std::move(result), (*this)(val));
+    }
+    return result;
+  }
 };
 template <typename A> SymbolVector GetSymbolVector(const A &x) {
   return GetSymbolVectorHelper{}(x);
@@ -1159,6 +1172,20 @@ class UnsafeToCopyVisitor : public AnyTraverse<UnsafeToCopyVisitor> {
     return !admitPureCall_ || !procRef.proc().IsPure();
   }
   bool operator()(const CoarrayRef &) { return true; }
+  template <typename T> bool operator()(const ConditionalExpr<T> &x) {
+    // A conditional expression is unsafe to copy if any of its parts are unsafe
+    for (const auto &condition : x.conditions()) {
+      if ((*this)(condition)) {
+        return true;
+      }
+    }
+    for (const auto &value : x.values()) {
+      if ((*this)(value)) {
+        return true;
+      }
+    }
+    return false;
+  }
 
 private:
   bool admitPureCall_{false};
@@ -1381,6 +1408,7 @@ enum class Operator {
   Call,
   Constant,
   Convert,
+  Conditional,
   Div,
   Eq,
   Eqv,
diff --git a/flang/include/flang/Evaluate/traverse.h b/flang/include/flang/Evaluate/traverse.h
index d63c16f93230a..306337274bf1f 100644
--- a/flang/include/flang/Evaluate/traverse.h
+++ b/flang/include/flang/Evaluate/traverse.h
@@ -224,6 +224,10 @@ class Traverse {
   Result operator()(const StructureConstructor &x) const {
     return visitor_.Combine(visitor_(x.derivedTypeSpec()), CombineContents(x));
   }
+  // Conditional expressions (Fortran 2023)
+  template <typename T> Result operator()(const ConditionalExpr<T> &x) const {
+    return Combine(x.conditions(), x.values());
+  }
 
   // Operations and wrappers
   // Have a single operator() for all Operations.
diff --git a/flang/include/flang/Parser/characters.h b/flang/include/flang/Parser/characters.h
index 3761700ad348c..620c6b357f948 100644
--- a/flang/include/flang/Parser/characters.h
+++ b/flang/include/flang/Parser/characters.h
@@ -170,6 +170,7 @@ inline constexpr bool IsValidFortranTokenCharacter(char ch) {
   case '<':
   case '=':
   case '>':
+  case '?': // Used in conditional expressions (Fortran 2023)
   case '[':
   case ']':
   case '{': // Used in OpenMP context selector specification
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 84c7b8d2a5349..4f6142af7eaf6 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -252,6 +252,8 @@ class ParseTreeDumper {
   NODE(parser, ComputedGotoStmt)
   NODE(parser, ConcurrentControl)
   NODE(parser, ConcurrentHeader)
+  NODE(parser, ConditionalExpr)
+  NODE(ConditionalExpr, Branch)
   NODE(parser, ConnectSpec)
   NODE(ConnectSpec, CharExpr)
   NODE_ENUM(ConnectSpec::CharExpr, Kind)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 4aec99c80bdae..706d31dca3331 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -1678,6 +1678,19 @@ struct ImageSelector {
   std::tuple<std::list<Cosubscript>, std::list<ImageSelectorSpec>> t;
 };
 
+// F2023: R1002 conditional-expr ->
+//   ( scalar-logical-expr ? expr
+//     [ : scalar-logical-expr ? expr ]...
+//     : expr )
+struct ConditionalExpr {
+  TUPLE_CLASS_BOILERPLATE(ConditionalExpr);
+  struct Branch {
+    TUPLE_CLASS_BOILERPLATE(Branch);
+    std::tuple<ScalarLogicalExpr, common::Indirection<Expr>> t;
+  };
+  std::tuple<std::list<Branch>, common::Indirection<Expr>> t;
+};
+
 // R1001 - R1022 expressions
 struct Expr {
   UNION_CLASS_BOILERPLATE(Expr);
@@ -1776,11 +1789,12 @@ struct Expr {
   CharBlock source;
 
   std::variant<common::Indirection<CharLiteralConstantSubstring>,
-      LiteralConstant, common::Indirection<Designator>, ArrayConstructor,
-      StructureConstructor, common::Indirection<FunctionReference>, Parentheses,
-      UnaryPlus, Negate, NOT, PercentLoc, DefinedUnary, Power, Multiply, Divide,
-      Add, Subtract, Concat, LT, LE, EQ, NE, GE, GT, AND, OR, EQV, NEQV,
-      DefinedBinary, ComplexConstructor, common::Indirection<SubstringInquiry>>
+      LiteralConstant, ConditionalExpr, common::Indirection<Designator>,
+      ArrayConstructor, StructureConstructor,
+      common::Indirection<FunctionReference>, Parentheses, UnaryPlus, Negate,
+      NOT, PercentLoc, DefinedUnary, Power, Multiply, Divide, Add, Subtract,
+      Concat, LT, LE, EQ, NE, GE, GT, AND, OR, EQV, NEQV, DefinedBinary,
+      ComplexConstructor, common::Indirection<SubstringInquiry>>
       u;
 };
 
diff --git a/flang/include/flang/Semantics/dump-expr.h b/flang/include/flang/Semantics/dump-expr.h
index 8cbb78b585f4a..5fbed77139958 100644
--- a/flang/include/flang/Semantics/dump-expr.h
+++ b/flang/include/flang/Semantics/dump-expr.h
@@ -201,6 +201,28 @@ class DumpEvaluateExpr {
     Show(op.right());
     Outdent();
   }
+  template <typename T> void Show(const evaluate::ConditionalExpr<T> &x) {
+    Indent("conditional expr "s + std::string(TypeOf<T>::name));
+    const auto &conds = x.conditions();
+    const auto &vals = x.values();
+    // Show condition-value pairs
+    for (const auto &[cond, val] : llvm::zip(conds, vals)) {
+      Indent("branch");
+      Indent("condition");
+      Show(cond);
+      Outdent();
+      Indent("value");
+      Show(val);
+      Outdent();
+      Outdent();
+    }
+    if (!vals.empty()) {
+      Indent("default value");
+      Show(vals.back());
+      Outdent();
+    }
+    Outdent();
+  }
   void Show(const evaluate::Relational<evaluate::SomeType> &x);
   template <typename T> void Show(const evaluate::Expr<T> &x) {
     Indent("expr <"s + std::string(TypeOf<T>::name) + ">"s);
diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index 490399aa03ff8..0054a86486e79 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -169,6 +169,7 @@ class ExpressionAnalyzer {
   MaybeExpr Analyze(const parser::DataStmtValue &);
   MaybeExpr Analyze(const parser::AllocateObject &);
   MaybeExpr Analyze(const parser::PointerObject &);
+  MaybeExpr Analyze(const parser::ConditionalExpr &);
 
   template <typename A> MaybeExpr Analyze(const common::Indirection<A> &x) {
     return Analyze(x.value());
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index e73a4d82951af..7c5e7c129765c 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -92,6 +92,23 @@ class IsConstantExprHelper
                 !sym.attrs().test(semantics::Attr::VALUE)));
   }
 
+  template <typename T>
+  bool operator()(const ConditionalExpr<T> &conditional) const {
+    // A conditional expression is constant if all its conditions and values are
+    // constant
+    for (const auto &condition : conditional.conditions()) {
+      if (!(*this)(condition)) {
+        return false;
+      }
+    }
+    for (const auto &value : conditional.values()) {
+      if (!(*this)(value)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   bool operator()(const ImpliedDoIndex &ido) const {
     return acImpliedDos_.find(ido.name) != acImpliedDos_.end() || !context_ ||
         context_->GetImpliedDo(ido.name).has_value();
@@ -229,6 +246,20 @@ struct IsActuallyConstantHelper {
   template <typename T> bool operator()(const Parentheses<T> &x) {
     return (*this)(x.left());
   }
+  template <typename T> bool operator()(const ConditionalExpr<T> &x) {
+    // A conditional expression is actually constant if all its parts are
+    for (const auto &condition : x.conditions()) {
+      if (!(*this)(condition)) {
+        return false;
+      }
+    }
+    for (const auto &value : x.values()) {
+      if (!(*this)(value)) {
+        return false;
+      }
+    }
+    return true;
+  }
   template <typename T> bool operator()(const Expr<T> &x) {
     return common::visit([=](const auto &y) { return (*this)(y); }, x.u);
   }
@@ -358,6 +389,10 @@ class IsInitialDataTargetHelper
   bool operator()(const Operation<D, R, O...> &) const {
     return false;
   }
+  template <typename T> bool operator()(const ConditionalExpr<T> &) const {
+    // A conditional expression cannot be an initial data target
+    return false;
+  }
   template <typename T> bool operator()(const Parentheses<T> &x) const {
     return (*this)(x.left());
   }
@@ -492,6 +527,21 @@ class SuspiciousRealLiteralFinder
     }
     return (*this)(x.left());
   }
+  template <typename T> bool operator()(const ConditionalExpr<T> &x) const {
+    // Check all conditions and values in the conditional expression for
+    // suspicious literals
+    for (const auto &cond : x.conditions()) {
+      if ((*this)(cond)) {
+        return true;
+      }
+    }
+    for (const auto &value : x.values()) {
+      if ((*this)(value)) {
+        return true;
+      }
+    }
+    return false;
+  }
 
 private:
   int kind_;
@@ -531,6 +581,16 @@ class InexactLiteralConversionFlagClearer
     mut.set_isFromInexactLiteralConversion(false);
     return false;
   }
+  template <typename T> bool operator()(const ConditionalExpr<T> &x) const {
+    // Clear flags in all conditions and values of the conditional expression
+    for (const auto &cond : x.conditions()) {
+      (*this)(cond);
+    }
+    for (const auto &value : x.values()) {
+      (*this)(value);
+    }
+    return false;
+  }
 };
 
 // Converts, folds, and then checks type, rank, and shape of an
@@ -798,6 +858,20 @@ class CheckSpecificationExprHelper
     return std::nullopt;
   }
 
+  template <typename T> Result operator()(const ConditionalExpr<T> &x) const {
+    for (const auto &cond : x.conditions()) {
+      if (auto result{(*this)(cond)}) {
+        return result;
+      }
+    }
+    for (const auto &val : x.values()) {
+      if (auto result{(*this)(val)}) {
+        return result;
+      }
+    }
+    return std::nullopt;
+  }
+
   Result operator()(const ProcedureRef &x) const {
     if (const auto *symbol{x.proc().GetSymbol()}) {
       const Symbol &ultimate{symbol->GetUltimate()};
@@ -1193,6 +1267,31 @@ class IsContiguousHelper
 
   Result operator()(const NullPointer &) const { return true; }
 
+  template <typename T> Result operator()(const ConditionalExpr<T> &x) {
+    // Track contiguity across all possible runtime branches
+    bool hasContiguous{false};
+    bool hasNonContiguous{false};
+    bool hasUnknown{false};
+    for (const auto &val : x.values()) {
+      auto result{(*this)(val)};
+      if (!result) {
+        hasUnknown = true;
+      } else if (*result) {
+        hasContiguous = true;
+      } else {
+        hasNonContiguous = true;
+      }
+    }
+    // Return definite result only if all values have uniform contiguity
+    if (hasUnknown || (hasContiguous && hasNonContiguous)) {
+      return std::nullopt;
+    } else if (hasContiguous) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
 private:
   // Returns "true" for a provably empty or simply contiguous array section;
   // return "false" for a provably nonempty discontiguous section or for use
@@ -1386,6 +1485,20 @@ struct IsErrorExprHelper : public AnyTraverse<IsErrorExprHelper, bool> {
   bool operator()(const SpecificIntrinsic &x) {
     return x.name == IntrinsicProcTable::InvalidName;
   }
+
+  template <typename T> bool operator()(const ConditionalExpr<T> &x) {
+    for (const auto &cond : x.conditions()) {
+      if ((*this)(cond)) {
+        return true;
+      }
+    }
+    for (const auto &val : x.values()) {
+      if ((*this)(val)) {
+        return true;
+      }
+    }
+    return false;
+  }
 };
 
 template <typename A> bool IsErrorExpr(const A &x) {
@@ -1501,6 +1614,20 @@ class StmtFunctionChecker
     return std::nullopt;
   }
 
+  template <typename T> Result operator()(const ConditionalExpr<T> &x) {
+    for (const auto &cond : x.conditions()) {
+      if (auto result{(*this)(cond)}) {
+        return result;
+      }
+    }
+    for (const auto &val : x.values()) {
+      if (auto result{(*this)(val)}) {
+        return result;
+      }
+    }
+    return std::nullopt;
+  }
+
 private:
   const Symbol &sf_;
   FoldingContext &context_;
@@ -1760,6 +1887,18 @@ class CollectUsedSymbolValuesHelper
 ...
[truncated]

``````````

</details>


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


More information about the flang-commits mailing list