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

Caroline Newcombe via flang-commits flang-commits at lists.llvm.org
Tue Mar 24 11:47:28 PDT 2026


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

>From b1d02948dcd4138b120cb4bc167785d8842b1246 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/4] [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 0c015bc9a2f1b..a494c26139988 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1821,6 +1821,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 c476040009db0dd6dd0809bd98eae6e4a3c8f753 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/4] [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 a494c26139988..8fbab2b88507b 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1821,40 +1821,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.
@@ -1873,15 +1872,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;
   }
 
@@ -1906,13 +1906,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;
   }
 
@@ -1971,12 +1972,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 ce15266ebeff73199189e0076d79408223b243b9 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/4] [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 98f82de5cc2590478147e6245864a3ed3430e17a 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/4] [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 8fbab2b88507b..8706ce4be90e2 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1828,11 +1828,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([&]() {
@@ -1863,18 +1863,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) {
@@ -1893,22 +1893,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,
@@ -1933,8 +1933,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());
     }
@@ -1946,16 +1946,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)};
@@ -1972,7 +1972,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.
@@ -1987,19 +1987,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
 



More information about the flang-commits mailing list