blob: fac95dd6dc4ed65b36088c96ea51e94252e070db [file] [edit]
! RUN: %python %S/test_errors.py %s %flang_fc1
! Test semantic analysis of conditional arguments (F2023:R1526-R1528)
! Constraints F2023:C1538-C1545
module m_conditional_arg
implicit none
interface
subroutine sub_int(x)
integer, intent(in) :: x
end subroutine
subroutine sub_real(x)
real, intent(in) :: x
end subroutine
subroutine sub_int_out(x)
integer, intent(out) :: x
end subroutine
subroutine sub_int_inout(x)
integer, intent(inout) :: x
end subroutine
subroutine sub_optional(x)
integer, intent(in), optional :: x
end subroutine
subroutine sub_not_optional(x)
integer, intent(in) :: x
end subroutine
subroutine sub_alloc(x)
integer, intent(inout), allocatable :: x
end subroutine
subroutine sub_pointer(x)
integer, intent(inout), pointer :: x
end subroutine
subroutine sub_array(x)
integer, intent(in) :: x(:)
end subroutine
subroutine sub_assumed_rank(x)
integer, intent(in) :: x(..)
end subroutine
subroutine sub_coarray(x)
integer, intent(inout) :: x[*]
end subroutine
subroutine sub_two(x, y)
integer, intent(in) :: x, y
end subroutine
subroutine sub_array_fixed(x)
integer, intent(in) :: x(5)
end subroutine
subroutine sub_array_two(x, y)
integer, intent(in) :: x(:), y(:)
end subroutine
subroutine sub_matrix(x)
integer, intent(in) :: x(:,:)
end subroutine
subroutine sub_array_optional(x)
integer, intent(in), optional :: x(:)
end subroutine
subroutine sub_matrix_optional(x)
integer, intent(in), optional :: x(:,:)
end subroutine
pure integer function func_int(x)
integer, intent(in) :: x
end function
pure real function func_real(x)
real, intent(in) :: x
end function
pure integer function func_two(x, y)
integer, intent(in) :: x, y
end function
end interface
contains
! =========================================================================
! Positive tests: valid conditional arguments
! =========================================================================
subroutine test_valid_simple
integer :: a, b
logical :: flag
! Simple two-branch conditional arg with explicit interface
call sub_int((flag ? a : b))
end subroutine
subroutine test_valid_multi_branch
integer :: a, b, c
logical :: flag, flag2
! Multi-branch conditional arg
call sub_int((flag ? a : flag2 ? b : c))
end subroutine
subroutine test_valid_nil_optional
integer :: a
logical :: flag
! .NIL. is allowed with optional dummy
call sub_optional((flag ? a : .NIL.))
end subroutine
subroutine test_valid_nil_middle
integer :: a, b
logical :: flag, flag2
! .NIL. in middle branch with optional dummy
call sub_optional((flag ? .NIL. : flag2 ? a : b))
end subroutine
subroutine test_valid_expressions
integer :: a, b
logical :: flag
! Expression consequent-args with INTENT(IN)
call sub_int((flag ? a + 1 : b * 2))
end subroutine
subroutine test_valid_intent_out
integer :: a, b
logical :: flag
! Variable consequent-args with INTENT(OUT)
call sub_int_out((flag ? a : b))
end subroutine
subroutine test_valid_intent_inout
integer :: a, b
logical :: flag
! Variable consequent-args with INTENT(INOUT)
call sub_int_inout((flag ? a : b))
end subroutine
subroutine test_valid_two_args
integer :: a, b, c, d
logical :: flag, flag2
! Multiple arguments, one conditional
call sub_two(a, (flag ? b : c))
end subroutine
! =========================================================================
! Implicit interface: conditional arguments require an explicit interface.
! =========================================================================
subroutine test_implicit_interface
integer :: a, b
logical :: flag
!ERROR: Conditional argument requires an explicit interface
call external_sub_no_interface((flag ? a : b))
end subroutine
! =========================================================================
! F2023:R1526: The condition in a conditional argument must be a
! scalar-logical-expr.
! =========================================================================
subroutine test_nonlogical_condition
integer :: a, b, icond
real :: rcond
character :: ccond
logical :: flag
!ERROR: Must have LOGICAL type, but is INTEGER(4)
call sub_int((icond ? a : b))
!ERROR: Must have LOGICAL type, but is REAL(4)
call sub_int((rcond ? a : b))
!ERROR: Must have LOGICAL type, but is CHARACTER(KIND=1,LEN=1_8)
call sub_int((ccond ? a : b))
! Valid: logical condition
call sub_int((flag ? a : b))
end subroutine
subroutine test_nonscalar_condition
integer :: a, b
logical :: arr_flag(5)
!ERROR: Must be a scalar value, but is a rank-1 array
call sub_int((arr_flag ? a : b))
end subroutine
! =========================================================================
! F2023:C1538: Each consequent-arg shall have the same declared type and
! kind type parameters.
! =========================================================================
subroutine test_f2023_c1538_different_type
integer :: a
real :: r
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have INTEGER(4) and REAL(4)
call sub_int((flag ? a : r))
end subroutine
subroutine test_f2023_c1538_different_kind
integer(4) :: a
integer(8) :: b
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have INTEGER(4) and INTEGER(8)
call sub_int((flag ? a : b))
end subroutine
subroutine test_f2023_c1538_three_branch_mismatch
integer :: a, b
real :: r
logical :: flag, flag2
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have INTEGER(4) and REAL(4)
call sub_int((flag ? a : flag2 ? b : r))
end subroutine
! =========================================================================
! F2023:C1539: Either all consequent-args shall have the same rank, or be
! assumed-rank.
! =========================================================================
subroutine test_f2023_c1539_rank_mismatch
integer :: a
integer :: arr(5)
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same rank
call sub_int((flag ? a : arr))
end subroutine
subroutine test_f2023_c1539_mixed_assumed_rank_and_fixed_rank(x)
integer, intent(in) :: x(..)
logical :: flag
integer :: a
! Mixing assumed-rank and non-assumed-rank violates F2023:C1539
!ERROR: All consequent-args in a conditional argument must have the same rank or all must be assumed-rank
call sub_int((flag ? x : a))
end subroutine
! =========================================================================
! F2023:C1540: At least one consequent shall be a consequent-arg.
! If the corresponding dummy argument is not optional, .NIL.
! shall not appear.
! =========================================================================
subroutine test_f2023_c1540_all_nil
logical :: flag
!ERROR: At least one consequent in a conditional argument must not be .NIL.
call sub_optional((flag ? .NIL. : .NIL.))
end subroutine
subroutine test_f2023_c1540_nil_non_optional
integer :: a
logical :: flag
!ERROR: .NIL. in conditional argument associated with non-optional dummy argument 'x='
call sub_not_optional((flag ? a : .NIL.))
end subroutine
! =========================================================================
! F2023:C1541: If its corresponding dummy argument is INTENT(OUT) or
! INTENT(INOUT), each consequent-arg shall be a variable.
! =========================================================================
subroutine test_f2023_c1541_intent_out_expr
integer :: a
logical :: flag
!ERROR: Each consequent-arg in conditional argument associated with INTENT(OUT) dummy argument 'x=' must be a variable
!ERROR: Actual argument associated with INTENT(OUT) dummy argument 'x=' is not definable
!ERROR: 'a+1_4' is not a variable or pointer
call sub_int_out((flag ? a + 1 : a))
end subroutine
subroutine test_f2023_c1541_intent_inout_expr
integer :: a
logical :: flag
!ERROR: Each consequent-arg in conditional argument associated with INTENT(IN OUT) dummy argument 'x=' must be a variable
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'x=' is not definable
!ERROR: 'a+1_4' is not a variable or pointer
call sub_int_inout((flag ? a + 1 : a))
end subroutine
! =========================================================================
! F2023:C1542: If its corresponding dummy argument is allocatable, a
! pointer, or a coarray, the attributes of each
! consequent-arg shall satisfy the requirements of that dummy
! argument.
! =========================================================================
subroutine test_f2023_c1542_non_allocatable
integer :: a, b
logical :: flag
!ERROR: ALLOCATABLE dummy argument 'x=' must be associated with an ALLOCATABLE actual argument
call sub_alloc((flag ? a : b))
end subroutine
subroutine test_f2023_c1542_non_pointer
integer :: a, b
logical :: flag
!ERROR: Actual argument associated with POINTER dummy argument 'x=' must also be POINTER unless INTENT(IN)
call sub_pointer((flag ? a : b))
end subroutine
subroutine test_f2023_c1542_non_coarray
integer :: a, b
logical :: flag
! Non-coarray consequent-args passed to a coarray dummy violates F2023:C1542
!ERROR: Each consequent-arg in conditional argument associated with a coarray dummy argument 'x=' must be a coarray
!ERROR: Actual argument associated with coarray dummy argument 'x=' must be a coarray
call sub_coarray((flag ? a : b))
end subroutine
! =========================================================================
! F2023:C1543: A consequent-arg shall not be assumed-rank unless its
! corresponding dummy argument is also assumed-rank.
! =========================================================================
subroutine test_f2023_c1543_assumed_rank_to_non_assumed_rank_dummy(x, y)
integer, intent(in) :: x(..), y(..)
logical :: flag
! Both consequents are assumed-rank (satisfies F2023:C1539) but the
! dummy is not assumed-rank — violates F2023:C1543.
!ERROR: Assumed-rank consequent-arg in conditional argument may only be associated with assumed-rank dummy argument 'x='
!ERROR: Assumed-rank actual argument may not be associated with a dummy argument 'x=' that is not also assumed-rank
call sub_int((flag ? x : y))
end subroutine
! =========================================================================
! F2023:C1544: A consequent-arg that is an expr shall not be a variable.
!
! This is a grammar disambiguation rule making the "expr" and "variable"
! alternatives of R1528 mutually exclusive. It is automatically satisfied
! because the parser collapses both alternatives into a single Expr
! production; IsVariable() determines the distinction at the semantic
! level. The tests below demonstrate that the distinction works correctly:
! variables are accepted where variables are required (C1541), expressions
! are accepted where expressions suffice (INTENT(IN)), and non-variable
! expressions are rejected where variables are required.
! =========================================================================
subroutine test_f2023_c1544_variable_with_intent_in
integer :: a, b
logical :: flag
! A variable consequent-arg is valid with INTENT(IN): it matched the
! "variable" alternative of R1528, satisfying C1544.
call sub_int((flag ? a : b))
end subroutine
subroutine test_f2023_c1544_expr_with_intent_in
integer :: a, b
logical :: flag
! A non-variable expression is valid with INTENT(IN): it matched the
! "expr" alternative of R1528 and is not a variable, satisfying C1544.
call sub_int((flag ? a + 1 : b * 2))
end subroutine
subroutine test_f2023_c1544_variable_with_intent_out
integer :: a, b
logical :: flag
! A variable consequent-arg is valid with INTENT(OUT): it matched the
! "variable" alternative, satisfying both C1544 and C1541.
call sub_int_out((flag ? a : b))
end subroutine
subroutine test_f2023_c1544_expr_with_intent_out
integer :: a
logical :: flag
! A non-variable expression with INTENT(OUT) satisfies C1544 (it is an
! expr and not a variable) but violates C1541 (INTENT(OUT) requires a
! variable). The C1541 error demonstrates the disambiguation works.
!ERROR: Each consequent-arg in conditional argument associated with INTENT(OUT) dummy argument 'x=' must be a variable
!ERROR: Actual argument associated with INTENT(OUT) dummy argument 'x=' is not definable
!ERROR: 'a+1_4' is not a variable or pointer
call sub_int_out((flag ? a + 1 : a))
end subroutine
subroutine test_f2023_c1544_mixed_variable_and_expr
integer :: a
logical :: flag
! One consequent-arg is a variable, the other is an expression.
! Both are valid with INTENT(IN): each independently satisfies C1544
! (variable matched "variable", expression matched "expr").
call sub_int((flag ? a : a + 1))
end subroutine
! =========================================================================
! Typeless consequent-args: BOZ literals and NULL() without MOLD=
! are not allowed as consequent-args because they have no type.
! =========================================================================
subroutine test_typeless_boz_consequent
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
call sub_int((flag ? a : z'FF'))
end subroutine
subroutine test_typeless_boz_first_consequent
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
call sub_int((flag ? z'FF' : a))
end subroutine
subroutine test_typeless_boz_both_consequents
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
call sub_int((flag ? z'FF' : z'00'))
end subroutine
subroutine test_typeless_boz_multi_branch
integer :: a, b
logical :: flag, flag2
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
call sub_int((flag ? a : flag2 ? b'101' : b))
end subroutine
subroutine test_typeless_null_consequent
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
!ERROR: NULL() may not be used as an expression in this context
call sub_int((flag ? a : null()))
end subroutine
subroutine test_typeless_null_first_consequent
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
!ERROR: NULL() may not be used as an expression in this context
call sub_int((flag ? null() : a))
end subroutine
subroutine test_typeless_null_both_consequents
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
!ERROR: NULL() may not be used as an expression in this context
call sub_optional((flag ? null() : null()))
end subroutine
! =========================================================================
! F2023:C1545: In a reference to a generic procedure, each consequent-arg
! shall have the same corank, and if any consequent-arg has the
! ALLOCATABLE or POINTER attribute, each consequent-arg shall
! have that attribute.
! =========================================================================
subroutine test_f2023_c1545_allocatable_inconsistency
integer, allocatable :: a
integer :: b
logical :: flag
!ERROR: If any consequent-arg in a conditional argument has the ALLOCATABLE attribute, each must have it
!ERROR: ALLOCATABLE dummy argument 'x=' must be associated with an ALLOCATABLE actual argument
call sub_alloc((flag ? a : b))
end subroutine
subroutine test_f2023_c1545_pointer_inconsistency
integer, pointer :: p
integer :: b
logical :: flag
!ERROR: If any consequent-arg in a conditional argument has the POINTER attribute, each must have it
!ERROR: Actual argument associated with POINTER dummy argument 'x=' must also be POINTER unless INTENT(IN)
call sub_pointer((flag ? p : b))
end subroutine
subroutine test_f2023_c1545_allocatable_consistent_valid
integer, allocatable :: a, b
logical :: flag
! Both consequent-args are allocatable -- no C1545 error
call sub_alloc((flag ? a : b))
end subroutine
subroutine test_f2023_c1545_pointer_consistent_valid
integer, pointer :: p, q
logical :: flag
! Both consequent-args are pointer -- no C1545 error
call sub_pointer((flag ? p : q))
end subroutine
! =========================================================================
! Shape analysis: verify that conditional args with array consequent-args
! get their shape from the consequents, not from the scalar condition.
! Without the GetShapeHelper(ActualArgument) override, the Traverse base
! class would return the scalar shape of the condition via CombineAnyOf,
! causing spurious shape mismatches.
! =========================================================================
subroutine test_shape_array_conditional_arg
integer :: a(5), b(5)
logical :: flag
! Array conditional arg passed to assumed-shape dummy — shape comes
! from the consequent-args (rank 1), not the scalar condition.
call sub_array((flag ? a : b))
end subroutine
subroutine test_shape_array_fixed_extent
integer :: a(5), b(5)
logical :: flag
! Array conditional arg with fixed-extent dummy.
call sub_array_fixed((flag ? a : b))
end subroutine
subroutine test_shape_matrix_conditional_arg
integer :: m1(3,4), m2(3,4)
logical :: flag
! Rank-2 array conditional arg.
call sub_matrix((flag ? m1 : m2))
end subroutine
subroutine test_shape_two_array_args
integer :: a(5), b(5), c(5), d(5)
logical :: f1, f2
! Two independent array conditional args in the same call.
call sub_array_two((f1 ? a : b), (f2 ? c : d))
end subroutine
subroutine test_shape_nil_with_array
integer :: a(5), b(5)
logical :: flag, flag2
! .NIL. mixed with rank-1 array consequent-args passed to an optional
! array dummy. If the shape analysis fails to extract rank from the
! first non-.NIL. consequent, this will produce a rank mismatch error.
call sub_array_optional((flag ? .NIL. : flag2 ? a : b))
end subroutine
subroutine test_shape_nil_scalar_to_array_dummy
integer :: a, b
logical :: flag, flag2
! .NIL. with scalar consequent-args passed to an optional array dummy.
! Shape analysis extracts rank 0 from the first non-.NIL. consequent,
! which mismatches the assumed-shape array dummy.
!ERROR: Scalar actual argument may not be associated with assumed-shape dummy argument 'x='
call sub_array_optional((flag ? .NIL. : flag2 ? a : b))
end subroutine
subroutine test_shape_nil_skipped_rank_mismatch
integer :: a(5), b(5)
logical :: flag, flag2
! .NIL. is the first consequent; non-.NIL. consequents are rank-1 arrays.
! Dummy is a rank-2 matrix. If shape were extracted from .NIL. (no shape),
! this might silently pass. Instead, shape comes from the rank-1 array,
! producing a rank mismatch — proving .NIL. was correctly skipped.
!ERROR: Rank of dummy argument is 2, but actual argument has rank 1
call sub_matrix_optional((flag ? .NIL. : flag2 ? a : b))
end subroutine
subroutine test_shape_nil_forced_rank_match
integer :: a(5)
! .TRUE. forces .NIL. to be selected — after folding, the arg becomes
! absent. But shape analysis runs on the unfolded conditional arg and
! still checks the rank of the non-.NIL. consequent (a, rank 1) against
! the dummy (rank 1). No error because ranks match.
call sub_array_optional((.true. ? .NIL. : a))
end subroutine
subroutine test_shape_nil_forced_rank_mismatch
integer :: a(5)
! .TRUE. forces .NIL. to be selected, but shape analysis still extracts
! rank from the non-.NIL. consequent (a, rank 1). The dummy is rank 2,
! so this errors — proving shape is NOT extracted from .NIL. even when
! .NIL. is the branch that will be selected at compile time.
!ERROR: Rank of dummy argument is 2, but actual argument has rank 1
call sub_matrix_optional((.true. ? .NIL. : a))
end subroutine
subroutine test_shape_nil_with_array_optional
integer :: a(5), b(5)
logical :: flag, flag2
! .NIL. with array consequent-args and an optional scalar dummy.
! Shape comes from the first non-.NIL. consequent (a(1), scalar).
call sub_optional((flag ? .NIL. : flag2 ? a(1) : b(1)))
end subroutine
subroutine test_shape_multi_branch_array
integer :: a(5), b(5), c(5)
logical :: f1, f2
! Multi-branch conditional arg with arrays — all same rank.
call sub_array((f1 ? a : f2 ? b : c))
end subroutine
! =========================================================================
! Intrinsic characterization: conditional args with intrinsic procedures.
! Verifies that intrinsic argument matching correctly extracts the type
! and kind from a conditional arg via GetArgExpr().
! =========================================================================
subroutine test_intrinsic_abs_int
integer :: a, b, r
logical :: flag
! ABS with integer conditional arg — runtime condition exercises
! the GetArgExpr() path in intrinsic characterization.
r = abs((flag ? a : b))
end subroutine
subroutine test_intrinsic_abs_real
real :: a, b, r
logical :: flag
r = abs((flag ? a : b))
end subroutine
subroutine test_intrinsic_max_conditional
integer :: a, b, c, r
logical :: flag
! MAX with a mix of conditional and plain args.
r = max((flag ? a : b), c)
end subroutine
subroutine test_intrinsic_min_multi_conditional
integer :: a, b, c, d, r
logical :: f1, f2
! MIN with multiple conditional args.
r = min((f1 ? a : b), (f2 ? c : d))
end subroutine
subroutine test_intrinsic_len_trim_char
character(10) :: s1, s2
logical :: flag
integer :: r
r = len_trim((flag ? s1 : s2))
end subroutine
subroutine test_intrinsic_multi_branch
integer :: a, b, c, r
logical :: f1, f2
! Multi-branch conditional arg in intrinsic call.
r = abs((f1 ? a : f2 ? b : c))
end subroutine
! =========================================================================
! Coarray: conditional args with coarray consequent-args.
! Verifies that GetCorank (via GetArgExpr()) correctly extracts the
! corank from a conditional arg's consequent.
! =========================================================================
subroutine test_valid_coarray_conditional(a, b, flag)
integer, intent(inout) :: a[*], b[*]
logical, intent(in) :: flag
! Both consequent-args are coarrays — matches coarray dummy.
call sub_coarray((flag ? a : b))
end subroutine
subroutine test_valid_coarray_multi_branch(a, b, c, f1, f2)
integer, intent(inout) :: a[*], b[*], c[*]
logical, intent(in) :: f1, f2
! Multi-branch with all coarray consequent-args.
call sub_coarray((f1 ? a : f2 ? b : c))
end subroutine
! =========================================================================
! Double-parenthesized conditional: the extra parens cause the parser to
! treat it as a ConditionalExpr (expression-level) rather than a
! ConditionalArg (argument-level). This exercises the expression folding
! path for intrinsics instead of the ConditionalArg path.
! =========================================================================
subroutine test_double_paren_abs_int
integer :: a, b, r
logical :: flag
r = abs(((flag ? a : b)))
end subroutine
subroutine test_double_paren_abs_real
real :: a, b, r
logical :: flag
r = abs(((flag ? a : b)))
end subroutine
subroutine test_double_paren_max
integer :: a, b, c, r
logical :: flag
r = max(((flag ? a : b)), c)
end subroutine
subroutine test_double_paren_multi_branch
integer :: a, b, c, r
logical :: f1, f2
r = abs(((f1 ? a : f2 ? b : c)))
end subroutine
! =========================================================================
! Non-intrinsic (user-defined) function calls with conditional args.
! Unlike intrinsics, these skip the intrinsic folding path entirely,
! so the ConditionalArg in ActualArgument::u_ is passed through as-is.
! =========================================================================
subroutine test_user_func_int
integer :: a, b, r
logical :: flag
r = func_int((flag ? a : b))
end subroutine
subroutine test_user_func_real
real :: a, b, r
logical :: flag
r = func_real((flag ? a : b))
end subroutine
subroutine test_user_func_multi_branch
integer :: a, b, c, r
logical :: f1, f2
r = func_int((f1 ? a : f2 ? b : c))
end subroutine
subroutine test_user_func_two_args
integer :: a, b, c, d, r
logical :: f1, f2
! One conditional arg and one plain arg.
r = func_two((f1 ? a : b), c)
end subroutine
subroutine test_user_func_two_conditional
integer :: a, b, c, d, r
logical :: f1, f2
! Both arguments are conditional args.
r = func_two((f1 ? a : b), (f2 ? c : d))
end subroutine
end module
! ===========================================================================
! Test conditional arguments used across module boundaries via USE
! ===========================================================================
module m_cond_arg_provider
implicit none
interface
subroutine ext_sub_int(x)
integer, intent(in) :: x
end subroutine
subroutine ext_sub_optional(x)
integer, intent(in), optional :: x
end subroutine
subroutine ext_sub_real(x)
real, intent(in) :: x
end subroutine
subroutine ext_sub_int_out(x)
integer, intent(out) :: x
end subroutine
end interface
contains
subroutine provider_valid(a, b, flag)
integer, intent(in) :: a, b
logical, intent(in) :: flag
call ext_sub_int((flag ? a : b))
end subroutine
subroutine provider_valid_optional(a, flag)
integer, intent(in) :: a
logical, intent(in) :: flag
call ext_sub_optional((flag ? a : .NIL.))
end subroutine
end module
subroutine test_use_module_conditional_arg
use m_cond_arg_provider
implicit none
integer :: x, y
logical :: cond
! Valid: use procedures from a module with conditional args
call provider_valid(x, y, cond)
call provider_valid_optional(x, cond)
! Valid: use module interfaces directly with conditional args
call ext_sub_int((cond ? x : y))
call ext_sub_optional((cond ? x : .NIL.))
end subroutine
subroutine test_use_module_type_mismatch
use m_cond_arg_provider
implicit none
integer :: a
real :: r
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have INTEGER(4) and REAL(4)
call ext_sub_int((flag ? a : r))
end subroutine
subroutine test_use_module_boz
use m_cond_arg_provider
implicit none
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
call ext_sub_int((flag ? a : z'FF'))
end subroutine
subroutine test_use_module_null
use m_cond_arg_provider
implicit none
integer :: a
logical :: flag
!ERROR: Typeless expression is not allowed as a consequent in a conditional argument
!ERROR: NULL() may not be used as an expression in this context
call ext_sub_int((flag ? null() : a))
end subroutine
subroutine test_use_module_nil_non_optional
use m_cond_arg_provider
implicit none
integer :: a
logical :: flag
!ERROR: .NIL. in conditional argument associated with non-optional dummy argument 'x='
call ext_sub_int((flag ? a : .NIL.))
end subroutine
subroutine test_use_module_intent_out_expr
use m_cond_arg_provider
implicit none
integer :: a
logical :: flag
!ERROR: Each consequent-arg in conditional argument associated with INTENT(OUT) dummy argument 'x=' must be a variable
!ERROR: Actual argument associated with INTENT(OUT) dummy argument 'x=' is not definable
!ERROR: 'a+1_4' is not a variable or pointer
call ext_sub_int_out((flag ? a + 1 : a))
end subroutine
! =========================================================================
! Derived type tests
! =========================================================================
module m_derived_types
implicit none
type :: t1
integer :: x
end type
type :: t2
integer :: x
end type
type, extends(t1) :: t1_ext
integer :: y
end type
interface
subroutine sub_t1(x)
import :: t1
type(t1), intent(in) :: x
end subroutine
subroutine sub_class_t1(x)
import :: t1
class(t1), intent(in) :: x
end subroutine
subroutine sub_class_star(x)
class(*), intent(in) :: x
end subroutine
subroutine sub_type_star(x)
type(*), intent(in) :: x
end subroutine
end interface
end module
subroutine test_derived_same_type
use m_derived_types
implicit none
type(t1) :: a, b
logical :: flag
! Valid: same declared type
call sub_t1((flag ? a : b))
end subroutine
subroutine test_derived_mismatched_type
use m_derived_types
implicit none
type(t1) :: a
type(t2) :: b
logical :: flag
!ERROR: All consequent-args in a conditional argument must be the same derived type; have t1 and t2
call sub_t1((flag ? a : b))
end subroutine
! Per F2023 15.5.2.3p4, mixing CLASS(t) and TYPE(t) with the same t is valid —
! the conditional arg becomes polymorphic.
subroutine test_polymorphic_class_and_type
use m_derived_types
implicit none
type(t1), allocatable :: a
class(t1), allocatable :: b
logical :: flag
! Valid: CLASS(t1) mixed with TYPE(t1), same declared type per C1538
call sub_class_t1((flag ? b : a))
end subroutine
! CLASS(*) mixed with non-CLASS(*) is invalid — no declared type to compare.
subroutine test_unlimited_poly_mismatch
use m_derived_types
implicit none
type(t1) :: a
class(*), allocatable :: b
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have CLASS(*) and t1
call sub_class_star((flag ? b : a))
end subroutine
! Both CLASS(*) is valid.
subroutine test_unlimited_poly_both
use m_derived_types
implicit none
class(*), allocatable :: a, b
logical :: flag
! Valid: both unlimited polymorphic
call sub_class_star((flag ? a : b))
end subroutine
! TYPE(*) with TYPE(*) — both assumed type, should be valid.
! F2023 15.5.2.3-2: consequent-args are actual arguments, so TYPE(*) is permitted.
subroutine test_assumed_type_both(a, b)
use m_derived_types
implicit none
type(*), intent(in) :: a, b
logical :: flag
! Valid: both assumed type
call sub_type_star((flag ? a : b))
end subroutine
! TYPE(*) with TYPE(t1) — one assumed type, one concrete type, should error.
subroutine test_assumed_type_mismatch(a)
use m_derived_types
implicit none
type(*), intent(in) :: a
type(t1) :: b
logical :: flag
!ERROR: All consequent-args in a conditional argument must have the same type and kind; have TYPE(*) and t1
call sub_type_star((flag ? a : b))
end subroutine
! CLASS(t1) with CLASS(t1) — both polymorphic same declared type, should be valid.
subroutine test_class_same_type
use m_derived_types
implicit none
class(t1), allocatable :: a, b
logical :: flag
! Valid: both CLASS(t1), same declared type
call sub_class_t1((flag ? a : b))
end subroutine
! CLASS(t1) with CLASS(t2) — both polymorphic different declared types, should error.
subroutine test_class_different_types
use m_derived_types
implicit none
class(t1), allocatable :: a
class(t2), allocatable :: b
logical :: flag
!ERROR: All consequent-args in a conditional argument must be the same derived type; have CLASS(t1) and CLASS(t2)
call sub_class_star((flag ? a : b))
end subroutine
! =========================================================================
! Assumed-type (TYPE(*)) usage in a consequent (F2018 C710 / F2023 C715).
! A consequent-arg is an actual argument, so a *bare* TYPE(*) dummy is
! permitted as a whole consequent. But an assumed-type entity nested inside
! a larger consequent expression remains illegal: the waiver must apply only
! to the consequent expression itself, not to its sub-expressions.
! =========================================================================
! Valid: a bare TYPE(*) consequent is an actual argument.
subroutine test_assumed_type_bare_ok(a, b)
implicit none
type(*), intent(in) :: a, b
logical :: flag
interface
subroutine sub_star(x)
type(*), intent(in) :: x
end subroutine
end interface
call sub_star((flag ? a : b))
end subroutine
! A parenthesized assumed-type consequent is an expression, not a bare actual
! argument, so it is illegal. This is the case that escaped diagnosis when the
! TYPE(*) waiver leaked into the whole consequent sub-expression tree.
subroutine test_assumed_type_parenthesized(a, b)
implicit none
type(*), intent(in) :: a, b
logical :: flag
interface
subroutine sub_star(x)
type(*), intent(in) :: x
end subroutine
end interface
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_star((flag ? (a) : b))
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_star((flag ? ((a)) : b))
end subroutine
! Assumed-type nested in a larger consequent expression is illegal. These cases
! are also independently diagnosed when each operand/argument is analyzed, but
! they must remain errors regardless of the conditional-argument waiver.
subroutine test_assumed_type_in_subexpr(a, b)
implicit none
type(*), intent(in) :: a, b
integer :: other, arr(3)
logical :: flag, flag2
interface
subroutine sub_int(x)
integer, intent(in) :: x
end subroutine
end interface
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_int((flag ? a + 1 : other))
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_int((flag ? other : b + 1))
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_int((flag ? -a : other))
!ERROR: Assumed type TYPE(*) dummy argument not allowed for 'a=' intrinsic argument
call sub_int((flag ? iabs(a) : other))
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_int((flag ? other : flag2 ? a + 1 : other))
!ERROR: TYPE(*) dummy argument may only be used as an actual argument
call sub_int((flag ? arr(a) : other))
end subroutine
! =========================================================================
! C1538 derived-type identity via structure equivalence and type parameters.
! The consequent-arg type check uses AreSameDerivedTypeIgnoringLengthParameters,
! which (a) resolves symbol aliases, (b) treats separately-declared SEQUENCE /
! BIND(C) types as the same type when structurally equivalent (F2023 7.5.2.4),
! and (c) requires equal kind type parameters while allowing length type
! parameters to differ.
! =========================================================================
module m_seq_cond
contains
function f1()
type :: point
sequence
integer :: x, y, z
end type
type(point) :: f1
end function
function f2()
type :: point
sequence
integer :: x, y, z
end type
type(point) :: f2
end function
subroutine foo(p)
type :: point
sequence
integer :: x, y, z
end type
type(point), intent(in) :: p
end subroutine
! Valid: f1() and f2() return separately-declared but structurally identical
! SEQUENCE types, which are the same type per F2023 7.5.2.4.
subroutine test_seq_equiv(cdt)
logical :: cdt
call foo((cdt ? f1() : f2()))
end subroutine
end module
module m_param_cond
type :: tlen(l)
integer, len :: l
integer :: a(l)
end type
type :: tkind(k)
integer, kind :: k
integer(k) :: a
end type
interface
subroutine sub_tlen(x)
import :: tlen
type(tlen(*)), intent(in) :: x
end subroutine
subroutine sub_tkind4(x)
import :: tkind
type(tkind(4)), intent(in) :: x
end subroutine
end interface
contains
! Valid: length type parameters may differ between consequent-args (C1538
! constrains only the declared type and kind type parameters).
subroutine test_len_param_differ(cdt)
logical :: cdt
type(tlen(3)) :: a
type(tlen(5)) :: b
call sub_tlen((cdt ? a : b))
end subroutine
! Error: kind type parameters must match.
subroutine test_kind_param_differ(cdt)
logical :: cdt
type(tkind(4)) :: a
type(tkind(8)) :: b
!ERROR: All consequent-args in a conditional argument must be the same derived type; have tkind(k=4_4) and tkind(k=8_4)
call sub_tkind4((cdt ? a : b))
end subroutine
end module