Skip to content

Commit 477158f

Browse files
committed
best to use struct with C_BOOL mismatch to show problem
in case of segfault (e.g. windows oneapi) need this well-known technique for WILL_FAIL
1 parent a67eeb1 commit 477158f

10 files changed

Lines changed: 134 additions & 97 deletions

File tree

src/bool/bad_bool.f90

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
module bad_bool
22

33
use, intrinsic :: iso_c_binding, only : C_INT
4+
use, intrinsic :: iso_fortran_env, only : error_unit
45

56
implicit none
67

8+
integer, parameter :: lk = 8
9+
10+
type, bind(C) :: bool_args
11+
logical(8) :: value
12+
integer(C_INT) :: dummy
13+
end type
14+
715
contains
816

9-
logical function logical_not(L, dummy) bind(C)
10-
logical, intent(in), value :: L
11-
integer(C_INT), intent(in) :: dummy
17+
logical function logical_not(args) bind(C)
18+
type(bool_args), intent(in), value :: args
1219

13-
logical_not = .not. L
20+
logical_not = .not. args%value
1421

15-
print '(/, a, l1, a, l1)', "logical_not(", L, "): ", logical_not
22+
print '(/, a, l1, a, l1)', "logical_not(", args%value, "): ", logical_not
1623

1724
print '(a16,2x,a,2x,a8,2x,a8)', "storage_size()", "bits", "hex(in)", "hex(out)"
18-
print '(a16,2x,i3,2x,z8,2x,z8)', "C_BOOL: ", storage_size(L), L, logical_not
25+
print '(a16,2x,i3,2x,z8,2x,z8)', "C_BOOL: ", storage_size(args%value), args%value, logical_not
1926

20-
if (dummy /= 42_C_INT) error stop "dummy argument should be 42"
27+
if (args%dummy /= 42_C_INT) then
28+
write(error_unit, '(a,i0,a)') "bool_passthru passed dummy argument ", args%dummy, " but expected 42"
29+
error stop
30+
end if
2131

2232
end function logical_not
2333

24-
logical function bool_passthru(L, dummy) bind(C)
25-
logical, intent(in), value :: L
26-
integer(C_INT), intent(in) :: dummy
27-
if (dummy /= 42_C_INT) error stop "dummy argument should be 42"
28-
bool_passthru = L
34+
logical function bool_passthru(args) bind(C)
35+
type(bool_args), intent(in), value :: args
36+
if (args%dummy /= 42_C_INT) then
37+
write(error_unit, '(a,i0,a)') "bool_passthru passed dummy argument ", args%dummy, " but expected 42"
38+
error stop
39+
end if
40+
bool_passthru = args%value
2941
end function bool_passthru
3042

3143

src/bool/logbool.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@
77

88
#include "my_bool.h"
99

