Skip to content

Commit 65b897c

Browse files
zbeekmanTarun Prabhu
authored andcommitted
[Fortran/UnitTests] Add type finalization unit tests
This suite of tests was created originally by Wileam Phan, Damian Rouson, and Brad Richardson as part of the Smart-Pointers library's test suite. The original adaptation for inclusion in the llvm-test-suite can be found here: - https://github.com/BerkeleyLab/llvm-test-suite/tree/damians-fortran-type-finalization SHA: 0268bcf - https://github.com/BerkeleyLab/llvm-test-suite/tree/berkely-lab-damian-v0.1 SHA: 0268bcf The test suite was then adapted to be made appropriate for inclusion in a compiler test suite by Izaak Beekman. A summary of the tests can be found in the README.md file added in the Fortran/UnitTests/finalization subdirectory. Co-Authored-by: Damian Rouson <[email protected]> Differential Revision: https://reviews.llvm.org/D147804
1 parent 2666b1f commit 65b897c

26 files changed

+634
-0
lines changed

Fortran/UnitTests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# This file should only contain add_subdirectory(...) one for each test
22
add_subdirectory(hello)
33
add_subdirectory(fcvs21_f95) # NIST Fortran Compiler Validation Suite
4+
add_subdirectory(finalization)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Configure the file below into the source tree with CMake so that the
2+
# testing infrastructure can find it.
3+
4+
specification_expression_finalization.reference_output
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
include(CheckFortranCompilerFlag)
2+
3+
# LLVMFlang prefixes error stop output to stdout/stderr with "Fortran"
4+
# and other compilers don't.
5+
# The `specification_expression_finalization.f90` test requires
6+
# examining the output of an `error_stop` statement.
7+
# Configure the expected results based on the Fortran compiler in use.
8+
9+
set(MAYBE_LLVM_ERROR_STOP_PREFIX "")
10+
set(MAYBE_LLVM_ERROR_STOP_COLON "")
11+
if(CMAKE_Fortran_COMPILER_ID MATCHES "LLVMFlang")
12+
set(MAYBE_LLVM_ERROR_STOP_PREFIX "Fortran ")
13+
set(MAYBE_LLVM_ERROR_STOP_COLON ":")
14+
endif()
15+
16+
configure_file(
17+
specification_expression_finalization.reference_output.in
18+
${CMAKE_CURRENT_SOURCE_DIR}/specification_expression_finalization.reference_output
19+
@ONLY)
20+
21+
set(Source)
22+
list(APPEND Source
23+
allocatable_component.f90
24+
allocated_allocatable_lhs.f90
25+
block_end.f90
26+
finalize_on_deallocate.f90
27+
finalize_on_end.f90
28+
intent_out.f90
29+
lhs_object.f90
30+
rhs_function_reference.f90
31+
specification_expression_finalization.f90
32+
target_deallocation.f90)
33+
34+
# set(FP_IGNOREWHITESPACE OFF)
35+
36+
llvm_singlesource()
37+
38+
file(COPY lit.local.cfg DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
Finalization Unit Tests
2+
=======================
3+
4+
This suite of tests was created originally by Wileam Phan, Damian Rouson,
5+
and Brad Richardson as part of the
6+
[[ https://github.com/sourceryinstitute/smart-pointers | Smart-Pointers ]]
7+
library's test suite.
8+
All compilers, except for NAG, did not initially have a working/correct
9+
implmentation of finalization.
10+
An all-in-one reproducer test was created to share with compiler
11+
teams that was easy to run (just compile a single file and run it).
12+
This is ideal for reporting bugs to compiler teams,
13+
but not appropriate for inclusion in a compiler test suite.
14+
15+
The original adaptation for inclusion in the llvm-test-suite can be found here:
16+
17+
* https://github.com/BerkeleyLab/llvm-test-suite/tree/damians-fortran-type-finalization
18+
SHA: `0268bcf0048e67cd1280f9ef65aebd2aa402130b`
19+
* https://github.com/BerkeleyLab/llvm-test-suite/tree/berkely-lab-damian-v0.1
20+
SHA: `0268bcf0048e67cd1280f9ef65aebd2aa402130b`
21+
22+
The test suite was then adapted to be made appropriate for inclusion
23+
in a compiler test suite by Izaak Beekman.
24+
Broadly, this required:
25+
26+
- Each test should be broken into in individual file.
27+
- Each test should have a corresponding expected output.
28+
- Use the compilers build system rather than a custom fortran driver program
29+
(relying) on `execute_command_line`.
30+
- The tests should be incorporated following the conventions adopted by the
31+
compiler project.
32+
- The README/documentation should be updated and made appropriate for keeping
33+
in the compiler project's test suite repository.
34+
- e.g., Describe the tests and how to use them
35+
- Don't keep information about what version of which compiler works since
36+
it will get stale quickly and be a maintainance headache.
37+
38+
To run these finalization tests, and only these tests,
39+
first you must build a recent version of llvm flang.
40+
LLVM version d585a8afdf2f70159759dccb11d775cdf432aba4,
41+
from Fri Apr 7 18:12:12 2023 +0000 is known to work.
42+
Newer versions should work as well unless a regression is introduced.
43+
44+
You can setup your directory structure as follows:
45+
46+
```
47+
llvm-project # llvm-project/llvm source code
48+
├── build # Build directory for llvm-project/flang
49+
├── test-suite # llvm-project/llvm-test-suite source code
50+
└── test-suite-build # Build directory for test-suite
51+
```
52+
53+
Flang is built in the `build` subdirectory.
54+
The test-suite-build directory is created by the user
55+
and is initially empty until running CMake for the teset-suite.
56+
To configure, build and run the tests once llvm/flang has been built,
57+
a command similar to the following can be used from within test-suite-build:
58+
59+
``` shell
60+
cmake -DCMAKE_BUILD_TYPE=Release \
61+
-DCMAKE_Fortran_COMPILER:FILEPATH=/home/users/<you>/llvm-project/build/bin/flang-new \
62+
-DCMAKE_Fortran_FLAGS=-flang-experimental-exec \
63+
-DTEST_SUITE_FORTRAN:BOOL=On \
64+
-DTEST_SUITE_SUBDIRS=Fortran/UnitTests/finalization \
65+
../test-suite
66+
make -j 4
67+
../build/bin/llvm-lit Fortran/UnitTests/finalization
68+
```
69+
70+
Summary of Tests
71+
----------------
72+
73+
* [`allocatable_component.f90`]
74+
* Finalizes an allocatable component object on deallocation of an intent out dymmy argument
75+
* Test conformance with Fortran 2018 clause 7.5.6.3, para. 2 ("allocatable entity is deallocated")
76+
+ 9.7.3.2, para. 6 ("INTENT(OUT) allocatable dummy argument is deallocated")
77+
* [`allocated_allocatable_lhs.f90`]
78+
* Finalizes an allocated allocatable LHS of an intrinsic assignment
79+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 1 behavior:
80+
"allocated allocatable variable"
81+
* [`block_end.f90`]
82+
* Finalizes a non-pointer non-allocatable object at the end of a block construct
83+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 4:
84+
"termination of the BLOCK construct"
85+
* [`finalize_on_deallocate.f90`]
86+
* Finalizes an object upon explicit deallocation
87+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 2:
88+
"allocatable entity is deallocated"
89+
* [`finalize_on_end.f90`]
90+
* finalizes a non-pointer non-allocatable object at the END statement
91+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 3:
92+
"before return or END statement"
93+
* [`intent_out.f90`]
94+
* Finalizes an intent(out) derived type dummy argument
95+
* Test conformance with Fortran 2018 standard clause 7.5.6.3, paragraph 7:
96+
"nonpointer, nonallocatable, INTENT (OUT) dummy argument"
97+
* [`lhs_object.f90`]
98+
* Finalizes a non-allocatable object on the LHS of an intrinsic assignment
99+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 1 behavior:
100+
"not an unallocated allocatable variable"
101+
* [`rhs_function_reference.f90`]
102+
* Finalizes a function reference on the RHS of an intrinsic assignment
103+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 5 behavior:
104+
"nonpointer function result"
105+
* [`specification_expression_finalization.f90`]
106+
* Finalizes a function result in a specification expression
107+
* Test compiler conformance with clause 7.5.6.3, paragraph 6 in the Fortran
108+
Interpretation Document (https://j3-fortran.org/doc/year/18/18-007r1.pdf):
109+
"If a specification expression in a scoping unit references
110+
a function, the result is finalized before execution of the executable
111+
constructs in the scoping unit." (The same statement appears in clause
112+
4.5.5.2, paragraph 5 of the Fortran 2003 standard.) In such a scenario,
113+
the final subroutine must be pure. The only way to observe output from
114+
a pure final subroutine is for the subroutine to execute an error stop
115+
statement. A correct execution of this test will error-terminate and ouput
116+
the text "finalize: intentional error termination to verify finalization".
117+
* [`target_deallocation.f90`]
118+
* Finalizes a target when the associated pointer is deallocated
119+
* Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 2 behavior:
120+
"pointer is deallocated"
121+
122+
123+
Common Code
124+
-----------
125+
126+
* [`object_type_m.f90`]
127+
* To reduce code duplication, yet allow each test to be treated by
128+
CMake as a single source file, a small amount of common code is
129+
`include`d from this file by each test file.
130+
* Due to the way CMake handles `.mod` module files, it is important
131+
that each of the test files uses unique module names, otherwise
132+
CMake will encounter a race condition when building in parallel
133+
wherein it might clobber a `.mod` module file or corresponding
134+
timestamp when multiple `.mod` files are being created with the
135+
same name.
136+
* This file contains the main derived type object for testing and the
137+
corresponding final subroutine, `count_finalizations` to verify that
138+
finalization took pace (by counting finalizations in a public module
139+
variable)
140+
141+
[`allocatable_component.f90`]: ./allocatable_component.f90
142+
[`allocated_allocatable_lhs.f90`]: ./allocated_allocatable_lhs.f90
143+
[`block_end.f90`]: ./block_end.f90
144+
[`finalize_on_deallocate.f90`]: ./finalize_on_deallocate.f90
145+
[`finalize_on_end.f90`]: ./finalize_on_end.f90
146+
[`intent_out.f90`]: ./intent_out.f90
147+
[`lhs_object.f90`]: ./lhs_object.f90
148+
[`rhs_function_reference.f90`]: ./rhs_function_reference.f90
149+
[`specification_expression_finalization.f90`]: ./specification_expression_finalization.f90
150+
[`target_deallocation.f90`]: ./target_deallocation.f90
151+
[`object_type_m.f90`]: ./object_type_m.f90
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module allocatable_component_m
2+
include "object_type_m.f90"
3+
4+
function allocatable_component() result(outcome)
5+
!! Test conformance with Fortran 2018 clause 7.5.6.3, para. 2 ("allocatable entity is deallocated")
6+
!! + 9.7.3.2, para. 6 ("INTENT(OUT) allocatable dummy argument is deallocated")
7+
!! finalizes an allocatable component object
8+
type(wrapper_t), allocatable :: wrapper
9+
logical outcome
10+
integer initial_tally
11+
12+
initial_tally = finalizations
13+
14+
allocate(wrapper)
15+
allocate(wrapper%object)
16+
call finalize_intent_out_component(wrapper)
17+
associate(finalization_tally => finalizations - initial_tally)
18+
outcome = finalization_tally==1
19+
end associate
20+
21+
contains
22+
23+
subroutine finalize_intent_out_component(output)
24+
type(wrapper_t), intent(out) :: output ! finalizes object component
25+
allocate(output%object)
26+
output%object%dummy = avoid_unused_variable_warning
27+
end subroutine
28+
29+
end function
30+
31+
end module allocatable_component_m
32+
33+
program main
34+
use allocatable_component_m, only : allocatable_component, report
35+
implicit none
36+
character(len=*), parameter :: description = "finalizes an allocatable component object"
37+
38+
write(*,"(A)") report(allocatable_component()) // description
39+
40+
end program
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Pass: finalizes an allocatable component object
2+
exit 0
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module allocated_allocatable_lhs_m
2+
include "object_type_m.f90"
3+
4+
function allocated_allocatable_lhs() result(outcome)
5+
!! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 1 behavior:
6+
!! "allocated allocatable variable"
7+
!! finalizes an allocated allocatable LHS of an intrinsic assignment
8+
type(object_t), allocatable :: lhs
9+
type(object_t) rhs
10+
logical outcome
11+
integer initial_tally
12+
13+
rhs%dummy = avoid_unused_variable_warning
14+
initial_tally = finalizations
15+
allocate(lhs)
16+
lhs = rhs ! finalizes lhs
17+
associate(finalization_tally => finalizations - initial_tally)
18+
outcome = finalization_tally==1
19+
end associate
20+
end function
21+
22+
end module allocated_allocatable_lhs_m
23+
24+
program main
25+
use allocated_allocatable_lhs_m, only : allocated_allocatable_lhs, report
26+
implicit none
27+
character(len=*), parameter :: description = "finalizes an allocated allocatable LHS of an intrinsic assignment"
28+
29+
write(*,"(A)") report(allocated_allocatable_lhs()) // description
30+
31+
end program
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Pass: finalizes an allocated allocatable LHS of an intrinsic assignment
2+
exit 0
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module block_end_m
2+
include "object_type_m.f90"
3+
4+
function block_end() result(outcome)
5+
!! Test conformance with Fortran 2018 clause 7.5.6.3, paragraph 4:
6+
!! "termination of the BLOCK construct"
7+
!! finalizes a non-pointer non-allocatable object at the end of a block construct
8+
logical outcome
9+
integer initial_tally
10+
11+
initial_tally = finalizations
12+
block
13+
type(object_t) object
14+
object % dummy = avoid_unused_variable_warning
15+
end block ! Finalizes object
16+
associate(finalization_tally => finalizations - initial_tally)
17+
outcome = finalization_tally==1
18+
end associate
19+
end function
20+
21+
end module block_end_m
22+
23+
program main
24+
use block_end_m, only : block_end, report
25+
implicit none
26+
character(len=*), parameter :: description = &
27+
"finalizes a non-pointer non-allocatable object at the end of a block construct"
28+
29+
write(*,"(A)") report(block_end()) // description
30+
31+
end program
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Pass: finalizes a non-pointer non-allocatable object at the end of a block construct
2+
exit 0

0 commit comments

Comments
 (0)