Skip to content

Commit 59c3e7a

Browse files
author
Damian Rouson
committed
Add assertion utility.
Build instructions ------------------ FC=caf cmake <path-to-icar-source-dir> -DNO_ASSERTIONS=ON Conditioning an assertion call on the value of NO_ASSERTIONS enables optimizing compilers to eliminate the assertion via dead-code-removal optimization. Use case 1 ---------- Pass the optional "success" argument & check success without error-terminating on failure: use assertions_interface, only : assert,assertions if (assertions) call assert( 2 > 1, "always true inequality", success) if (error_code/=0) call my_error_handler() Use case 2 ---------- Don't pass the "success" argument and therefore error-terminate upon assertion failure: use assertions_interface, only : assert,assertions if (assertions) call assert( 2 > 1, "always true inequality") Improve comment clarity.
1 parent 003efcb commit 59c3e7a

File tree

5 files changed

+211
-4
lines changed

5 files changed

+211
-4
lines changed

src/tests/CMakeLists.txt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ if (HIGH_RESOLUTION_TIMER)
1515
)
1616
endif()
1717

18-
add_subdirectory(integration)
19-
add_subdirectory(unit)
20-
add_subdirectory(installation)
21-
add_subdirectory(regression)
18+
set( directory_list
19+
utilities
20+
integration
21+
unit
22+
installation
23+
regression
24+
)
25+
foreach(directory ${directory_list})
26+
add_subdirectory(${directory})
27+
endforeach()

