| ! 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 |