[flang-commits] [flang] [flang] Implement conditional expressions lowering (F2023) (PR #186490)

Caroline Newcombe via flang-commits flang-commits at lists.llvm.org
Thu Apr 9 08:02:42 PDT 2026


https://github.com/cenewcombe updated https://github.com/llvm/llvm-project/pull/186490

>From f42b4c43647a4c3243633d67add0223321f815cc Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Fri, 13 Mar 2026 13:25:35 -0500
Subject: [PATCH 1/9] [flang] Implement conditional expressions lowering
 (F2023)

Implements HLFIR lowering Fortran 2023 conditional expressions (R1002):
  result = (condition ? value1 : condition2 ? value2 : ... : elseValue)

This adds:
- Lowering to HLFIR with lazy evaluation using conditional branches
- Parsing and semantics implemented in a separate branch/PR
- LIT test coverage for HLFIR lowering

Current limitations:
- Conditional expressions as actual arguments are not yet implemented
- Polymorphic (CLASS) types not yet supported

This implements #176999
---
 flang/lib/Lower/ConvertExprToHLFIR.cpp      | 188 ++++++++++++++
 flang/test/Lower/HLFIR/conditional-expr.f90 | 257 ++++++++++++++++++++
 2 files changed, 445 insertions(+)
 create mode 100644 flang/test/Lower/HLFIR/conditional-expr.f90

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 7ddd09e59c262..8422c2a039efd 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1827,6 +1827,194 @@ class HlfirBuilder {
     llvm_unreachable("unknown descriptor inquiry");
   }
 
+  /// Build nested if-then-else chain for conditional expressions with lazy
+  /// evaluation. The assignValue callback generates and assigns each value to
+  /// avoid evaluating non-taken branches.
+  template <typename T>
+  void buildConditionalIfChain(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+      const std::function<void(int valueIndex)> &assignValue) {
+    const mlir::Location loc = getLoc();
+    fir::FirOpBuilder &builder = getBuilder();
+    std::function<void(int)> buildIfChain = [&](int i) {
+      if (i >= static_cast<int>(condExpr.conditions().size())) {
+        // All conditions false: assign final else value.
+        getStmtCtx().pushScope();
+        assignValue(static_cast<int>(condExpr.values().size()) - 1);
+        getStmtCtx().finalizeAndPop();
+      } else {
+        getStmtCtx().pushScope();
+        const hlfir::EntityWithAttributes condEntity =
+            gen(condExpr.conditions()[i]);
+        mlir::Value condition =
+            hlfir::loadTrivialScalar(loc, builder, condEntity);
+        condition = builder.createConvert(loc, builder.getI1Type(), condition);
+        builder.genIfOp(loc, {}, condition, /*withElseRegion=*/true)
+            .genThen([&]() {
+              getStmtCtx().pushScope();
+              assignValue(i);
+              getStmtCtx().finalizeAndPop();
+            })
+            .genElse([&]() { buildIfChain(i + 1); })
+            .end();
+        getStmtCtx().finalizeAndPop();
+      }
+    };
+    buildIfChain(0);
+  }
+
+  /// Generate scalar conditional with lazy evaluation using assignment.
+  /// Creates a temporary and assigns the selected branch value to it.
+  template <typename T>
+  hlfir::Entity genScalarConditionalLazy(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+      mlir::Type elementType,
+      const llvm::SmallVector<mlir::Value, 1> &typeParams) {
+    const mlir::Location loc = getLoc();
+    fir::FirOpBuilder &builder = getBuilder();
+    const mlir::Value tempStorage = builder.createTemporary(
+        loc, elementType, ".cond.scalar",
+        /*shape=*/mlir::ValueRange{}, /*typeParams=*/typeParams);
+    const hlfir::DeclareOp tempDecl = hlfir::DeclareOp::create(
+        builder, loc, tempStorage, ".cond.result",
+        /*shape=*/mlir::Value{}, /*typeParams=*/typeParams);
+    const hlfir::Entity temp{tempDecl};
+    buildConditionalIfChain(condExpr, [&](int valueIndex) {
+      hlfir::Entity entity = gen(condExpr.values()[valueIndex]);
+      auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
+      hlfir::Entity value{fir::getBase(exv)};
+      if (cleanup) {
+        getStmtCtx().attachCleanup(*cleanup);
+      }
+      hlfir::AssignOp::create(builder, loc, value, temp);
+    });
+    return temp;
+  }
+
+  /// Generate conditional expression using an allocatable temporary with lazy
+  /// evaluation. Creates an unallocated allocatable, then uses assignment to
+  /// set the value from the chosen branch (allocation/reallocation handled by
+  /// runtime).
+  template <typename T>
+  hlfir::Entity genAllocatableConditionalLazy(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+      mlir::Type resultType, llvm::StringRef debugName) {
+    const mlir::Location loc = getLoc();
+    fir::FirOpBuilder &builder = getBuilder();
+    const mlir::Type heapType = fir::HeapType::get(resultType);
+    const mlir::Type boxHeapType = fir::BoxType::get(heapType);
+    const mlir::Value tempStorage =
+        builder.createTemporary(loc, boxHeapType, debugName);
+    const mlir::Value unallocBox = fir::factory::createUnallocatedBox(
+        builder, loc, boxHeapType, /*nonDeferredParams=*/{});
+    builder.createStoreWithConvert(loc, unallocBox, tempStorage);
+    const hlfir::DeclareOp tempDecl =
+        hlfir::DeclareOp::create(builder, loc, tempStorage, ".cond.result");
+    const hlfir::Entity temp{tempDecl};
+    // Lazy evaluation: only the selected branch is evaluated and assigned.
+    buildConditionalIfChain(condExpr, [&](int valueIndex) {
+      const hlfir::Entity entity = gen(condExpr.values()[valueIndex]);
+      hlfir::AssignOp::create(builder, loc, entity, temp,
+                              /*isWholeAllocatableAssignment=*/true,
+                              /*keepLhsLengthIfRealloc=*/false,
+                              /*temporary_lhs=*/true);
+    });
+    return temp;
+  }
+
+  /// Generate scalar CHARACTER conditional with deferred-length using lazy
+  /// evaluation. Only the chosen branch is evaluated; the result gets that
+  /// branch's length.
+  template <typename T>
+  hlfir::Entity genScalarDeferredCharConditionalLazy(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+      mlir::Type elementType) {
+    return genAllocatableConditionalLazy(condExpr, elementType, ".cond.char");
+  }
+
+  /// Generate array conditional expression with lazy evaluation using
+  /// assignment. Per F2023 10.1.4(7), the shape is determined by the chosen
+  /// branch.
+  template <typename T>
+  hlfir::Entity genArrayConditionalLazy(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
+    mlir::Type condResultType = Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr));
+    if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
+      condResultType = fir::unwrapRefType(boxTy.getEleTy());
+    }
+    return genAllocatableConditionalLazy(condExpr, condResultType,
+                                         ".cond.array");
+  }
+
+  /// Generate scalar CHARACTER conditional with proper length handling.
+  template <typename T>
+  std::optional<hlfir::EntityWithAttributes> genCharacterConditional(
+      const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
+    const mlir::Location loc = getLoc();
+    fir::FirOpBuilder &builder = getBuilder();
+    const mlir::Type resultType = Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr));
+    const mlir::Type elementType = hlfir::getFortranElementType(resultType);
+    if (auto charType = mlir::dyn_cast<fir::CharacterType>(elementType)) {
+      if (charType.hasConstantLen()) {
+        llvm::SmallVector<mlir::Value, 1> typeParams;
+        const mlir::Value len = builder.createIntegerConstant(
+            loc, builder.getCharacterLengthType(), charType.getLen());
+        typeParams.push_back(len);
+        return hlfir::EntityWithAttributes{
+            genScalarConditionalLazy(condExpr, elementType, typeParams)};
+      }
+      // Non-constant/varying length: use allocatable conditional to get length
+      // from selected branch.
+      return hlfir::EntityWithAttributes{
+          genScalarDeferredCharConditionalLazy(condExpr, elementType)};
+    }
+    return std::nullopt;
+  }
+
+  /// Conditional expression (Fortran 2023)
+  template <typename T>
+  hlfir::EntityWithAttributes
+  gen(const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
+    assert(!condExpr.conditions().empty() &&
+           "conditional expression must have conditions");
+    assert(!condExpr.values().empty() &&
+           "conditional expression must have values");
+    assert(condExpr.values().size() == condExpr.conditions().size() + 1 &&
+           "values must have exactly one more element than conditions");
+    const int rank = condExpr.Rank();
+
+    // Arrays: handle early to avoid unnecessary type checks.
+    // Per F2023 10.1.4(7), the shape is determined by the chosen branch.
+    if (rank != 0) {
+      return hlfir::EntityWithAttributes{genArrayConditionalLazy(condExpr)};
+    }
+    // CHARACTER scalars require special handling for type parameters.
+    if constexpr (T::category == Fortran::common::TypeCategory::Character) {
+      if (auto result = genCharacterConditional(condExpr)) {
+        return *result;
+      }
+    }
+    // Derived type scalars require special handling for type parameters.
+    if constexpr (T::category == Fortran::common::TypeCategory::Derived) {
+      const mlir::Type resultType = Fortran::lower::translateSomeExprToFIRType(
+          converter, toEvExpr(condExpr));
+      const mlir::Type elementType = hlfir::getFortranElementType(resultType);
+      return hlfir::EntityWithAttributes{
+          genScalarConditionalLazy(condExpr, elementType, {})};
+    }
+    // Other scalar types (INTEGER, REAL, COMPLEX, LOGICAL, UNSIGNED).
+    mlir::Type condResultType = Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr));
+    if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
+      condResultType = fir::unwrapRefType(boxTy.getEleTy());
+    }
+    const mlir::Type resultType = hlfir::getFortranElementType(condResultType);
+    return hlfir::EntityWithAttributes{
+        genScalarConditionalLazy(condExpr, resultType, {})};
+  }
+
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::ImpliedDoIndex &var) {
     mlir::Value value = symMap.lookupImpliedDo(toStringRef(var.name));
diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
new file mode 100644
index 0000000000000..6da5f11ddc011
--- /dev/null
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -0,0 +1,257 @@
+! Test lowering of conditional expressions (Fortran 2023)
+! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPtest_scalar_integer(
+! CHECK-SAME:    %[[FLAG:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "flag"},
+! CHECK-SAME:    %[[X:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME:    %[[Y:.*]]: !fir.ref<i32> {fir.bindc_name = "y"})
+subroutine test_scalar_integer(flag, x, y)
+  logical :: flag
+  integer :: x, y, result
+  ! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! CHECK-DAG: %[[FLAG_DECL:.*]]:2 = hlfir.declare %[[FLAG]]
+  ! CHECK-DAG: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]]
+  ! CHECK-DAG: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]]
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
+
+  result = (flag ? x : y)
+  ! CHECK: %[[FLAG_LOAD:.*]] = fir.load %[[FLAG_DECL]]#0
+  ! CHECK: %[[FLAG_CONV:.*]] = fir.convert %[[FLAG_LOAD]] : (!fir.logical<4>) -> i1
+  ! CHECK: fir.if %[[FLAG_CONV]] {
+  ! CHECK:   %[[X_LOAD:.*]] = fir.load %[[X_DECL]]#0
+  ! CHECK:   hlfir.assign %[[X_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
+  ! CHECK: } else {
+  ! CHECK:   %[[Y_LOAD:.*]] = fir.load %[[Y_DECL]]#0
+  ! CHECK:   hlfir.assign %[[Y_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
+  ! CHECK: }
+  ! CHECK: %[[LOAD:.*]] = fir.load %[[TEMP_DECL]]#0
+  ! CHECK: hlfir.assign %[[LOAD]] to %{{.*}} : i32, !fir.ref<i32>
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_scalar_real(
+subroutine test_scalar_real(flag, x, y)
+  logical :: flag
+  real :: x, y, result
+  result = (flag ? x : y)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca f32 {bindc_name = ".cond.scalar"
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_scalar_complex(
+subroutine test_scalar_complex(flag, x, y)
+  logical :: flag
+  complex :: x, y, result
+  result = (flag ? x : y)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca complex<f32> {bindc_name = ".cond.scalar"
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_scalar_logical(
+subroutine test_scalar_logical(flag, x, y)
+  logical :: flag, x, y, result
+  result = (flag ? x : y)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca !fir.logical<4> {bindc_name = ".cond.scalar"
+  ! CHECK: fir.if
+  ! CHECK: } else {
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_multi_branch(
+subroutine test_multi_branch(x)
+  integer :: x, result
+  ! Multi-branch: x > 10 ? 100 : x > 5 ? 50 : 0
+  result = (x > 10 ? 100 : x > 5 ? 50 : 0)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
+  ! First condition: x > 10
+  ! CHECK: %[[CMP1:.*]] = arith.cmpi sgt
+  ! CHECK: fir.if %[[CMP1]] {
+  ! CHECK:   %[[C100:.*]] = arith.constant 100
+  ! CHECK:   hlfir.assign %[[C100]] to %[[TEMP_DECL]]#0
+  ! CHECK: } else {
+  ! Second condition: x > 5
+  ! CHECK:   %[[CMP2:.*]] = arith.cmpi sgt
+  ! CHECK:   fir.if %[[CMP2]] {
+  ! CHECK:     %[[C50:.*]] = arith.constant 50
+  ! CHECK:     hlfir.assign %[[C50]] to %[[TEMP_DECL]]#0
+  ! CHECK:   } else {
+  ! CHECK:     %[[C0:.*]] = arith.constant 0
+  ! CHECK:     hlfir.assign %[[C0]] to %[[TEMP_DECL]]#0
+  ! CHECK:   }
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_char_constant_len(
+subroutine test_char_constant_len(flag)
+  logical :: flag
+  character(len=5) :: str1, str2, result
+  str1 = "HELLO"
+  str2 = "WORLD"
+  result = (flag ? str1 : str2)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca !fir.char<1,5> {bindc_name = ".cond.scalar"
+  ! CHECK: %{{.*}} = arith.constant 5 : index
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] typeparams %{{.*}} {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_char_deferred_len(
+subroutine test_char_deferred_len(flag)
+  logical :: flag
+  character(len=:), allocatable :: str1, str2, result
+  str1 = "SHORT"
+  str2 = "A MUCH LONGER STRING"
+  ! Result length comes from selected branch
+  result = (flag ? str1 : str2)
+  ! CHECK-DAG: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>> {bindc_name = ".cond.char"
+  ! CHECK-DAG: %[[UNALLOC:.*]] = fir.zero_bits !fir.heap<!fir.char<1,?>>
+  ! CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index
+  ! CHECK: %[[BOX:.*]] = fir.embox %[[UNALLOC]] typeparams %[[C0]]
+  ! CHECK: fir.store %[[BOX]] to %{{.*}} : !fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>
+  ! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX_ALLOC]] {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[BOX_DECL]]#0 realloc temporary_lhs
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[BOX_DECL]]#0 realloc temporary_lhs
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_array(
+subroutine test_array(flag)
+  logical :: flag
+  integer :: arr1(10), arr2(10), result(10)
+  arr1 = 1
+  arr2 = 2
+  result = (flag ? arr1 : arr2)
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".cond.array"
+  ! CHECK: %[[UNALLOC:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
+  ! CHECK: %[[SHAPE:.*]] = fir.shape
+  ! CHECK: %[[BOX:.*]] = fir.embox %[[UNALLOC]](%[[SHAPE]])
+  ! CHECK: fir.store %[[BOX]] to %[[BOX_ALLOC]]
+  ! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX_ALLOC]] {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[BOX_DECL]]#0 realloc temporary_lhs
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[BOX_DECL]]#0 realloc temporary_lhs
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_derived_type(
+subroutine test_derived_type(flag)
+  type :: point
+    real :: x, y
+  end type
+  logical :: flag
+  type(point) :: p1, p2, result
+  p1 = point(1.0, 2.0)
+  p2 = point(3.0, 4.0)
+  result = (flag ? p1 : p2)
+  ! CHECK: %[[TEMP:.*]] = fir.alloca !fir.type<_QFtest_derived_typeTpoint{x:f32,y:f32}> {bindc_name = ".cond.scalar"
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.type<_QFtest_derived_typeTpoint{x:f32,y:f32}>>, !fir.ref<!fir.type<_QFtest_derived_typeTpoint{x:f32,y:f32}>>
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.type<_QFtest_derived_typeTpoint{x:f32,y:f32}>>, !fir.ref<!fir.type<_QFtest_derived_typeTpoint{x:f32,y:f32}>>
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_nested_conditionals(
+subroutine test_nested_conditionals(flag1, flag2, x, y, z)
+  logical :: flag1, flag2
+  integer :: x, y, z, result
+  ! Nested: flag1 ? (flag2 ? x : y) : z
+  result = (flag1 ? (flag2 ? x : y) : z)
+  ! Outer temp allocation
+  ! CHECK: fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! Outer temp declaration and conditional
+  ! CHECK: hlfir.declare {{.*}} {uniq_name = ".cond.result"}
+  ! CHECK: fir.if {{%.*}} {
+  ! Inner temp declaration and conditional
+  ! CHECK:   hlfir.declare {{.*}} {uniq_name = ".cond.result"}
+  ! CHECK:   fir.if {{%.*}} {
+  ! CHECK:     hlfir.assign {{.*}}
+  ! CHECK:   } else {
+  ! CHECK:     hlfir.assign {{.*}}
+  ! CHECK:   }
+  ! CHECK:   fir.load
+  ! CHECK:   hlfir.assign {{.*}}
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}}
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_in_expression(
+subroutine test_in_expression(flag, x, y)
+  logical :: flag
+  integer :: x, y, z
+  ! Conditional in larger expression: (flag ? x : y) + 10
+  z = (flag ? x : y) + 10
+  ! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! CHECK: fir.if
+  ! CHECK: } else {
+  ! CHECK: }
+  ! CHECK: %[[COND_RESULT:.*]] = fir.load
+  ! CHECK: %[[C10:.*]] = arith.constant 10
+  ! CHECK: %[[SUM:.*]] = arith.addi %[[COND_RESULT]], %[[C10]]
+  ! CHECK: hlfir.assign %[[SUM]]
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_assumed_length_char(
+subroutine test_assumed_length_char(flag, str1, str2)
+  logical :: flag
+  character(len=*) :: str1, str2
+  character(len=100) :: result
+  result = (flag ? str1 : str2)
+  ! Deferred length path since len=* is not constant
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>> {bindc_name = ".cond.char"
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: }
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_different_kinds(
+subroutine test_different_kinds(flag)
+  logical :: flag
+  integer(kind=4) :: i4_1, i4_2, i4_result
+  integer(kind=8) :: i8_1, i8_2, i8_result
+
+  ! Both temps allocated at function start
+  ! CHECK-DAG: %{{.*}} = fir.alloca i64 {bindc_name = ".cond.scalar"}
+  ! CHECK-DAG: %{{.*}} = fir.alloca i32 {bindc_name = ".cond.scalar"}
+
+  i4_1 = 1
+  i4_2 = 2
+  i4_result = (flag ? i4_1 : i4_2)
+
+  i8_1 = 3
+  i8_2 = 4
+  i8_result = (flag ? i8_1 : i8_2)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_array_section(
+subroutine test_array_section(flag)
+  logical :: flag
+  integer :: arr1(20), arr2(20), result(10)
+  result = (flag ? arr1(1:10) : arr2(11:20))
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".cond.array"
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: }
+end subroutine

>From 7df7b264b8b05cacdb4dc41c31df3c16df9eadc7 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Fri, 20 Mar 2026 14:48:05 -0500
Subject: [PATCH 2/9] [flang] Update conditional expressions to tree
 representation (lowering portion)

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp      | 103 ++++++++++----------
 flang/test/Lower/HLFIR/conditional-expr.f90 |  13 +--
 2 files changed, 56 insertions(+), 60 deletions(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 8422c2a039efd..584e2bd17f154 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1827,40 +1827,39 @@ class HlfirBuilder {
     llvm_unreachable("unknown descriptor inquiry");
   }
 
-  /// Build nested if-then-else chain for conditional expressions with lazy
-  /// evaluation. The assignValue callback generates and assigns each value to
-  /// avoid evaluating non-taken branches.
-  template <typename T>
-  void buildConditionalIfChain(
-      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
-      const std::function<void(int valueIndex)> &assignValue) {
+  /// Build nested if-then-else chain by walking the right-skewed
+  /// ConditionalExpr tree. The assignValue callback generates and assigns
+  /// each value to avoid evaluating non-taken branches.
+  template <typename T, typename Callback>
+  void
+  buildConditionalIfChain(const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+                          const Callback &assignValue) {
     const mlir::Location loc = getLoc();
     fir::FirOpBuilder &builder = getBuilder();
-    std::function<void(int)> buildIfChain = [&](int i) {
-      if (i >= static_cast<int>(condExpr.conditions().size())) {
-        // All conditions false: assign final else value.
-        getStmtCtx().pushScope();
-        assignValue(static_cast<int>(condExpr.values().size()) - 1);
-        getStmtCtx().finalizeAndPop();
-      } else {
-        getStmtCtx().pushScope();
-        const hlfir::EntityWithAttributes condEntity =
-            gen(condExpr.conditions()[i]);
-        mlir::Value condition =
-            hlfir::loadTrivialScalar(loc, builder, condEntity);
-        condition = builder.createConvert(loc, builder.getI1Type(), condition);
-        builder.genIfOp(loc, {}, condition, /*withElseRegion=*/true)
-            .genThen([&]() {
-              getStmtCtx().pushScope();
-              assignValue(i);
-              getStmtCtx().finalizeAndPop();
-            })
-            .genElse([&]() { buildIfChain(i + 1); })
-            .end();
-        getStmtCtx().finalizeAndPop();
-      }
-    };
-    buildIfChain(0);
+    getStmtCtx().pushScope();
+    const hlfir::EntityWithAttributes condEntity = gen(condExpr.condition());
+    mlir::Value condition = hlfir::loadTrivialScalar(loc, builder, condEntity);
+    condition = builder.createConvert(loc, builder.getI1Type(), condition);
+    builder.genIfOp(loc, {}, condition, /*withElseRegion=*/true)
+        .genThen([&]() {
+          getStmtCtx().pushScope();
+          assignValue(condExpr.thenValue());
+          getStmtCtx().finalizeAndPop();
+        })
+        .genElse([&]() {
+          // Recurse for nested ConditionalExpr; else assign terminal value.
+          if (const auto *nested =
+                  std::get_if<Fortran::evaluate::ConditionalExpr<T>>(
+                      &condExpr.elseValue().u)) {
+            buildConditionalIfChain(*nested, assignValue);
+          } else {
+            getStmtCtx().pushScope();
+            assignValue(condExpr.elseValue());
+            getStmtCtx().finalizeAndPop();
+          }
+        })
+        .end();
+    getStmtCtx().finalizeAndPop();
   }
 
   /// Generate scalar conditional with lazy evaluation using assignment.
@@ -1879,15 +1878,16 @@ class HlfirBuilder {
         builder, loc, tempStorage, ".cond.result",
         /*shape=*/mlir::Value{}, /*typeParams=*/typeParams);
     const hlfir::Entity temp{tempDecl};
-    buildConditionalIfChain(condExpr, [&](int valueIndex) {
-      hlfir::Entity entity = gen(condExpr.values()[valueIndex]);
-      auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
-      hlfir::Entity value{fir::getBase(exv)};
-      if (cleanup) {
-        getStmtCtx().attachCleanup(*cleanup);
-      }
-      hlfir::AssignOp::create(builder, loc, value, temp);
-    });
+    buildConditionalIfChain(
+        condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
+          hlfir::Entity entity = gen(expr);
+          auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
+          hlfir::Entity value{fir::getBase(exv)};
+          if (cleanup) {
+            getStmtCtx().attachCleanup(*cleanup);
+          }
+          hlfir::AssignOp::create(builder, loc, value, temp);
+        });
     return temp;
   }
 
@@ -1912,13 +1912,14 @@ class HlfirBuilder {
         hlfir::DeclareOp::create(builder, loc, tempStorage, ".cond.result");
     const hlfir::Entity temp{tempDecl};
     // Lazy evaluation: only the selected branch is evaluated and assigned.
-    buildConditionalIfChain(condExpr, [&](int valueIndex) {
-      const hlfir::Entity entity = gen(condExpr.values()[valueIndex]);
-      hlfir::AssignOp::create(builder, loc, entity, temp,
-                              /*isWholeAllocatableAssignment=*/true,
-                              /*keepLhsLengthIfRealloc=*/false,
-                              /*temporary_lhs=*/true);
-    });
+    buildConditionalIfChain(
+        condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
+          const hlfir::Entity entity = gen(expr);
+          hlfir::AssignOp::create(builder, loc, entity, temp,
+                                  /*isWholeAllocatableAssignment=*/true,
+                                  /*keepLhsLengthIfRealloc=*/false,
+                                  /*temporary_lhs=*/true);
+        });
     return temp;
   }
 
@@ -1977,12 +1978,6 @@ class HlfirBuilder {
   template <typename T>
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
-    assert(!condExpr.conditions().empty() &&
-           "conditional expression must have conditions");
-    assert(!condExpr.values().empty() &&
-           "conditional expression must have values");
-    assert(condExpr.values().size() == condExpr.conditions().size() + 1 &&
-           "values must have exactly one more element than conditions");
     const int rank = condExpr.Rank();
 
     // Arrays: handle early to avoid unnecessary type checks.
diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index 6da5f11ddc011..43df21cf3768b 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -1,5 +1,5 @@
 ! Test lowering of conditional expressions (Fortran 2023)
-! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -o - %s 2>&1 | FileCheck %s
 
 ! CHECK-LABEL: func.func @_QPtest_scalar_integer(
 ! CHECK-SAME:    %[[FLAG:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "flag"},
@@ -98,13 +98,14 @@ subroutine test_char_constant_len(flag)
   str1 = "HELLO"
   str2 = "WORLD"
   result = (flag ? str1 : str2)
-  ! CHECK: %[[TEMP:.*]] = fir.alloca !fir.char<1,5> {bindc_name = ".cond.scalar"
-  ! CHECK: %{{.*}} = arith.constant 5 : index
-  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] typeparams %{{.*}} {uniq_name = ".cond.result"}
+  ! Per F2023, the length type parameter is that of the chosen branch, so
+  ! branches may have different lengths. The result length is therefore
+  ! always only known at runtime: use the allocatable (deferred) path.
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>> {bindc_name = ".cond.char"
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
   ! CHECK: }
 end subroutine
 

>From fb687545a2a5efd0b66e9b7353505d4b48774da2 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Mon, 23 Mar 2026 12:11:14 -0500
Subject: [PATCH 3/9] [flang] Fix ConditionalExpr lowering test for static
 array extents

---
 flang/test/Lower/HLFIR/conditional-expr.f90 | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index 43df21cf3768b..79e35da15bf1a 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -137,8 +137,8 @@ subroutine test_array(flag)
   arr1 = 1
   arr2 = 2
   result = (flag ? arr1 : arr2)
-  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".cond.array"
-  ! CHECK: %[[UNALLOC:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<{{.*}}xi32>>> {bindc_name = ".cond.array"
+  ! CHECK: %[[UNALLOC:.*]] = fir.zero_bits !fir.heap<!fir.array<{{.*}}xi32>>
   ! CHECK: %[[SHAPE:.*]] = fir.shape
   ! CHECK: %[[BOX:.*]] = fir.embox %[[UNALLOC]](%[[SHAPE]])
   ! CHECK: fir.store %[[BOX]] to %[[BOX_ALLOC]]
@@ -249,7 +249,7 @@ subroutine test_array_section(flag)
   logical :: flag
   integer :: arr1(20), arr2(20), result(10)
   result = (flag ? arr1(1:10) : arr2(11:20))
-  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".cond.array"
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<{{.*}}xi32>>> {bindc_name = ".cond.array"
   ! CHECK: fir.if
   ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
   ! CHECK: } else {

>From b6b2fa82274309852e4467939b3f0a470a8c3c24 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Tue, 24 Mar 2026 13:43:23 -0500
Subject: [PATCH 4/9] [flang] Conditional expressions (lowering): used braced
 initialization and update test expectation

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp      | 76 ++++++++++-----------
 flang/test/Lower/HLFIR/conditional-expr.f90 | 11 ++-
 2 files changed, 43 insertions(+), 44 deletions(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 584e2bd17f154..6c51bc26abb1e 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1834,11 +1834,11 @@ class HlfirBuilder {
   void
   buildConditionalIfChain(const Fortran::evaluate::ConditionalExpr<T> &condExpr,
                           const Callback &assignValue) {
-    const mlir::Location loc = getLoc();
-    fir::FirOpBuilder &builder = getBuilder();
+    const mlir::Location loc{getLoc()};
+    fir::FirOpBuilder &builder{getBuilder()};
     getStmtCtx().pushScope();
-    const hlfir::EntityWithAttributes condEntity = gen(condExpr.condition());
-    mlir::Value condition = hlfir::loadTrivialScalar(loc, builder, condEntity);
+    const hlfir::EntityWithAttributes condEntity{gen(condExpr.condition())};
+    mlir::Value condition{hlfir::loadTrivialScalar(loc, builder, condEntity)};
     condition = builder.createConvert(loc, builder.getI1Type(), condition);
     builder.genIfOp(loc, {}, condition, /*withElseRegion=*/true)
         .genThen([&]() {
@@ -1869,18 +1869,18 @@ class HlfirBuilder {
       const Fortran::evaluate::ConditionalExpr<T> &condExpr,
       mlir::Type elementType,
       const llvm::SmallVector<mlir::Value, 1> &typeParams) {
-    const mlir::Location loc = getLoc();
-    fir::FirOpBuilder &builder = getBuilder();
-    const mlir::Value tempStorage = builder.createTemporary(
+    const mlir::Location loc{getLoc()};
+    fir::FirOpBuilder &builder{getBuilder()};
+    const mlir::Value tempStorage{builder.createTemporary(
         loc, elementType, ".cond.scalar",
-        /*shape=*/mlir::ValueRange{}, /*typeParams=*/typeParams);
-    const hlfir::DeclareOp tempDecl = hlfir::DeclareOp::create(
+        /*shape=*/mlir::ValueRange{}, /*typeParams=*/typeParams)};
+    const hlfir::DeclareOp tempDecl{hlfir::DeclareOp::create(
         builder, loc, tempStorage, ".cond.result",
-        /*shape=*/mlir::Value{}, /*typeParams=*/typeParams);
+        /*shape=*/mlir::Value{}, /*typeParams=*/typeParams)};
     const hlfir::Entity temp{tempDecl};
     buildConditionalIfChain(
         condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
-          hlfir::Entity entity = gen(expr);
+          hlfir::Entity entity{gen(expr)};
           auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
           hlfir::Entity value{fir::getBase(exv)};
           if (cleanup) {
@@ -1899,22 +1899,22 @@ class HlfirBuilder {
   hlfir::Entity genAllocatableConditionalLazy(
       const Fortran::evaluate::ConditionalExpr<T> &condExpr,
       mlir::Type resultType, llvm::StringRef debugName) {
-    const mlir::Location loc = getLoc();
-    fir::FirOpBuilder &builder = getBuilder();
-    const mlir::Type heapType = fir::HeapType::get(resultType);
-    const mlir::Type boxHeapType = fir::BoxType::get(heapType);
-    const mlir::Value tempStorage =
-        builder.createTemporary(loc, boxHeapType, debugName);
-    const mlir::Value unallocBox = fir::factory::createUnallocatedBox(
-        builder, loc, boxHeapType, /*nonDeferredParams=*/{});
+    const mlir::Location loc{getLoc()};
+    fir::FirOpBuilder &builder{getBuilder()};
+    const mlir::Type heapType{fir::HeapType::get(resultType)};
+    const mlir::Type boxHeapType{fir::BoxType::get(heapType)};
+    const mlir::Value tempStorage{
+        builder.createTemporary(loc, boxHeapType, debugName)};
+    const mlir::Value unallocBox{fir::factory::createUnallocatedBox(
+        builder, loc, boxHeapType, /*nonDeferredParams=*/{})};
     builder.createStoreWithConvert(loc, unallocBox, tempStorage);
-    const hlfir::DeclareOp tempDecl =
-        hlfir::DeclareOp::create(builder, loc, tempStorage, ".cond.result");
+    const hlfir::DeclareOp tempDecl{
+        hlfir::DeclareOp::create(builder, loc, tempStorage, ".cond.result")};
     const hlfir::Entity temp{tempDecl};
     // Lazy evaluation: only the selected branch is evaluated and assigned.
     buildConditionalIfChain(
         condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
-          const hlfir::Entity entity = gen(expr);
+          const hlfir::Entity entity{gen(expr)};
           hlfir::AssignOp::create(builder, loc, entity, temp,
                                   /*isWholeAllocatableAssignment=*/true,
                                   /*keepLhsLengthIfRealloc=*/false,
@@ -1939,8 +1939,8 @@ class HlfirBuilder {
   template <typename T>
   hlfir::Entity genArrayConditionalLazy(
       const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
-    mlir::Type condResultType = Fortran::lower::translateSomeExprToFIRType(
-        converter, toEvExpr(condExpr));
+    mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr))};
     if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
       condResultType = fir::unwrapRefType(boxTy.getEleTy());
     }
@@ -1952,16 +1952,16 @@ class HlfirBuilder {
   template <typename T>
   std::optional<hlfir::EntityWithAttributes> genCharacterConditional(
       const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
-    const mlir::Location loc = getLoc();
-    fir::FirOpBuilder &builder = getBuilder();
-    const mlir::Type resultType = Fortran::lower::translateSomeExprToFIRType(
-        converter, toEvExpr(condExpr));
-    const mlir::Type elementType = hlfir::getFortranElementType(resultType);
+    const mlir::Location loc{getLoc()};
+    fir::FirOpBuilder &builder{getBuilder()};
+    const mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr))};
+    const mlir::Type elementType{hlfir::getFortranElementType(resultType)};
     if (auto charType = mlir::dyn_cast<fir::CharacterType>(elementType)) {
       if (charType.hasConstantLen()) {
         llvm::SmallVector<mlir::Value, 1> typeParams;
-        const mlir::Value len = builder.createIntegerConstant(
-            loc, builder.getCharacterLengthType(), charType.getLen());
+        const mlir::Value len{builder.createIntegerConstant(
+            loc, builder.getCharacterLengthType(), charType.getLen())};
         typeParams.push_back(len);
         return hlfir::EntityWithAttributes{
             genScalarConditionalLazy(condExpr, elementType, typeParams)};
@@ -1978,7 +1978,7 @@ class HlfirBuilder {
   template <typename T>
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
-    const int rank = condExpr.Rank();
+    const int rank{condExpr.Rank()};
 
     // Arrays: handle early to avoid unnecessary type checks.
     // Per F2023 10.1.4(7), the shape is determined by the chosen branch.
@@ -1993,19 +1993,19 @@ class HlfirBuilder {
     }
     // Derived type scalars require special handling for type parameters.
     if constexpr (T::category == Fortran::common::TypeCategory::Derived) {
-      const mlir::Type resultType = Fortran::lower::translateSomeExprToFIRType(
-          converter, toEvExpr(condExpr));
-      const mlir::Type elementType = hlfir::getFortranElementType(resultType);
+      const mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
+          converter, toEvExpr(condExpr))};
+      const mlir::Type elementType{hlfir::getFortranElementType(resultType)};
       return hlfir::EntityWithAttributes{
           genScalarConditionalLazy(condExpr, elementType, {})};
     }
     // Other scalar types (INTEGER, REAL, COMPLEX, LOGICAL, UNSIGNED).
-    mlir::Type condResultType = Fortran::lower::translateSomeExprToFIRType(
-        converter, toEvExpr(condExpr));
+    mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr))};
     if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
       condResultType = fir::unwrapRefType(boxTy.getEleTy());
     }
-    const mlir::Type resultType = hlfir::getFortranElementType(condResultType);
+    const mlir::Type resultType{hlfir::getFortranElementType(condResultType)};
     return hlfir::EntityWithAttributes{
         genScalarConditionalLazy(condExpr, resultType, {})};
   }
diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index 79e35da15bf1a..a726386f5b9c2 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -98,14 +98,13 @@ subroutine test_char_constant_len(flag)
   str1 = "HELLO"
   str2 = "WORLD"
   result = (flag ? str1 : str2)
-  ! Per F2023, the length type parameter is that of the chosen branch, so
-  ! branches may have different lengths. The result length is therefore
-  ! always only known at runtime: use the allocatable (deferred) path.
-  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>> {bindc_name = ".cond.char"
+  ! Constant length: use scalar temp path.
+  ! CHECK: %[[TEMP:.*]] = fir.alloca !fir.char<1,5> {bindc_name = ".cond.scalar"
+  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] typeparams {{.*}} {uniq_name = ".cond.result"}
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0
   ! CHECK: }
 end subroutine
 

>From dc61561883bb2084b8ca28406cab5825988b5524 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Tue, 31 Mar 2026 14:27:23 -0500
Subject: [PATCH 5/9] [flang] Add lowering LIT test for non-contiguous array
 sections in conditional expressions

---
 flang/test/Lower/HLFIR/conditional-expr.f90 | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index a726386f5b9c2..77d72ff1acc49 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -255,3 +255,17 @@ subroutine test_array_section(flag)
   ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
   ! CHECK: }
 end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_noncontiguous_section(
+subroutine test_noncontiguous_section(flag)
+  logical :: flag
+  integer :: arr1(20), arr2(20), result(5)
+  ! Non-contiguous stride-2 sections: result must be contiguous.
+  result = (flag ? arr1(1:10:2) : arr2(2:10:2))
+  ! CHECK: %[[BOX_ALLOC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<{{.*}}xi32>>> {bindc_name = ".cond.array"
+  ! CHECK: fir.if
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: } else {
+  ! CHECK:   hlfir.assign {{.*}} to {{.*}} realloc temporary_lhs
+  ! CHECK: }
+end subroutine

>From 489bf136464dd0d4c3f3bfc811609eeb7322aad8 Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Wed, 1 Apr 2026 13:02:58 -0500
Subject: [PATCH 6/9] [flang] Fix memory leak in ConditionalExpr lowering for
 allocatable temporaries

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 6c51bc26abb1e..7f2932f2664a1 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1920,6 +1920,13 @@ class HlfirBuilder {
                                   /*keepLhsLengthIfRealloc=*/false,
                                   /*temporary_lhs=*/true);
         });
+    fir::FirOpBuilder *const bldr{&builder};
+    getStmtCtx().attachCleanup([=]() {
+      fir::factory::genFreememIfAllocated(
+          *bldr, loc,
+          fir::MutableBoxValue{tempStorage, /*lenParams=*/{},
+                               fir::MutableProperties{}});
+    });
     return temp;
   }
 

>From 2ee433aa40a308889f3c932f30d765d502bfbf0c Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Mon, 6 Apr 2026 15:51:50 -0500
Subject: [PATCH 7/9] [flang] Fixes to conditional expressions lowering

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp      | 90 ++++++---------------
 flang/test/Lower/HLFIR/conditional-expr.f90 | 50 ++++++------
 2 files changed, 51 insertions(+), 89 deletions(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 7f2932f2664a1..d50fcb5932c08 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1847,16 +1847,9 @@ class HlfirBuilder {
           getStmtCtx().finalizeAndPop();
         })
         .genElse([&]() {
-          // Recurse for nested ConditionalExpr; else assign terminal value.
-          if (const auto *nested =
-                  std::get_if<Fortran::evaluate::ConditionalExpr<T>>(
-                      &condExpr.elseValue().u)) {
-            buildConditionalIfChain(*nested, assignValue);
-          } else {
-            getStmtCtx().pushScope();
-            assignValue(condExpr.elseValue());
-            getStmtCtx().finalizeAndPop();
-          }
+          getStmtCtx().pushScope();
+          assignValue(condExpr.elseValue());
+          getStmtCtx().finalizeAndPop();
         })
         .end();
     getStmtCtx().finalizeAndPop();
@@ -1865,10 +1858,10 @@ class HlfirBuilder {
   /// Generate scalar conditional with lazy evaluation using assignment.
   /// Creates a temporary and assigns the selected branch value to it.
   template <typename T>
-  hlfir::Entity genScalarConditionalLazy(
-      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
-      mlir::Type elementType,
-      const llvm::SmallVector<mlir::Value, 1> &typeParams) {
+  hlfir::Entity
+  genScalarConditional(const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+                       mlir::Type elementType,
+                       const llvm::SmallVector<mlir::Value, 1> &typeParams) {
     const mlir::Location loc{getLoc()};
     fir::FirOpBuilder &builder{getBuilder()};
     const mlir::Value tempStorage{builder.createTemporary(
@@ -1881,12 +1874,8 @@ class HlfirBuilder {
     buildConditionalIfChain(
         condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
           hlfir::Entity entity{gen(expr)};
-          auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
-          hlfir::Entity value{fir::getBase(exv)};
-          if (cleanup) {
-            getStmtCtx().attachCleanup(*cleanup);
-          }
-          hlfir::AssignOp::create(builder, loc, value, temp);
+          entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
+          hlfir::AssignOp::create(builder, loc, entity, temp);
         });
     return temp;
   }
@@ -1896,7 +1885,7 @@ class HlfirBuilder {
   /// set the value from the chosen branch (allocation/reallocation handled by
   /// runtime).
   template <typename T>
-  hlfir::Entity genAllocatableConditionalLazy(
+  hlfir::Entity genAllocatableConditional(
       const Fortran::evaluate::ConditionalExpr<T> &condExpr,
       mlir::Type resultType, llvm::StringRef debugName) {
     const mlir::Location loc{getLoc()};
@@ -1930,31 +1919,6 @@ class HlfirBuilder {
     return temp;
   }
 
-  /// Generate scalar CHARACTER conditional with deferred-length using lazy
-  /// evaluation. Only the chosen branch is evaluated; the result gets that
-  /// branch's length.
-  template <typename T>
-  hlfir::Entity genScalarDeferredCharConditionalLazy(
-      const Fortran::evaluate::ConditionalExpr<T> &condExpr,
-      mlir::Type elementType) {
-    return genAllocatableConditionalLazy(condExpr, elementType, ".cond.char");
-  }
-
-  /// Generate array conditional expression with lazy evaluation using
-  /// assignment. Per F2023 10.1.4(7), the shape is determined by the chosen
-  /// branch.
-  template <typename T>
-  hlfir::Entity genArrayConditionalLazy(
-      const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
-    mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
-        converter, toEvExpr(condExpr))};
-    if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
-      condResultType = fir::unwrapRefType(boxTy.getEleTy());
-    }
-    return genAllocatableConditionalLazy(condExpr, condResultType,
-                                         ".cond.array");
-  }
-
   /// Generate scalar CHARACTER conditional with proper length handling.
   template <typename T>
   std::optional<hlfir::EntityWithAttributes> genCharacterConditional(
@@ -1971,12 +1935,12 @@ class HlfirBuilder {
             loc, builder.getCharacterLengthType(), charType.getLen())};
         typeParams.push_back(len);
         return hlfir::EntityWithAttributes{
-            genScalarConditionalLazy(condExpr, elementType, typeParams)};
+            genScalarConditional(condExpr, elementType, typeParams)};
       }
       // Non-constant/varying length: use allocatable conditional to get length
       // from selected branch.
       return hlfir::EntityWithAttributes{
-          genScalarDeferredCharConditionalLazy(condExpr, elementType)};
+          genAllocatableConditional(condExpr, elementType, ".cond.char")};
     }
     return std::nullopt;
   }
@@ -1990,7 +1954,12 @@ class HlfirBuilder {
     // Arrays: handle early to avoid unnecessary type checks.
     // Per F2023 10.1.4(7), the shape is determined by the chosen branch.
     if (rank != 0) {
-      return hlfir::EntityWithAttributes{genArrayConditionalLazy(condExpr)};
+      mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
+          converter, toEvExpr(condExpr))};
+      if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType))
+        condResultType = fir::unwrapRefType(boxTy.getEleTy());
+      return hlfir::EntityWithAttributes{
+          genAllocatableConditional(condExpr, condResultType, ".cond.array")};
     }
     // CHARACTER scalars require special handling for type parameters.
     if constexpr (T::category == Fortran::common::TypeCategory::Character) {
@@ -1998,23 +1967,16 @@ class HlfirBuilder {
         return *result;
       }
     }
-    // Derived type scalars require special handling for type parameters.
-    if constexpr (T::category == Fortran::common::TypeCategory::Derived) {
-      const mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
-          converter, toEvExpr(condExpr))};
-      const mlir::Type elementType{hlfir::getFortranElementType(resultType)};
-      return hlfir::EntityWithAttributes{
-          genScalarConditionalLazy(condExpr, elementType, {})};
-    }
-    // Other scalar types (INTEGER, REAL, COMPLEX, LOGICAL, UNSIGNED).
-    mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
+    // Scalar types (INTEGER, REAL, COMPLEX, LOGICAL, UNSIGNED, Derived).
+    mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
         converter, toEvExpr(condExpr))};
-    if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType)) {
-      condResultType = fir::unwrapRefType(boxTy.getEleTy());
+    if constexpr (T::category != Fortran::common::TypeCategory::Derived) {
+      if (auto boxTy = mlir::dyn_cast<fir::BoxType>(resultType)) {
+        resultType = fir::unwrapRefType(boxTy.getEleTy());
+      }
     }
-    const mlir::Type resultType{hlfir::getFortranElementType(condResultType)};
-    return hlfir::EntityWithAttributes{
-        genScalarConditionalLazy(condExpr, resultType, {})};
+    return hlfir::EntityWithAttributes{genScalarConditional(
+        condExpr, hlfir::getFortranElementType(resultType), {})};
   }
 
   hlfir::EntityWithAttributes
diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index 77d72ff1acc49..d7f2334d409e5 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -18,11 +18,9 @@ subroutine test_scalar_integer(flag, x, y)
   ! CHECK: %[[FLAG_LOAD:.*]] = fir.load %[[FLAG_DECL]]#0
   ! CHECK: %[[FLAG_CONV:.*]] = fir.convert %[[FLAG_LOAD]] : (!fir.logical<4>) -> i1
   ! CHECK: fir.if %[[FLAG_CONV]] {
-  ! CHECK:   %[[X_LOAD:.*]] = fir.load %[[X_DECL]]#0
-  ! CHECK:   hlfir.assign %[[X_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
+  ! CHECK:   hlfir.assign %[[X_DECL]]#0 to %[[TEMP_DECL]]#0 : !fir.ref<i32>, !fir.ref<i32>
   ! CHECK: } else {
-  ! CHECK:   %[[Y_LOAD:.*]] = fir.load %[[Y_DECL]]#0
-  ! CHECK:   hlfir.assign %[[Y_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
+  ! CHECK:   hlfir.assign %[[Y_DECL]]#0 to %[[TEMP_DECL]]#0 : !fir.ref<i32>, !fir.ref<i32>
   ! CHECK: }
   ! CHECK: %[[LOAD:.*]] = fir.load %[[TEMP_DECL]]#0
   ! CHECK: hlfir.assign %[[LOAD]] to %{{.*}} : i32, !fir.ref<i32>
@@ -36,9 +34,9 @@ subroutine test_scalar_real(flag, x, y)
   ! CHECK: %[[TEMP:.*]] = fir.alloca f32 {bindc_name = ".cond.scalar"
   ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<f32>, !fir.ref<f32>
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<f32>, !fir.ref<f32>
   ! CHECK: }
 end subroutine
 
@@ -50,9 +48,9 @@ subroutine test_scalar_complex(flag, x, y)
   ! CHECK: %[[TEMP:.*]] = fir.alloca complex<f32> {bindc_name = ".cond.scalar"
   ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>>
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>>
   ! CHECK: }
 end subroutine
 
@@ -71,23 +69,25 @@ subroutine test_multi_branch(x)
   integer :: x, result
   ! Multi-branch: x > 10 ? 100 : x > 5 ? 50 : 0
   result = (x > 10 ? 100 : x > 5 ? 50 : 0)
-  ! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = ".cond.scalar"
-  ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
-  ! First condition: x > 10
-  ! CHECK: %[[CMP1:.*]] = arith.cmpi sgt
-  ! CHECK: fir.if %[[CMP1]] {
-  ! CHECK:   %[[C100:.*]] = arith.constant 100
-  ! CHECK:   hlfir.assign %[[C100]] to %[[TEMP_DECL]]#0
+  ! Both outer and inner temps are hoisted to function entry.
+  ! CHECK-DAG: fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! CHECK-DAG: fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! Outer temp declaration and first condition: x > 10
+  ! CHECK: hlfir.declare {{.*}} {uniq_name = ".cond.result"}
+  ! CHECK: arith.cmpi sgt
+  ! CHECK: fir.if {{.*}} {
+  ! CHECK:   hlfir.assign {{.*}}
   ! CHECK: } else {
-  ! Second condition: x > 5
-  ! CHECK:   %[[CMP2:.*]] = arith.cmpi sgt
-  ! CHECK:   fir.if %[[CMP2]] {
-  ! CHECK:     %[[C50:.*]] = arith.constant 50
-  ! CHECK:     hlfir.assign %[[C50]] to %[[TEMP_DECL]]#0
+  ! Inner temp for the nested conditional: x > 5 ? 50 : 0
+  ! CHECK:   hlfir.declare {{.*}} {uniq_name = ".cond.result"}
+  ! CHECK:   arith.cmpi sgt
+  ! CHECK:   fir.if {{.*}} {
+  ! CHECK:     hlfir.assign {{.*}}
   ! CHECK:   } else {
-  ! CHECK:     %[[C0:.*]] = arith.constant 0
-  ! CHECK:     hlfir.assign %[[C0]] to %[[TEMP_DECL]]#0
+  ! CHECK:     hlfir.assign {{.*}}
   ! CHECK:   }
+  ! CHECK:   fir.load
+  ! CHECK:   hlfir.assign {{.*}}
   ! CHECK: }
 end subroutine
 
@@ -174,8 +174,9 @@ subroutine test_nested_conditionals(flag1, flag2, x, y, z)
   integer :: x, y, z, result
   ! Nested: flag1 ? (flag2 ? x : y) : z
   result = (flag1 ? (flag2 ? x : y) : z)
-  ! Outer temp allocation
-  ! CHECK: fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! Both outer and inner temps are hoisted to function entry.
+  ! CHECK-DAG: fir.alloca i32 {bindc_name = ".cond.scalar"
+  ! CHECK-DAG: fir.alloca i32 {bindc_name = ".cond.scalar"
   ! Outer temp declaration and conditional
   ! CHECK: hlfir.declare {{.*}} {uniq_name = ".cond.result"}
   ! CHECK: fir.if {{%.*}} {
@@ -186,7 +187,6 @@ subroutine test_nested_conditionals(flag1, flag2, x, y, z)
   ! CHECK:   } else {
   ! CHECK:     hlfir.assign {{.*}}
   ! CHECK:   }
-  ! CHECK:   fir.load
   ! CHECK:   hlfir.assign {{.*}}
   ! CHECK: } else {
   ! CHECK:   hlfir.assign {{.*}}

>From 5b656e4b79ac06cb27e7032f08fb9b85fb13646e Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Thu, 9 Apr 2026 08:45:29 -0500
Subject: [PATCH 8/9] [flang] Conditional expressions lowering and test updates

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp      | 27 +++++++++------------
 flang/test/Lower/HLFIR/conditional-expr.f90 | 14 ++++++-----
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index d50fcb5932c08..003167f1c22f8 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1874,7 +1874,7 @@ class HlfirBuilder {
     buildConditionalIfChain(
         condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
           hlfir::Entity entity{gen(expr)};
-          entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
+          entity = hlfir::loadTrivialScalar(loc, builder, entity);
           hlfir::AssignOp::create(builder, loc, entity, temp);
         });
     return temp;
@@ -1950,31 +1950,28 @@ class HlfirBuilder {
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::ConditionalExpr<T> &condExpr) {
     const int rank{condExpr.Rank()};
-
+    mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
+        converter, toEvExpr(condExpr))};
+    if (fir::isPolymorphicType(resultType))
+      TODO(getLoc(), "polymorphic conditional expression");
+    if (fir::isRecordWithTypeParameters(
+            hlfir::getFortranElementType(resultType)))
+      TODO(getLoc(), "conditional expression with length-parameterized "
+                     "derived type");
     // Arrays: handle early to avoid unnecessary type checks.
     // Per F2023 10.1.4(7), the shape is determined by the chosen branch.
     if (rank != 0) {
-      mlir::Type condResultType{Fortran::lower::translateSomeExprToFIRType(
-          converter, toEvExpr(condExpr))};
-      if (auto boxTy = mlir::dyn_cast<fir::BoxType>(condResultType))
-        condResultType = fir::unwrapRefType(boxTy.getEleTy());
+      const mlir::Type condResultType{
+          hlfir::getFortranElementOrSequenceType(resultType)};
       return hlfir::EntityWithAttributes{
           genAllocatableConditional(condExpr, condResultType, ".cond.array")};
     }
     // CHARACTER scalars require special handling for type parameters.
     if constexpr (T::category == Fortran::common::TypeCategory::Character) {
-      if (auto result = genCharacterConditional(condExpr)) {
+      if (auto result = genCharacterConditional(condExpr))
         return *result;
-      }
     }
     // Scalar types (INTEGER, REAL, COMPLEX, LOGICAL, UNSIGNED, Derived).
-    mlir::Type resultType{Fortran::lower::translateSomeExprToFIRType(
-        converter, toEvExpr(condExpr))};
-    if constexpr (T::category != Fortran::common::TypeCategory::Derived) {
-      if (auto boxTy = mlir::dyn_cast<fir::BoxType>(resultType)) {
-        resultType = fir::unwrapRefType(boxTy.getEleTy());
-      }
-    }
     return hlfir::EntityWithAttributes{genScalarConditional(
         condExpr, hlfir::getFortranElementType(resultType), {})};
   }
diff --git a/flang/test/Lower/HLFIR/conditional-expr.f90 b/flang/test/Lower/HLFIR/conditional-expr.f90
index d7f2334d409e5..d0d7f41a92124 100644
--- a/flang/test/Lower/HLFIR/conditional-expr.f90
+++ b/flang/test/Lower/HLFIR/conditional-expr.f90
@@ -18,9 +18,11 @@ subroutine test_scalar_integer(flag, x, y)
   ! CHECK: %[[FLAG_LOAD:.*]] = fir.load %[[FLAG_DECL]]#0
   ! CHECK: %[[FLAG_CONV:.*]] = fir.convert %[[FLAG_LOAD]] : (!fir.logical<4>) -> i1
   ! CHECK: fir.if %[[FLAG_CONV]] {
-  ! CHECK:   hlfir.assign %[[X_DECL]]#0 to %[[TEMP_DECL]]#0 : !fir.ref<i32>, !fir.ref<i32>
+  ! CHECK:   %[[X_LOAD:.*]] = fir.load %[[X_DECL]]#0 : !fir.ref<i32>
+  ! CHECK:   hlfir.assign %[[X_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign %[[Y_DECL]]#0 to %[[TEMP_DECL]]#0 : !fir.ref<i32>, !fir.ref<i32>
+  ! CHECK:   %[[Y_LOAD:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref<i32>
+  ! CHECK:   hlfir.assign %[[Y_LOAD]] to %[[TEMP_DECL]]#0 : i32, !fir.ref<i32>
   ! CHECK: }
   ! CHECK: %[[LOAD:.*]] = fir.load %[[TEMP_DECL]]#0
   ! CHECK: hlfir.assign %[[LOAD]] to %{{.*}} : i32, !fir.ref<i32>
@@ -34,9 +36,9 @@ subroutine test_scalar_real(flag, x, y)
   ! CHECK: %[[TEMP:.*]] = fir.alloca f32 {bindc_name = ".cond.scalar"
   ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<f32>, !fir.ref<f32>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<f32>, !fir.ref<f32>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : f32, !fir.ref<f32>
   ! CHECK: }
 end subroutine
 
@@ -48,9 +50,9 @@ subroutine test_scalar_complex(flag, x, y)
   ! CHECK: %[[TEMP:.*]] = fir.alloca complex<f32> {bindc_name = ".cond.scalar"
   ! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".cond.result"}
   ! CHECK: fir.if
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
   ! CHECK: } else {
-  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>>
+  ! CHECK:   hlfir.assign {{.*}} to %[[TEMP_DECL]]#0 : complex<f32>, !fir.ref<complex<f32>>
   ! CHECK: }
 end subroutine
 

>From ec30486bb5efcf8d7cbf9be92ecf7a53d260fb0d Mon Sep 17 00:00:00 2001
From: Caroline Newcombe <caroline.newcombe at hpe.com>
Date: Thu, 9 Apr 2026 09:05:23 -0500
Subject: [PATCH 9/9] [flang] Remove conditional expressions HLFIR lowering
 TODO after rebase with main

---
 flang/lib/Lower/ConvertExprToHLFIR.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 003167f1c22f8..b6816ae91e44f 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1788,12 +1788,6 @@ class HlfirBuilder {
     TODO(getLoc(), "lowering type parameter inquiry to HLFIR");
   }
 
-  template <typename T>
-  hlfir::EntityWithAttributes
-  gen(const Fortran::evaluate::ConditionalExpr<T> &) {
-    TODO(getLoc(), "lowering conditional expression to HLFIR");
-  }
-
   hlfir::EntityWithAttributes
   gen(const Fortran::evaluate::DescriptorInquiry &desc) {
     mlir::Location loc = getLoc();



More information about the flang-commits mailing list