| ! { dg-do run } |
| ! |
| ! Test conformance with clause 7.5.6.3, paragraph 6 of F2018. Most of PR106576: |
| ! The finalization of function results within specification expressions is tested |
| ! in finalize_49.f90. |
| ! |
| ! Contributed by Damian Rouson <damian@archaeologic.codes> |
| ! |
| module test_result_m |
| !! Define tests for each scenario in which the Fortran 2018 |
| !! standard mandates type finalization. |
| implicit none |
| |
| private |
| public :: test_result_t, get_test_results |
| |
| type test_result_t |
| character(len=132) description |
| logical outcome |
| end type |
| |
| type object_t |
| integer dummy |
| contains |
| final :: count_finalizations |
| end type |
| |
| type wrapper_t |
| private |
| type(object_t), allocatable :: object |
| end type |
| |
| integer :: finalizations = 0 |
| integer, parameter :: avoid_unused_variable_warning = 1 |
| |
| contains |
| |
| function get_test_results() result(test_results) |
| type(test_result_t), allocatable :: test_results(:) |
| |
| test_results = [ & |
| test_result_t("finalizes a non-allocatable object on the LHS of an intrinsic assignment", lhs_object()) & |
| ,test_result_t("finalizes an allocated allocatable LHS of an intrinsic assignment", allocated_allocatable_lhs()) & |
| ,test_result_t("finalizes a target when the associated pointer is deallocated", target_deallocation()) & |
| ,test_result_t("finalizes an object upon explicit deallocation", finalize_on_deallocate()) & |
| ,test_result_t("finalizes a non-pointer non-allocatable object at the END statement", finalize_on_end()) & |
| ,test_result_t("finalizes a non-pointer non-allocatable object at the end of a block construct", block_end()) & |
| ,test_result_t("finalizes a function reference on the RHS of an intrinsic assignment", rhs_function_reference()) & |
| ,test_result_t("finalizes an intent(out) derived type dummy argument", intent_out()) & |
| ,test_result_t("finalizes an allocatable component object", allocatable_component()) & |
| ] |
| end function |
| |
| function construct_object() result(object) |
| !! Constructor for object_t |
| type(object_t) object |
| object % dummy = avoid_unused_variable_warning |
| end function |
| |
| subroutine count_finalizations(self) |
| !! Destructor for object_t |
| type(object_t), intent(inout) :: self |
| finalizations = finalizations + 1 |
| self % dummy = avoid_unused_variable_warning |
| end subroutine |
| |
| function lhs_object() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 1 behavior: |
| !! "not an unallocated allocatable variable" |
| type(object_t) lhs, rhs |
| logical outcome |
| integer initial_tally |
| |
| rhs%dummy = avoid_unused_variable_warning |
| initial_tally = finalizations |
| lhs = rhs ! finalizes lhs |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| end function |
| |
| function allocated_allocatable_lhs() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 1 behavior: |
| !! "allocated allocatable variable" |
| type(object_t), allocatable :: lhs |
| type(object_t) rhs |
| logical outcome |
| integer initial_tally |
| |
| rhs%dummy = avoid_unused_variable_warning |
| initial_tally = finalizations |
| allocate(lhs) |
| lhs = rhs ! finalizes lhs |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| end function |
| |
| function target_deallocation() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 2 behavior: |
| !! "pointer is deallocated" |
| type(object_t), pointer :: object_ptr => null() |
| logical outcome |
| integer initial_tally |
| |
| allocate(object_ptr, source=object_t(dummy=0)) |
| initial_tally = finalizations |
| deallocate(object_ptr) ! finalizes object |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| end function |
| |
| function allocatable_component() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, para. 2 ("allocatable entity is deallocated") |
| !! + 9.7.3.2, para. 6 ("INTENT(OUT) allocatable dummy argument is deallocated") |
| type(wrapper_t), allocatable :: wrapper |
| logical outcome |
| integer initial_tally |
| |
| initial_tally = finalizations |
| |
| allocate(wrapper) |
| allocate(wrapper%object) |
| call finalize_intent_out_component(wrapper) |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| |
| contains |
| |
| subroutine finalize_intent_out_component(output) |
| type(wrapper_t), intent(out) :: output ! finalizes object component |
| allocate(output%object) |
| output%object%dummy = avoid_unused_variable_warning |
| end subroutine |
| |
| end function |
| |
| function finalize_on_deallocate() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 2: |
| !! "allocatable entity is deallocated" |
| type(object_t), allocatable :: object |
| logical outcome |
| integer initial_tally |
| |
| initial_tally = finalizations |
| allocate(object) |
| object%dummy = 1 |
| deallocate(object) ! finalizes object |
| associate(final_tally => finalizations - initial_tally) |
| outcome = final_tally==1 |
| end associate |
| end function |
| |
| function finalize_on_end() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 3: |
| !! "before return or END statement" |
| logical outcome |
| integer initial_tally |
| |
| initial_tally = finalizations |
| call finalize_on_end_subroutine() ! Finalizes local_obj |
| associate(final_tally => finalizations - initial_tally) |
| outcome = final_tally==1 |
| end associate |
| |
| contains |
| |
| subroutine finalize_on_end_subroutine() |
| type(object_t) local_obj |
| local_obj % dummy = avoid_unused_variable_warning |
| end subroutine |
| |
| end function |
| |
| function block_end() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 4: |
| !! "termination of the BLOCK construct" |
| logical outcome |
| integer initial_tally |
| |
| initial_tally = finalizations |
| block |
| type(object_t) object |
| object % dummy = avoid_unused_variable_warning |
| end block ! Finalizes object |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| end function |
| |
| function rhs_function_reference() result(outcome) |
| !! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 5 behavior: |
| !! "nonpointer function result" |
| type(object_t), allocatable :: object |
| logical outcome |
| integer initial_tally |
| |
| initial_tally = finalizations |
| object = construct_object() ! finalizes object_t result |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| end function |
| |
| function intent_out() result(outcome) |
| !! Test conformance with Fortran 2018 standard clause 7.5.6.3, paragraph 7: |
| !! "nonpointer, nonallocatable, INTENT (OUT) dummy argument" |
| logical outcome |
| type(object_t) object |
| integer initial_tally |
| |
| initial_tally = finalizations |
| call finalize_intent_out_arg(object) |
| associate(finalization_tally => finalizations - initial_tally) |
| outcome = finalization_tally==1 |
| end associate |
| contains |
| subroutine finalize_intent_out_arg(output) |
| type(object_t), intent(out) :: output ! finalizes output |
| output%dummy = avoid_unused_variable_warning |
| end subroutine |
| end function |
| |
| end module test_result_m |
| |
| program main |
| !! Test each scenario in which the Fortran 2018 standard |
| !! requires type finalization. |
| use test_result_m, only : test_result_t, get_test_results |
| implicit none |
| type(test_result_t), allocatable :: test_results(:) |
| integer i |
| |
| test_results = get_test_results() |
| |
| do i=1,size(test_results) |
| print *, report(test_results(i)%outcome), test_results(i)%description |
| end do |
| |
| if (any(.not.test_results%outcome)) stop "Failing tests" |
| |
| if (allocated (test_results)) deallocate (test_results) |
| |
| contains |
| |
| pure function report(outcome) |
| logical, intent(in) :: outcome |
| character(len=:), allocatable :: report |
| report = merge("Pass: ", "Fail: ", outcome) |
| end function |
| |
| end program |