! 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