diff --git a/README.md b/README.md index 7cb82d8..cb0c5a8 100644 --- a/README.md +++ b/README.md @@ -178,39 +178,42 @@ In the case of gfortran, this appears to have been resolved by default starting #### Line breaks in macro invocations -As mentioned above, preprocessor macro invocations are always expanded to a -single line, no matter how many lines were used by the invocation. This means -it's problematic to invoke the `call_assert*` macros with code like the -following: +The preprocessor is not currently specified by any Fortran standard, and +as of 2024 its operation differs in subtle ways between compilers. +One way in which compilers differ is how macro invocations can safely be broken +across multiple lines. + +For example, gfortran and flang-new both accept backslash `\` continuation +character for line-breaks in a macro invocation: ```fortran -! INCORRECT: don't use & line continuations! -call_assert_diagnose( computed_checksum == expected_checksum, & - "Checksum mismatch failure!", & +! OK for flang-new and gfortran +call_assert_diagnose( computed_checksum == expected_checksum, \ + "Checksum mismatch failure!", \ expected_checksum ) ``` -When the preprocessor expands the macro invocation above, the `&` characters -above are not interpreted as Fortran line continuations. Instead they are -inserted into the middle of the single-line macro expansion, where they will -(likely) create a confusing syntax error. -Instead when breaking long lines in a macro invocation, just break the line (no -continuation character!), eg: +Whereas Cray Fortran wants `&` line continuation characters, even inside +a macro invocation: ```fortran -! When breaking a line in a macro invocation, use backslash `\` continuation character: -call_assert_diagnose( computed_checksum == expected_checksum, \ - "Checksum mismatch failure!", \ +! OK for Cray Fortran +call_assert_diagnose( computed_checksum == expected_checksum, & + "Checksum mismatch failure!", & expected_checksum ) ``` +There appears to be no syntax acceptable to all compilers, so when writing +portable code it's probably best to avoid line breaks inside a macro invocation. + + #### Comments in macro invocations Fortran does not support comments with an end delimiter, -only to-end-of-line comments. As such, there is no way to safely insert a +only to-end-of-line comments. As such, there is no portable way to safely insert a Fortran comment into the middle of a macro invocation. For example, the following seemingly reasonable code results in a syntax error -after macro expansion: +after macro expansion (on gfortran and flang-new): ```fortran ! INCORRECT: cannot use Fortran comments inside macro invocation @@ -220,7 +223,7 @@ call_assert_diagnose( computed_checksum == expected_checksum, ! ensured since ve ``` Depending on your compiler it *might* be possible to use a C-style block -comment (because they are removed by the preprocessor), for example with +comment (because they are often removed by the preprocessor), for example with gfortran one can instead write the following: ```fortran diff --git a/include/assert_macros.h b/include/assert_macros.h index f53bb81..f5cf4db 100644 --- a/include/assert_macros.h +++ b/include/assert_macros.h @@ -14,7 +14,7 @@ ! Deal with stringification issues: ! https://gcc.gnu.org/legacy-ml/fortran/2009-06/msg00131.html #ifndef STRINGIFY -# ifdef __GFORTRAN__ +# if defined(__GFORTRAN__) || defined(_CRAYFTN) # define STRINGIFY(x) "x" # else # define STRINGIFY(x) #x diff --git a/test/test-assert-macro.F90 b/test/test-assert-macro.F90 index 7384141..62372ca 100644 --- a/test/test-assert-macro.F90 +++ b/test/test-assert-macro.F90 @@ -44,6 +44,18 @@ program test_assert_macros block integer :: computed_checksum = 37, expected_checksum = 37 +#if defined(_CRAYFTN) + ! Cray Fortran uses different line continuations in macro invocations + call_assert_diagnose( computed_checksum == expected_checksum, & + "Checksum mismatch failure!", & + expected_checksum ) + print *," passes with macro-style line breaks" + + call_assert_diagnose( computed_checksum == expected_checksum, & ! ensured since version 3.14 + "Checksum mismatch failure!", & ! TODO: write a better message here + computed_checksum ) + print *," passes with C block comments embedded in macro" +#else call_assert_diagnose( computed_checksum == expected_checksum, \ "Checksum mismatch failure!", \ expected_checksum ) @@ -53,6 +65,7 @@ program test_assert_macros "Checksum mismatch failure!", /* TODO: write a better message here */ \ computed_checksum ) print *," passes with C block comments embedded in macro" +#endif end block