10-
bool logical_not(bool a, int* dummy)
10+
bool logical_not(bool_args args)
1111
{
12-
printf("C boolean sizeof(%d) = %zu\n", a, sizeof(a));
13-
if (*dummy != 42) {
14-
fprintf(stderr, "ERROR: dummy argument != 42, but %d\n", *dummy);
12+
printf("C boolean sizeof(%d) = %zu\n", args.value, sizeof(args.value));
13+
if (args.dummy != 42) {
14+
fprintf(stderr, "ERROR: dummy argument != 42, but %d\n", args.dummy);
1515
exit(EXIT_FAILURE);
1616
}
1717

18-
return !a;
18+
return !args.value;
1919
}
2020

21-
bool bool_passthru(bool a, int* dummy)
21+
bool bool_passthru(bool_args args)
2222
{
23-
printf("C boolean sizeof(%d) = %zu\n", a, sizeof(a));
24-
if (*dummy != 42) {
25-
fprintf(stderr, "ERROR: dummy argument != 42, but %d\n", *dummy);
23+
printf("C boolean sizeof(%d) = %zu\n", args.value, sizeof(args.value));
24+
if (args.dummy != 42) {
25+
fprintf(stderr, "ERROR: dummy argument != 42, but %d\n", args.dummy);
2626
exit(EXIT_FAILURE);
2727
}
2828

29-
return a;
29+
return args.value;
3030
}
3131

3232
bool bool_true(){ return true; }

src/bool/logbool.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,26 @@
33

44
#include "my_bool.h"
55

6-
bool logical_not(const bool a, int* dummy)
6+
bool logical_not(const bool_args args)
77
{
8-
std::cout << "C++ boolean sizeof(" << a << ") = " << sizeof(a) << "\n";
9-
if (*dummy != 42) {
10-
std::cerr << "ERROR: dummy argument != 42, but " << *dummy << "\n";
8+
std::cout << "C++ boolean sizeof(" << args.value << ") = " << sizeof(args.value) << "\n";
9+
if (args.dummy != 42) {
10+
std::cerr << "ERROR: dummy argument != 42, but " << args.dummy << "\n";
1111
std::exit(EXIT_FAILURE);
1212
}
1313

14-
return !a;
14+
return !args.value;
1515
}
1616

17-
bool bool_passthru(const bool a, int* dummy)
17+
bool bool_passthru(const bool_args args)
1818
{
19-
std::cout << "C++ boolean sizeof(" << a << ") = " << sizeof(a) << "\n";
20-
if (*dummy != 42) {
21-
std::cerr << "ERROR: dummy argument != 42, but " << *dummy << "\n";
19+
std::cout << "C++ boolean sizeof(" << args.value << ") = " << sizeof(args.value) << "\n";
20+
if (args.dummy != 42) {
21+
std::cerr << "ERROR: dummy argument != 42, but " << args.dummy << "\n";
2222
std::exit(EXIT_FAILURE);
2323
}
2424

25-
return a;
25+
return args.value;
2626
}
2727

2828
bool bool_true(){ return true; }

src/bool/logbool.f90

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
11
module logbool
22

3-
use, intrinsic :: iso_c_binding, only : C_BOOL, C_INT
3+
use, intrinsic :: iso_c_binding
4+
use, intrinsic :: iso_fortran_env
45

56
implicit none
67

7-
contains
8+
type, bind(C) :: bool_args
9+
logical(C_BOOL) :: value
10+
integer(C_INT) :: dummy
11+
end type
812

9-
logical(c_bool) function logical_not(L, dummy) bind(C)
13+
contains
1014

11-
logical(c_bool), intent(in), value :: L
12-
integer(c_int), intent(in) :: dummy
15+
logical(C_BOOL) function logical_not(args) bind(C)
16+
type(bool_args), intent(in), value :: args
1317

14-
logical_not = .not. L
18+
logical_not = .not. args%value
1519

16-
print '(/, a, l1, a, l1)', "logical_not(", L, "): ", logical_not
20+
print '(/, a, l1, a, l1)', "logical_not(", args%value, "): ", logical_not
1721

1822
print '(a16,2x,a,2x,a8,2x,a8)', "storage_size()", "bits", "hex(in)", "hex(out)"
19-
print '(a16,2x,i3,2x,z8,2x,z8)', "C_BOOL: ", storage_size(L), L, logical_not
23+
print '(a16,2x,i3,2x,z8,2x,z8)', "C_BOOL: ", storage_size(args%value), args%value, logical_not
2024

21-
if (dummy /= 42_c_int) error stop "dummy argument should be 42"
22-
! print '(a)', "logical_not passed dummy argument correctly"
25+
if (args%dummy /= 42_C_INT) then
26+
write(error_unit, '(a,i0,a)') "bool_passthru passed dummy argument ", args%dummy, " but expected 42"
27+
error stop
28+
end if
2329

2430
end function logical_not
2531

2632

27-
logical(C_BOOL) function bool_passthru(L, dummy) bind(C)
28-
logical(C_BOOL), intent(in), value :: L
29-
integer(C_INT), intent(in) :: dummy
30-
if (dummy /= 42_C_INT) error stop "dummy argument should be 42"
31-
bool_passthru = L
33+
logical(C_BOOL) function bool_passthru(args) bind(C)
34+
type(bool_args), intent(in), value :: args
35+
if (args%dummy /= 42_C_INT) then
36+
write(error_unit, '(a,i0,a)') "bool_passthru passed dummy argument ", args%dummy, " but expected 42"
37+
error stop
38+
end if
39+
bool_passthru = args%value
3240
end function bool_passthru
3341

3442

@@ -40,4 +48,4 @@ logical(C_BOOL) function bool_false() bind(C)
4048
bool_false = .false._C_BOOL
4149
end function
4250

43-
end module logbool
51+
end module

src/bool/my_bool.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
extern "C" {
33
#endif
44

5-
bool logical_not(const bool, int*);
6-
bool bool_passthru(const bool, int*);
5+
typedef struct bool_args {
6+
bool value;
7+
int dummy;
8+
} bool_args;
9+
10+
bool logical_not(bool_args);
11+
bool bool_passthru(bool_args);
712

813
bool bool_true();
914
bool bool_false();

test/bool/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,18 @@ add_test(NAME Cpp_C_bool COMMAND cxx_c_bool)
3939
add_executable(fortran_c_bad_bool bad_interface.f90)
4040
target_link_libraries(fortran_c_bad_bool PRIVATE bool_c)
4141
set_property(TARGET fortran_c_bad_bool PROPERTY LINKER_LANGUAGE Fortran)
42-
add_test(NAME Fortran_C_bad_bool COMMAND fortran_c_bad_bool)
42+
add_test(NAME Fortran_C_bad_bool COMMAND ${CMAKE_COMMAND} -E env $<TARGET_FILE:fortran_c_bad_bool>)
4343

4444
add_library(bad_bool_fortran OBJECT ${PROJECT_SOURCE_DIR}/src/bool/bad_bool.f90)
4545
target_include_directories(bad_bool_fortran INTERFACE ${PROJECT_SOURCE_DIR}/src/bool)
4646

4747
add_executable(c_fortran_bad_bool main.c)
4848
target_link_libraries(c_fortran_bad_bool PRIVATE bad_bool_fortran)
49-
add_test(NAME C_Fortran_bad_bool COMMAND c_fortran_bad_bool)
49+
add_test(NAME C_Fortran_bad_bool COMMAND ${CMAKE_COMMAND} -E env $<TARGET_FILE:c_fortran_bad_bool>)
5050

5151
add_executable(cxx_fortran_bad_bool main.cpp)
5252
target_link_libraries(cxx_fortran_bad_bool PRIVATE bad_bool_fortran)
53-
add_test(NAME Cpp_Fortran_bad_bool COMMAND cxx_fortran_bad_bool)
53+
add_test(NAME Cpp_Fortran_bad_bool COMMAND ${CMAKE_COMMAND} -E env $<TARGET_FILE:cxx_fortran_bad_bool>)
5454

5555
set_tests_properties(C_Fortran_bad_bool Fortran_C_bad_bool Cpp_Fortran_bad_bool PROPERTIES WILL_FAIL true)
56+
set_target_properties(c_fortran_bool c_fortran_bad_bool PROPERTIES LINKER_LANGUAGE C)

test/bool/bad_interface.f90

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,51 @@ program bad_interface
66

77
implicit none
88

9+
type, bind(C) :: bool_args
10+
logical(8) :: value
11+
integer(C_INT) :: dummy
12+
end type
13+
914
interface
10-
logical(C_BOOL) function logical_not(a, dint) bind(C)
11-
import C_INT, C_BOOL
12-
logical, intent(in), value :: a
13-
integer(C_INT), intent(in) :: dint
15+
logical(C_BOOL) function logical_not(args) bind(C)
16+
import C_BOOL, bool_args
17+
type(bool_args), intent(in), value :: args
1418
end function
1519

16-
logical(C_BOOL) function bool_passthru(a, dint) bind(C)
17-
import C_INT, C_BOOL
18-
logical, intent(in), value :: a
19-
integer(C_INT), intent(in) :: dint
20+
logical(C_BOOL) function bool_passthru(args) bind(C)
21+
import C_BOOL, bool_args
22+
type(bool_args), intent(in), value :: args
2023
end function
2124
end interface
2225

23-
logical :: tc, fc
26+
type(bool_args) :: tc, fc
2427
logical :: t0, f0, t1, f1
2528
!! show there's no warnings
2629

2730
logical :: true_f, false_f
2831

2932
t0 = .true.
3033
f0 = .false.
31-
tc = t0
32-
fc = f0
33-
t1 = tc
34-
f1 = fc
34+
tc%value = t0
35+
tc%dummy = 42_C_INT
36+
fc%value = f0
37+
fc%dummy = 42_C_INT
38+
t1 = tc%value
39+
f1 = fc%value
3540

3641
if (.not. t1) error stop "logical(C_BOOL) .true. should be .true."
3742
if (.not. t1 .eqv. t0) error stop "logical(C_BOOL) .true. should EQV .true."
3843
if (f1) error stop "logical(C_BOOL) .false. should be .false."
3944
if(.not. f1 .eqv. f0) error stop "logical(C_BOOL) .false. should EQV .false."
4045

41-
false_f = logical_not(tc, 42_C_INT)
42-
true_f = logical_not(fc, 42_C_INT)
46+
false_f = logical_not(tc)
47+
true_f = logical_not(fc)
4348

4449
if (false_f) error stop "logical_not(.true.) should be .false."
4550
if (.not. true_f) error stop "logical_not(.false.) should be .true."
4651

47-
false_f = bool_passthru(fc, 42_C_INT)
48-
true_f = bool_passthru(tc, 42_C_INT)
52+
false_f = bool_passthru(fc)
53+
true_f = bool_passthru(tc)
4954

5055
if (false_f) error stop "bool_passthru(.false.) should be .false."
5156
if (.not. true_f) error stop "bool_passthru(.true.) should be .true."

test/bool/main.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ if(b){
2424
c++;
2525
}
2626

27-
// pass a pointer to int with value 42 to check that the Fortran function receives it correctly
28-
int dummy = 42;
27+
bool_args args = { true, 42 };
2928

30-
b = logical_not(true, &dummy);
29+
b = logical_not(args);
3130
if(b) {
3231
fprintf(stderr, "logical_not(true) should be false: %d\n", b);
3332
c++;
3433
}
3534

36-
b = logical_not(false, &dummy);
35+
args.value = false;
36+
b = logical_not(args);
3737
if (!b) {
3838
fprintf(stderr, "logical_not(false) should be true: %d\n", b);
3939
c++;

test/bool/main.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,31 @@ if(b){
2121
c++;
2222
}
2323

24-
// pass a pointer to int with value 42 to check that the Fortran function receives it correctly
25-
int dummy = 42;
24+
bool_args args{true, 42};
2625

27-
b = logical_not(true, &dummy);
26+
b = logical_not(args);
2827

2928
if(b){
3029
std::cerr << "logical_not(true) failed: " << b << "\n";
3130
c++;
3231
}
3332

34-
b = logical_not(false, &dummy);
33+
args.value = false;
34+
b = logical_not(args);
3535

3636
if (!b){
3737
std::cerr << "logical_not(false) failed: " << b << "\n";
3838
c++;
3939
}
4040

41-
b = bool_passthru(false, &dummy);
41+
b = bool_passthru(args);
4242
if(b){
4343
std::cerr << "bool_passthru(false) failed: " << b << "\n";
4444
c++;
4545
}
4646

47-
b = bool_passthru(true, &dummy);
47+
args.value = true;
48+
b = bool_passthru(args);
4849
if(!b){
4950
std::cerr << "bool_passthru(true) failed: " << b << "\n";
5051
c++;

0 commit comments

Comments
 (0)