[flang-commits] [flang] [flang] Implement conditional expressions parser/semantics (F2023) (PR #186489)
Caroline Newcombe via flang-commits
flang-commits at lists.llvm.org
Wed Apr 1 08:10:36 PDT 2026
================
@@ -0,0 +1,385 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Test semantic analysis of conditional expressions (Fortran 2023)
+
+! Valid cases with basic types
+subroutine valid_basic_types(flag)
+ logical :: flag
+ integer :: i1, i2, i3
+ real :: r1, r2, r3
+ complex :: c1, c2, c3
+ logical :: l1, l2, l3
+ character(len=5) :: ch1, ch2, ch3
+
+ ! INTEGER conditionals
+ i3 = (flag ? i1 : i2)
+
+ ! REAL conditionals
+ r3 = (flag ? r1 : r2)
+
+ ! COMPLEX conditionals
+ c3 = (flag ? c1 : c2)
+
+ ! LOGICAL conditionals
+ l3 = (flag ? l1 : l2)
+
+ ! CHARACTER conditionals
+ ch3 = (flag ? ch1 : ch2)
+end subroutine
+
+! Valid cases with same kind
+subroutine valid_same_kind(flag)
+ logical :: flag
+ integer(kind=4) :: i4a, i4b, i4c
+ integer(kind=8) :: i8a, i8b, i8c
+ real(kind=4) :: r4a, r4b, r4c
+ real(kind=8) :: r8a, r8b, r8c
+
+ ! Same kind - valid
+ i4c = (flag ? i4a : i4b)
+ i8c = (flag ? i8a : i8b)
+ r4c = (flag ? r4a : r4b)
+ r8c = (flag ? r8a : r8b)
+end subroutine
+
+! Valid cases with literals
+subroutine valid_literals(flag)
+ logical :: flag
+ integer :: i
+ real :: r
+ character(len=10) :: ch
+
+ i = (flag ? 10 : 20)
+ r = (flag ? 1.0 : 2.0)
+ ch = (flag ? "HELLO" : "WORLD")
+end subroutine
+
+! Valid cases with nested conditionals
+subroutine valid_nested(flag1, flag2, x, y, z, w)
+ logical :: flag1, flag2
+ integer :: x, y, z, w, result
+
+ ! Nested in value position
+ result = (flag1 ? (flag2 ? x : y) : z)
+
+ ! Nested in condition (condition is logical)
+ result = ((x > y ? flag1 : flag2) ? w : z)
+
+ ! Multi-branch
+ result = (x > 10 ? 100 : x > 5 ? 50 : 0)
+end subroutine
+
+! Valid cases with arrays
+subroutine valid_arrays(flag)
+ logical :: flag
+ integer :: arr1(10), arr2(10), arr3(10)
+ real :: mat1(3,3), mat2(3,3), mat3(3,3)
+
+ ! Whole array conditional
+ arr3 = (flag ? arr1 : arr2)
+
+ ! Multidimensional arrays
+ mat3 = (flag ? mat1 : mat2)
+
+ ! Array sections
+ arr3(1:5) = (flag ? arr1(1:5) : arr2(1:5))
+end subroutine
+
+! Valid cases with derived types
+subroutine valid_derived_types(flag)
+ type :: point
+ real :: x, y
+ end type
+
+ logical :: flag
+ type(point) :: p1, p2, p3
+
+ p3 = (flag ? p1 : p2)
+end subroutine
+
+! Valid cases with character lengths
+subroutine valid_character_lengths(flag)
+ logical :: flag
+ character(len=5) :: short1, short2, short3
+ character(len=10) :: medium
+ character(len=20) :: long
+
+ ! Same length
+ short3 = (flag ? short1 : short2)
+
+ ! Different lengths - padding/truncation applies
+ medium = (flag ? short1 : medium)
+ long = (flag ? short1 : "A LONGER STRING")
+end subroutine
+
+! Valid: deferred-length character scalars
+subroutine valid_deferred_length_character(flag)
+ logical :: flag
+ character(len=:), allocatable :: str1, str2, result
+
+ str1 = "SHORT"
+ str2 = "A MUCH LONGER STRING"
+ ! Result length is determined by selected branch
+ result = (flag ? str1 : str2)
+end subroutine
+
+! Valid: assumed-length character arguments
+subroutine valid_assumed_length_character(flag, str1, str2)
+ logical :: flag
+ character(len=*) :: str1, str2
+ character(len=100) :: result
+
+ result = (flag ? str1 : str2)
+end subroutine
+
+! Error: condition must be logical
+subroutine error_non_logical_condition()
+ integer :: i, x, y
+ real :: r
+ character :: ch
+
+ !ERROR: Must have LOGICAL type, but is INTEGER(4)
+ i = (i ? x : y)
+
+ !ERROR: Must have LOGICAL type, but is REAL(4)
+ i = (r ? x : y)
+
+ !ERROR: Must have LOGICAL type, but is CHARACTER(KIND=1,LEN=1_8)
+ i = (ch ? x : y)
+end subroutine
+
+! Error: type mismatch between branches
+subroutine error_type_mismatch(flag)
+ logical :: flag
+ integer :: i1, i2
+ real :: r
+ character :: ch
+ complex :: c
+
+ !ERROR: All values in conditional expression must have the same type and kind; have INTEGER(4) and REAL(4)
+ i1 = (flag ? i2 : r)
+
+ !ERROR: All values in conditional expression must have the same type and kind; have INTEGER(4) and CHARACTER(KIND=1,LEN=1_8)
+ i1 = (flag ? i2 : ch)
+
+ !ERROR: All values in conditional expression must have the same type and kind; have REAL(4) and COMPLEX(4)
+ r = (flag ? r : c)
+
+ !ERROR: All values in conditional expression must have the same type and kind; have LOGICAL(4) and INTEGER(4)
+ flag = (flag ? flag : i1)
+end subroutine
+
+! Error: kind mismatch (F2023 C1004)
+subroutine error_kind_mismatch(flag)
+ logical :: flag
+ integer(kind=4) :: i4
+ integer(kind=8) :: i8
+ real(kind=4) :: r4
+ real(kind=8) :: r8
+ complex(kind=4) :: c4
+ complex(kind=8) :: c8
+
+ !ERROR: All values in conditional expression must have the same type and kind; have INTEGER(4) and INTEGER(8)
+ i4 = (flag ? i4 : i8)
+
+ !ERROR: All values in conditional expression must have the same type and kind; have REAL(4) and REAL(8)
+ r4 = (flag ? r4 : r8)
+
+ !ERROR: All values in conditional expression must have the same type and kind; have COMPLEX(4) and COMPLEX(8)
+ c4 = (flag ? c4 : c8)
+end subroutine
+
+! Error: derived type mismatch
+subroutine error_derived_type_mismatch(flag)
+ type :: type1
+ integer :: i
+ end type
+
+ type :: type2
+ integer :: i
+ end type
+
+ logical :: flag
+ type(type1) :: t1
+ type(type2) :: t2
+
+ !ERROR: All values in conditional expression must be the same derived type; have type1 and type2
+ t1 = (flag ? t1 : t2)
+end subroutine
+
+! Error: array rank mismatch
+subroutine error_array_rank_mismatch(flag)
+ logical :: flag
+ integer :: arr1(10), mat1(3,3), result(10)
+
+ !ERROR: All values in conditional expression must have the same rank; have rank 1 and 2
+ result = (flag ? arr1 : mat1)
+end subroutine
+
+! Error: scalar vs array mismatch
+subroutine error_scalar_array_mismatch(flag)
+ logical :: flag
+ integer :: scalar, arr(10), result(10)
+
+ !ERROR: All values in conditional expression must have the same rank; have rank 0 and 1
+ result = (flag ? scalar : arr)
+end subroutine
+
+! Error: condition must be scalar
+subroutine error_array_condition()
+ logical :: flags(5)
+ integer :: x(5), y(5), result(5)
+
+ !ERROR: Must be a scalar value, but is a rank-1 array
+ result = (flags ? x : y)
+end subroutine
+
+! Valid cases with intrinsic functions
+subroutine valid_intrinsic_functions(x, y, flag)
+ integer :: x, y
+ logical :: flag
+ integer :: result
+
+ result = (flag ? abs(x) : abs(y))
+ result = (flag ? max(x, y) : min(x, y))
+end subroutine
+
+! Valid: conditional in array constructor
+subroutine valid_in_array_constructor(flag, x, y)
+ logical :: flag
+ integer :: x, y, arr(3)
+
+ arr = [(flag ? x : y), (flag ? x + 1 : y + 1), (flag ? x + 2 : y + 2)]
+end subroutine
+
+! Valid: conditional in expression context
+subroutine valid_in_expression(flag, x, y)
+ logical :: flag
+ integer :: x, y, z
+
+ z = (flag ? x : y) + 10
+ z = 2 * (flag ? x : y)
+
+ if ((flag ? x : y) > 5) then
+ z = 1
+ end if
+end subroutine
+
+! Note: allocatable/pointer differences are handled by assignment semantics
+! The conditional expression just requires matching types
+
+! Valid: both branches allocatable
+subroutine valid_both_allocatable(flag)
+ logical :: flag
+ integer, allocatable :: alloc1, alloc2, result
+
+ allocate(result)
+ result = (flag ? alloc1 : alloc2)
+end subroutine
+
+! Valid: both branches pointer
+subroutine valid_both_pointer(flag)
+ logical :: flag
+ integer, pointer :: ptr1, ptr2, result
+
+ result = (flag ? ptr1 : ptr2)
+end subroutine
+
+! Valid: elemental context
+elemental integer function conditional_elemental(flag, x, y)
+ logical, intent(in) :: flag
+ integer, intent(in) :: x, y
+
+ conditional_elemental = (flag ? x : y)
+end function
+
+! Valid: pure context
+pure integer function conditional_pure(flag, x, y)
+ logical, intent(in) :: flag
+ integer, intent(in) :: x, y
+
+ conditional_pure = (flag ? x : y)
+end function
+
+! Valid: recursive context
+recursive integer function conditional_recursive(n, flag, x, y) result(res)
+ integer, intent(in) :: n
+ logical, intent(in) :: flag
+ integer, intent(in) :: x, y
+
+ if (n <= 0) then
+ res = (flag ? x : y)
+ else
+ res = conditional_recursive(n - 1, flag, x, y)
+ end if
+end function
+
+! Valid: nested multi-branch
+subroutine valid_multi_branch(x)
+ integer :: x, result
+
+ ! Five-branch conditional
+ result = (x > 20 ? 1 : x > 15 ? 2 : x > 10 ? 3 : x > 5 ? 4 : 5)
+end subroutine
+
+! Error: polymorphic types not yet supported
+subroutine error_polymorphic(flag)
+ type :: base_t
+ integer :: i
+ end type
+
+ logical :: flag
+ class(base_t), allocatable :: poly1, poly2, result
+
+ !ERROR: Conditional expressions with polymorphic types (CLASS) are not yet supported
+ result = (flag ? poly1 : poly2)
+end subroutine
+
+! Error: mismatched character kinds
+subroutine error_character_kind_mismatch(flag)
+ logical :: flag
+ character(kind=1, len=5) :: ch1
+ character(kind=4, len=5) :: ch4
+
+ !ERROR: All values in conditional expression must have the same type and kind; have CHARACTER(KIND=1,LEN=5_8) and CHARACTER(KIND=4,LEN=5_8)
+ ch1 = (flag ? ch1 : ch4)
+end subroutine
+
+! Valid: optional arguments
+subroutine valid_optional_args(flag, opt_x, opt_y)
+ logical :: flag
+ integer, optional :: opt_x, opt_y
+ integer :: result
+
+ if (present(opt_x) .and. present(opt_y)) then
+ result = (flag ? opt_x : opt_y)
+ end if
+end subroutine
+
+! Valid: mix of expressions and designators
+subroutine valid_mixed_expressions(flag, x, y)
----------------
cenewcombe wrote:
Done ✔️
https://github.com/llvm/llvm-project/pull/186489
More information about the flang-commits
mailing list