src/tests/utilities/CMakeLists.txt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Check support Fortran 2018 error termination in a pure procedure
2+
check_fortran_source_compiles("
3+
program main
4+
contains
5+
pure subroutine foo()
6+
error stop
7+
end subroutine
8+
end program
9+
"
10+
HAVE_ERROR_STOP_IN_PURE
11+
SRC_EXT ".f90"
12+
)
13+
if(HAVE_ERROR_STOP_IN_PURE)
14+
add_definitions(-DHAVE_ERROR_STOP_IN_PURE)
15+
endif()
16+
17+
# Check support Fortran 2018 variable stop code
18+
check_fortran_source_compiles("
19+
program main
20+
integer i
21+
i = 0
22+
error stop i
23+
end program
24+
"
25+
HAVE_VARIABLE_STOP_CODE
26+
SRC_EXT ".f90")
27+
if(HAVE_VARIABLE_STOP_CODE)
28+
add_definitions(-DHAVE_VARIABLE_STOP_CODE)
29+
endif()
30+
31+
#Toggle C preprocessor macro for turning assertions on or off
32+
if(NO_ASSERTIONS)
33+
set_source_files_properties(assertions_interface.f90 PROPERTIES COMPILE_FLAGS "-cpp -DUSE_ASSERTIONS=.false.")
34+
else()
35+
set_source_files_properties(assertions_interface.f90 PROPERTIES COMPILE_FLAGS "-cpp -DUSE_ASSERTIONS=.true.")
36+
endif()
37+
38+
add_library( OpenCoarraysTestUtilities
39+
object_interface.f90
40+
assertions_interface.F90
41+
assertions_implementation.F90
42+
)
43+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
submodule(assertions_interface) assertions_implementation
2+
!! Define the assert procedure
3+
4+
implicit none
5+
6+
contains
7+
8+
module procedure assert
9+
10+
character(len=:), allocatable :: message
11+
12+
if (present(success)) success=assertion
13+
14+
if (.not.assertion) then
15+
16+
call set(message)
17+
if (present(error_message)) error_message = message
18+
19+
if (.not. present(success)) then
20+
#ifdef HAVE_VARIABLE_STOP_CODE
21+
error stop message
22+
#else
23+
error stop "Assertion failed."
24+
#endif
25+
end if
26+
end if
27+
28+
contains
29+
30+
pure subroutine set(msg)
31+
32+
use object_interface, only : object
33+
!! import abstract type with generic binding supporting user-defined derived type output
34+
35+
character(len=:), intent(out), allocatable :: msg
36+
integer, parameter :: max_image_num_digits=12, max_diagnostic_length=1024
37+
integer, parameter :: msg_len = max_diagnostic_length + max_diagnostic_length
38+
39+
associate( base_msg_len=> len("Assertion '") +len_trim(adjustl(description)) +len("' failed on image ") +max_image_num_digits)
40+
allocate( character(len=msg_len) :: msg )
41+
write(msg,*) "Assertion '",trim(adjustl(description)),"' failed on image ",this_image()
42+
end associate
43+
44+
if (present(diagnostic_data)) then
45+
block
46+
!! append diagnostic string
47+
character(len=max_diagnostic_length) diagnostic_string
48+
49+
select type(diagnostic_data)
50+
type is(character(len=*))
51+
diagnostic_string = diagnostic_data
52+
type is(real)
53+
write(diagnostic_string,*) diagnostic_data
54+
type is(integer)
55+
write(diagnostic_string,*) diagnostic_data
56+
class is(object)
57+
write(diagnostic_string,*) diagnostic_data
58+
class default
59+
diagnostic_string = "of unrecognized type"
60+
end select
61+
62+
msg = trim(adjustl(msg)) // " with diagnostic data " // trim(adjustl(diagnostic_string))
63+
end block
64+
end if
65+
66+
end subroutine
67+
68+
end procedure
69+
70+
end submodule
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#ifndef USE_ASSERTIONS
2+
# define USE_ASSERTIONS .false.
3+
#endif
4+
module assertions_interface
5+
!! author: Damian Rouson
6+
!!
7+
!! Utility for runtime checking of logical assertions.
8+
!!
9+
!! Instructions
10+
!! ------------
11+
!! Compile with -DUSE_ASSERTIONS=.false. to define the logical parameter named "assertions" and to thereby
12+
!! facilitate the elimination of assertions during the dead-code removal phase of optimizing compilers:
13+
!!
14+
!! gfortran -cpp -DUSE_ASSERTIONS=.false. -c assertions_interface.f90
15+
!!
16+
!! or set the corresponding NO_ASSERTIONS variable defined in this directory's CMakeLists.txt:
17+
!!
18+
!! FC=caf cmake <opencoarrays-source-path> -DNO_ASSERTIONS=ON
19+
!!
20+
!! Conditioning assertion calls on the "assertions" compile-time constant enables optimizing compilers
21+
!! to eliminate assertion calls via dead-code-removal optimiztion.
22+
!!
23+
!! Use case 1
24+
!! ----------
25+
!! Pass the optional success argument & check for false return value as an indication of assertion failure:
26+
!!
27+
!! use assertions_interface, only : assert,assertions
28+
!! if (assertions) call assert( 2 > 1, "always true inequality", success)
29+
!! if (error_code/=0) call my_error_handler()
30+
!!
31+
!! Use case 2
32+
!! ----------
33+
!! Error-terminate if the assertion fails:
34+
!!
35+
!! use assertions_interface, only : assert,assertions
36+
!! if (assertions) call assert( 2 > 1, "always true inequality")
37+
!!
38+
implicit none
39+
private
40+
public :: assert
41+
public :: assertions
42+
43+
logical, parameter :: assertions=USE_ASSERTIONS
44+
45+
interface
46+
#ifdef HAVE_ERROR_STOP_IN_PURE
47+
pure &
48+
#endif
49+
module subroutine assert(assertion,description,diagnostic_data,success,error_message)
50+
!! On false assertion, error-terminate or, if present(success), copy assertion into success
51+
implicit none
52+
logical, intent(in) :: assertion
53+
!! Most assertions will be expressions, e.g., call assert( i>0, "positive i")
54+
character(len=*), intent(in) :: description
55+
!! Brief statement of what is being asserted
56+
class(*), intent(in), optional :: diagnostic_data
57+
!! Optional data to printed or added to error_message assertion evaluates to .false.
58+
logical, intent(out), optional :: success
59+
!! Optional copy of the assertion dummy argument
60+
character(len=:), intent(out), optional, allocatable :: error_message
61+
!! Optional informational message allocated only if assertion==.false. .and. present(success)
62+
end subroutine
63+
end interface
64+
end module
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module object_interface
2+
!! Object pattern abstract type to provide a universal interface to a userd-defined derived type ouptput
3+
!! capability specified in a generic binding
4+
implicit none
5+
6+
type, abstract :: object
7+
contains
8+
procedure(write_formatted_interface), deferred :: write_formatted
9+
generic :: write(formatted) => write_formatted
10+
end type
11+
12+
abstract interface
13+
subroutine write_formatted_interface(this,unit,iotype,vlist,iostat,iomsg)
14+
import object
15+
class(object), intent(in) :: this
16+
integer, intent(in) :: unit
17+
character (len=*), intent(in) :: iotype
18+
integer, intent(in) :: vlist(:)
19+
integer, intent(out) :: iostat
20+
character (len=*), intent(inout) :: iomsg
21+
end subroutine
22+
end interface
23+
24+
end module

0 commit comments

Comments
 (0)