[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