blob: f16472f486d42b2f7207add55b94500a1fc76a06 [file] [edit]
! RUN: %flang_fc1 -fdebug-unparse-no-sema %s 2>&1 | FileCheck %s
! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s -check-prefix=TREE
! Test parsing of conditional expressions (Fortran 2023 R1002)
! Simple two-branch conditional
subroutine simple_conditional(x, y, z)
integer :: x, y, z
! CHECK-LABEL: simple_conditional
! CHECK: z = ( x>5 ? y : 10 )
! TREE: ConditionalExpr
! TREE-NEXT: Scalar -> Logical -> Expr
! TREE: Expr -> Designator -> DataRef -> Name = 'y'
! TREE: Expr -> LiteralConstant -> IntLiteralConstant = '10'
z = (x > 5 ? y : 10)
end subroutine
! Three-branch conditional (multiple conditions)
subroutine multi_branch_conditional(x, y, z)
integer :: x, y, z
! CHECK-LABEL: multi_branch_conditional
! CHECK: z = ( x>10 ? 100 : ( y<5 ? 50 : 0 ) )
! TREE: ConditionalExpr
! TREE-NEXT: Scalar -> Logical -> Expr
! TREE: Expr -> LiteralConstant -> IntLiteralConstant = '100'
! TREE: Expr -> ConditionalExpr
! TREE: Scalar -> Logical -> Expr
! TREE: Expr -> LiteralConstant -> IntLiteralConstant = '50'
! TREE: Expr -> LiteralConstant -> IntLiteralConstant = '0'
z = (x > 10 ? 100 : y < 5 ? 50 : 0)
end subroutine
! Nested conditionals
subroutine nested_conditionals(x, y, w, z, flag1, flag2)
integer :: x, y, w, z
logical :: flag1, flag2
! CHECK-LABEL: nested_conditionals
! Nested in value position
! CHECK: z = ( flag1 ? ( x>y ? x : y ) : 0 )
! TREE: ConditionalExpr
! TREE-NEXT: Scalar -> Logical -> Expr
! TREE: Expr -> ConditionalExpr
! TREE: Scalar -> Logical -> Expr
! TREE: Expr -> Designator -> DataRef -> Name = 'x'
! TREE: Expr -> Designator -> DataRef -> Name = 'y'
! TREE: Expr -> LiteralConstant -> IntLiteralConstant = '0'
z = (flag1 ? (x > y ? x : y) : 0)
! Nested in condition
! CHECK: z = ( ( x>5 ? flag1 : flag2 ) ? y : 10 )
z = ((x > 5 ? flag1 : flag2) ? y : 10)
! Multiple nested
! CHECK: z = ( x>10 ? ( y>20 ? 1 : 2 ) : ( w>30 ? 3 : 4 ) )
z = (x > 10 ? (y > 20 ? 1 : 2) : (w > 30 ? 3 : 4))
end subroutine
! Basic type conditionals
subroutine basic_types(x, a, b, c, flag1, str1)
integer :: x
real :: a, b, c
logical :: flag1
character(len=10) :: str1
! CHECK-LABEL: basic_types
! Real type
! CHECK: c = ( a>b ? a : b )
c = (a > b ? a : b)
! Logical type
! CHECK: flag1 = ( x>5 ? .TRUE. : .FALSE. )
flag1 = (x > 5 ? .true. : .false.)
! Character type
! CHECK: str1 = ( flag1 ? "HELLO" : "WORLD" )
str1 = (flag1 ? "HELLO" : "WORLD")
end subroutine
! Complex expressions in conditions and branches
subroutine complex_expressions(x, y, z, flag1)
integer :: x, y, z
logical :: flag1
! CHECK-LABEL: complex_expressions
! Complex expressions in branches
! CHECK: z = ( x>y ? x*2+1 : y*3-2 )
z = (x > y ? x*2+1 : y*3-2)
! Complex logical condition
! CHECK: z = ( x>5.AND.y<10 ? x+y : x-y )
z = (x > 5 .and. y < 10 ? x+y : x-y)
! Logical NOT
! CHECK: z = ( .NOT.flag1 ? x : y )
z = (.not. flag1 ? x : y)
! Comparison chains
! CHECK: z = ( x>5.AND.x<10 ? x : 0 )
z = (x > 5 .and. x < 10 ? x : 0)
! Parenthesized expressions in branches
! CHECK: z = ( x>5 ? (y+z) : (y-z) )
z = (x > 5 ? (y+z) : (y-z))
end subroutine
! Many-branch conditionals
subroutine many_branches(x, z)
integer :: x, z
! CHECK-LABEL: many_branches
! Four branches
! CHECK: z = ( x>10 ? 100 : ( x>5 ? 50 : ( x>0 ? 10 : 0 ) ) )
z = (x > 10 ? 100 : x > 5 ? 50 : x > 0 ? 10 : 0)
! Five branches
! CHECK: z = ( x>20 ? 1 : ( x>15 ? 2 : ( x>10 ? 3 : ( x>5 ? 4 : 5 ) ) ) )
z = (x > 20 ? 1 : x > 15 ? 2 : x > 10 ? 3 : x > 5 ? 4 : 5)
end subroutine
! Conditionals with arrays and functions
subroutine arrays_and_functions(x, y, z, arr, flag1)
integer :: x, y, z, arr(5)
logical :: flag1
! CHECK-LABEL: arrays_and_functions
! Array element in conditional
! CHECK: z = ( arr(1)>arr(2) ? arr(1) : arr(2) )
z = (arr(1) > arr(2) ? arr(1) : arr(2))
! Function calls in conditional
! CHECK: x = ( abs(y)>10 ? abs(y) : y )
x = (abs(y) > 10 ? abs(y) : y)
! Array constructor elements
! CHECK: arr(1:3) = [( flag1 ? x : y ), ( .NOT.flag1 ? x : y ), ( x>y ? x : y )]
arr(1:3) = [(flag1 ? x : y), (.not. flag1 ? x : y), (x > y ? x : y)]
end subroutine
! Literals in conditionals
subroutine literals(x, z, a, c)
integer :: x, z
real :: a, c
! CHECK-LABEL: literals
! Real literals
! CHECK: c = ( a>0.0 ? 1.5 : 2.5 )
c = (a > 0.0 ? 1.5 : 2.5)
! Negative values
! CHECK: z = ( x<0 ? -1 : 1 )
z = (x < 0 ? -1 : 1)
end subroutine
! Conditional in specification expression context
function spec_expr_conditional(n, flag) result(res)
integer, intent(in) :: n
logical, intent(in) :: flag
integer :: res
! CHECK-LABEL: spec_expr_conditional
! CHECK: res = ( flag ? n*2 : n )
res = (flag ? n*2 : n)
end function
! Conditional with different integer kinds
subroutine integer_kinds(cond)
integer(kind=4) :: i4a, i4b, i4c
integer(kind=8) :: i8a, i8b, i8c
logical :: cond
! CHECK-LABEL: integer_kinds
! CHECK: i4c = ( cond ? i4a : i4b )
i4c = (cond ? i4a : i4b)
! CHECK: i8c = ( cond ? i8a : i8b )
i8c = (cond ? i8a : i8b)
end subroutine
! Conditional with different real kinds
subroutine real_kinds(cond)
real(kind=4) :: r4a, r4b, r4c
real(kind=8) :: r8a, r8b, r8c
logical :: cond
! CHECK-LABEL: real_kinds
! CHECK: r4c = ( cond ? r4a : r4b )
r4c = (cond ? r4a : r4b)
! CHECK: r8c = ( cond ? r8a : r8b )
r8c = (cond ? r8a : r8b)
end subroutine
! Conditional in various statement contexts
subroutine statement_contexts(flag)
integer :: x, y, arr(10)
logical :: flag
! CHECK-LABEL: statement_contexts
! In array constructor
! CHECK: arr(1:3) = [1, ( flag ? x : y ), 3]
arr(1:3) = [1, (flag ? x : y), 3]
! In if statement condition
! CHECK: IF (( flag ? x : y )>5) THEN
if ((flag ? x : y) > 5) then
x = 1
end if
! In print statement
! CHECK: PRINT *, ( flag ? x : y )
print *, (flag ? x : y)
! In assignment to array element
! CHECK: arr(5) = ( flag ? x : y )
arr(5) = (flag ? x : y)
end subroutine
! Complex type conditionals
subroutine complex_type(flag)
complex :: c1, c2, c3
complex(kind=8) :: c8a, c8b, c8c
logical :: flag
! CHECK-LABEL: complex_type
! CHECK: c3 = ( flag ? c1 : c2 )
c3 = (flag ? c1 : c2)
! CHECK: c8c = ( flag ? c8a : c8b )
c8c = (flag ? c8a : c8b)
! With complex literals
! CHECK: c3 = ( flag ? (1.0,2.0) : (3.0,4.0) )
c3 = (flag ? (1.0, 2.0) : (3.0, 4.0))
end subroutine
! Array-valued conditionals (F2023 10.1.4)
subroutine array_valued(flag)
integer :: arr1(5), arr2(5), arr3(5)
real :: mat1(3,3), mat2(3,3), mat3(3,3)
logical :: flag
! CHECK-LABEL: array_valued
! Whole array conditional
! CHECK: arr3 = ( flag ? arr1 : arr2 )
! TREE: ConditionalExpr
! TREE-NEXT: Scalar -> Logical -> Expr
! TREE: Expr -> Designator -> DataRef -> Name = 'arr1'
! TREE: Expr -> Designator -> DataRef -> Name = 'arr2'
arr3 = (flag ? arr1 : arr2)
! Multidimensional array conditional
! CHECK: mat3 = ( flag ? mat1 : mat2 )
mat3 = (flag ? mat1 : mat2)
! Array section conditional
! CHECK: arr3(1:3) = ( flag ? arr1(1:3) : arr2(1:3) )
arr3(1:3) = (flag ? arr1(1:3) : arr2(1:3))
end subroutine
! Derived type conditionals
subroutine derived_types(flag)
type :: point
real :: x, y
end type
type(point) :: p1, p2, p3
logical :: flag
! CHECK-LABEL: derived_types
! CHECK: p3 = ( flag ? p1 : p2 )
p3 = (flag ? p1 : p2)
end subroutine
! Character with different lengths
subroutine character_lengths(flag)
character(len=5) :: short1, short2
character(len=10) :: medium1, medium2
character(len=20) :: long_result
logical :: flag
! CHECK-LABEL: character_lengths
! Same length characters
! CHECK: short1 = ( flag ? "HELLO" : "WORLD" )
short1 = (flag ? "HELLO" : "WORLD")
! Different length literals (type conformance rules apply)
! CHECK: long_result = ( flag ? "SHORT" : "MUCH LONGER STRING" )
long_result = (flag ? "SHORT" : "MUCH LONGER STRING")
! Mixed variables and literals
! CHECK: medium1 = ( flag ? short1 : medium2 )
medium1 = (flag ? short1 : medium2)
end subroutine
! Verify that '?' inside string literals and comments does not interfere
! with conditional expression parsing.
subroutine question_mark_chars(flag, str1, str2, str3)
logical :: flag
character(len=20) :: str1, str2, str3
! CHECK-LABEL: question_mark_chars
! CHECK: str1 = "HELLO?"
str1 = "HELLO?"
! CHECK: str2 = ( flag ? "YES?" : "NO?" )
str2 = (flag ? "YES?" : "NO?")
! CHECK: str3 = "WHAT? WHY? HOW?"
str3 = "WHAT? WHY? HOW?" ! ? in a comment
! CHECK: str2 = ( flag ? "MAYBE?" : "NOPE" )
str2 = (flag ? "MAYBE?" : "NOPE") ! ? in a trailing comment
end subroutine
! Verify that '(' and ')' inside character literals are handled correctly by
! ConditionalExprLookahead.
subroutine paren_in_char_literal(c, i)
character(*), intent(in) :: c
integer, intent(out) :: i
! CHECK-LABEL: paren_in_char_literal
! CHECK: i = ( c==")" ? 1 : 2 )
i = (c == ")" ? 1 : 2)
! CHECK: i = ( c=="(" ? 1 : 2 )
i = (c == "(" ? 1 : 2)
! CHECK: i = ( c=="()" ? 1 : 2 )
i = (c == "()" ? 1 : 2)
end subroutine