From d5345dedc5494a4433bc17e04aa6314acf220a35 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Sun, 13 Sep 2026 20:06:56 -0700 Subject: [PATCH 1/9] Remove ASSERT_PARALLEL_CALLBACKS knob The ASSERT_PARALLEL_CALLBACKS knob was causing undesirable ABI breakage in projects where multiple components were using Assert compiled with or without ASSERT_PARALLEL_CALLBACKS. ASSERT_PARALLEL_CALLBACKS support is now always compiled-in, and is enabled dynamically based on whether the callbacks are set by the client. Drop support for LFortran 0.54 that fails to compile this feature, our LFortran floor version is now 0.55 --- .github/workflows/build.yml | 12 ++---- README.md | 3 -- example/false-assertion.F90 | 9 ++--- include/assert_features.h | 5 --- src/assert_m.F90 | 76 +++++++++++++++++-------------------- 5 files changed, 41 insertions(+), 64 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4279288..ffdd9a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,13 +143,8 @@ jobs: # https://hub.docker.com/r/phhargrove/lfortran/tags - os: ubuntu-24.04 compiler: lfortran - version: 0.54.0 - container: phhargrove/lfortran:0.54.0-1 - -# - os: ubuntu-24.04 -# compiler: lfortran -# version: 0.55.0 -# container: phhargrove/lfortran:0.55.0-1 + version: 0.55.0 + container: phhargrove/lfortran:0.55.0-1 # # - os: ubuntu-24.04 # compiler: lfortran @@ -362,9 +357,8 @@ jobs: ( set +e ; eval fpm run --example invoke-via-macro ${FPM_FLAGS} --flag \"$FFLAGS\" $CHECK_ASSERT ) - name: Test Assertions w/ Parallel Callbacks - if: ${{ matrix.compiler != 'lfortran' || matrix.version != '0.54.0' }} # issue #68, fixed in 0.55 env: - FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERT_MULTI_IMAGE --flag -DASSERT_PARALLEL_CALLBACKS + FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERT_MULTI_IMAGE --flag -DTEST_PARALLEL_CALLBACKS run: | fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" diff --git a/README.md b/README.md index 79ed46d..b8a0ea0 100644 --- a/README.md +++ b/README.md @@ -101,9 +101,6 @@ using syntax like: `fpm --flag "-DASSERTIONS=1"` The default is compiler-specific. Multi-image support can be disabled using `-DASSERT_MULTI_IMAGE=0`. -* `ASSERT_PARALLEL_CALLBACKS`: Controls the use of a callback interface for - multi-process features. Contact us for more details. - ### Cray Compiler Environment (CCE) `ftn` Because `fpm` uses the compiler name to determine the compiler identity and because CCE provides one compiler wrapper, `ftn`, for invoking all compilers, you will diff --git a/example/false-assertion.F90 b/example/false-assertion.F90 index f8e8e86..1da3c0f 100644 --- a/example/false-assertion.F90 +++ b/example/false-assertion.F90 @@ -2,22 +2,21 @@ program false_assertion use assert_m implicit none -#if ASSERT_PARALLEL_CALLBACKS +#if TEST_PARALLEL_CALLBACKS assert_this_image => assert_callback_this_image assert_error_stop => assert_callback_error_stop #endif call assert(.false., "false-assertion: unconditionally failing test") -#if ASSERT_PARALLEL_CALLBACKS +#if TEST_PARALLEL_CALLBACKS ! By default, assert uses `THIS_IMAGE()` in multi-image mode while ! composing assertion output, and invokes `ERROR STOP` to print the ! assertion and terminate execution. ! -! The ASSERT_PARALLEL_CALLBACKS preprocessor flag enables the client to replace +! The parallel callbacks features enables the client to replace ! the default use of these two Fortran features with client-provided callbacks. -! To use this feature, the client must build the library with `-DASSERT_PARALLEL_CALLBACKS`, -! and then at startup set the `assert_this_image` and `assert_error_stop` +! To use this feature, the client must ! set the `assert_this_image` and `assert_error_stop` ! procedure pointers to reference the desired callbacks. contains diff --git a/include/assert_features.h b/include/assert_features.h index f5bd4e5..9583595 100644 --- a/include/assert_features.h +++ b/include/assert_features.h @@ -11,9 +11,4 @@ # endif #endif -! Whether the library should use client callbacks for parallel features -#ifndef ASSERT_PARALLEL_CALLBACKS -#define ASSERT_PARALLEL_CALLBACKS 0 -#endif - #endif diff --git a/src/assert_m.F90 b/src/assert_m.F90 index 05f2097..d5cac2e 100644 --- a/src/assert_m.F90 +++ b/src/assert_m.F90 @@ -37,27 +37,25 @@ module assert_m private public :: assert, assert_always -#if ASSERT_PARALLEL_CALLBACKS - public :: assert_this_image_interface, assert_this_image - public :: assert_error_stop_interface, assert_error_stop - - abstract interface - pure function assert_this_image_interface() result(this_image_id) - implicit none - integer :: this_image_id - end function - end interface - procedure(assert_this_image_interface), pointer :: assert_this_image - - abstract interface - pure subroutine assert_error_stop_interface(stop_code_char) - implicit none - character(len=*), intent(in) :: stop_code_char - end subroutine - end interface - procedure(assert_error_stop_interface), pointer :: assert_error_stop + ! Parallel callbacks support + public :: assert_this_image_interface, assert_this_image + public :: assert_error_stop_interface, assert_error_stop -#endif + abstract interface + pure function assert_this_image_interface() result(this_image_id) + implicit none + integer :: this_image_id + end function + end interface + procedure(assert_this_image_interface), pointer :: assert_this_image + + abstract interface + pure subroutine assert_error_stop_interface(stop_code_char) + implicit none + character(len=*), intent(in) :: stop_code_char + end subroutine + end interface + procedure(assert_error_stop_interface), pointer :: assert_error_stop #ifndef USE_ASSERTIONS # if ASSERTIONS @@ -120,33 +118,27 @@ pure subroutine assert_always(assertion, description, file, line) end if end if -#if ASSERT_MULTI_IMAGE -# if ASSERT_PARALLEL_CALLBACKS - if (associated(assert_this_image)) then - me = assert_this_image() +# if ASSERT_MULTI_IMAGE + me = this_image() +# else + me = 0 +# endif + if (associated(assert_this_image)) then + me = assert_this_image() + end if + if (me > 0) then + block + character(len=128) image_number + write(image_number, *) me + message = 'Assertion failure on image ' // trim(adjustl(image_number)) // location // ': ' // description + end block else - me = 0 + message = 'Assertion failure' // location // ': ' // description end if -# else - me = this_image() -# endif - block - character(len=128) image_number - write(image_number, *) me - message = 'Assertion failure on image ' // trim(adjustl(image_number)) // location // ': ' // description - end block -#else - message = 'Assertion failure' // location // ': ' // description - me = 0 ! avoid a harmless warning -#endif -#if ASSERT_PARALLEL_CALLBACKS - if (associated(assert_this_image)) then + if (associated(assert_error_stop)) then call assert_error_stop(message) - else - ; ! deliberate fall-thru end if -#endif #ifdef __LFORTRAN__ ! workaround a defect observed in LFortran 0.54: ! error stop with an allocatable character argument prints garbage From 9a63ee694eeafdc1f5ed7c6be9543e7880ee58fc Mon Sep 17 00:00:00 2001 From: bonachea Date: Mon, 14 Sep 2026 10:33:59 -0700 Subject: [PATCH 2/9] Parallel callbacks: Ensure the procedure pointers are initialized Module save procedure pointers initially have undefined association status, and we were incorrectly relying on equivalence to unassociated. This was causing crashes on NAG. --- src/assert_m.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assert_m.F90 b/src/assert_m.F90 index d5cac2e..cebc599 100644 --- a/src/assert_m.F90 +++ b/src/assert_m.F90 @@ -47,7 +47,7 @@ pure function assert_this_image_interface() result(this_image_id) integer :: this_image_id end function end interface - procedure(assert_this_image_interface), pointer :: assert_this_image + procedure(assert_this_image_interface), pointer :: assert_this_image => null() abstract interface pure subroutine assert_error_stop_interface(stop_code_char) @@ -55,7 +55,7 @@ pure subroutine assert_error_stop_interface(stop_code_char) character(len=*), intent(in) :: stop_code_char end subroutine end interface - procedure(assert_error_stop_interface), pointer :: assert_error_stop + procedure(assert_error_stop_interface), pointer :: assert_error_stop => null() #ifndef USE_ASSERTIONS # if ASSERTIONS From d6ca5034265db09a8c44396596c97114bbf84a0f Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Sun, 13 Sep 2026 20:08:53 -0700 Subject: [PATCH 3/9] Change ASSERT_MULTI_IMAGE default to always disabled Most compilers require a command-line option to enable this_image(), and many are already smart enough to include the image number in non-quiet error stop output during a multi-image run, without any help from us. --- .github/workflows/build.yml | 13 ++++++++++++- README.md | 19 +++++++++---------- include/assert_features.h | 8 ++------ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffdd9a4..5729635 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -358,9 +358,20 @@ jobs: - name: Test Assertions w/ Parallel Callbacks env: - FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERT_MULTI_IMAGE --flag -DTEST_PARALLEL_CALLBACKS + FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DTEST_PARALLEL_CALLBACKS run: | fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" ( set +e ; eval fpm run --example false-assertion ${FPM_FLAGS} --flag \"$FFLAGS\" $CHECK_ASSERT ) ( set +e ; eval fpm run --example invoke-via-macro ${FPM_FLAGS} --flag \"$FFLAGS\" $CHECK_ASSERT ) + + - name: Test Assertions w/ ASSERT_MULTI_IMAGE + if: matrix.compiler == 'gfortran' + env: + FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -fcoarray=single --flag -DASSERT_MULTI_IMAGE + run: | + fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" + fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" + ( set +e ; eval fpm run --example false-assertion ${FPM_FLAGS} --flag \"$FFLAGS\" $CHECK_ASSERT ) + ( set +e ; eval fpm run --example invoke-via-macro ${FPM_FLAGS} --flag \"$FFLAGS\" $CHECK_ASSERT ) + diff --git a/README.md b/README.md index b8a0ea0..d69a829 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,7 @@ using syntax like: `fpm --flag "-DASSERTIONS=1"` * `ASSERT_MULTI_IMAGE`: Controls whether the library attempts to use multi-image Fortran features (e.g. to report the image number of an assertion failure). - The default is compiler-specific. Multi-image support can be disabled using - `-DASSERT_MULTI_IMAGE=0`. + Default is disabled, multi-image support can be enabled using `-DASSERT_MULTI_IMAGE`. ### Cray Compiler Environment (CCE) `ftn` Because `fpm` uses the compiler name to determine the compiler identity and because @@ -133,11 +132,11 @@ The above commands build the Assert library (with the default of assertion enfor #### Multi-image (parallel) execution With `gfortran` 14 or later versions and OpenCoarrays installed, use ``` -fpm test --compiler caf --profile release --runner "cafrun -n 2" +fpm test --compiler caf --profile release --runner "cafrun -n 2" --flag -DASSERT_MULTI_IMAGE ``` With `gfortran` 13 or earlier versions and OpenCoarrays installed, ``` -fpm test --compiler caf --profile release --runner "cafrun -n 2" --flag "-ffree-line-length-0" +fpm test --compiler caf --profile release --runner "cafrun -n 2" --flag "-DASSERT_MULTI_IMAGE -ffree-line-length-0" ``` ### Intel `ifx` @@ -153,16 +152,16 @@ With Intel Fortran and Intel MPI installed, fpm test --compiler ifx --profile release --flag "-coarray -DASSERT_MULTI_IMAGE" ``` -### LLVM `flang-new` +### LLVM `flang` #### Single-image (serial) execution -With `flang-new` version 19, use +With LLVM Flang version 19, use ``` fpm test --compiler flang-new --flag "-mmlir -allow-assumed-rank -O3" ``` -With `flang-new` version 20 or later, use +With LLVM Flang version 20 or later, use ``` -fpm test --compiler flang-new --flag "-O3" +fpm test --compiler flang --flag "-O3" ``` ### LFortran `lfortran` @@ -183,11 +182,11 @@ fpm test --compiler nagfor --flag -fpp #### Multi-image execution With `nagfor` 7.1, use ``` -fpm test --compiler nagfor --profile release --flag "-fpp -coarray=cosmp -f2018" +fpm test --compiler nagfor --profile release --flag "-fpp -coarray=cosmp -f2018 -DASSERT_MULTI_IMAGE" ``` With `nagfor` 7.2 or later, use ``` -fpm test --compiler nagfor --flag -fpp +fpm test --compiler nagfor --flag "-fpp -DASSERT_MULTI_IMAGE" ``` Documentation diff --git a/include/assert_features.h b/include/assert_features.h index 9583595..05a8538 100644 --- a/include/assert_features.h +++ b/include/assert_features.h @@ -2,13 +2,9 @@ #define _ASSERT_FEATURES_H ! Whether or not the assert library may use multi-image features -! Default is compiler-dependent +! Disabled by default since many compilers require extra arguments to enable multi-image features #ifndef ASSERT_MULTI_IMAGE -# if defined(__flang__) || defined(__INTEL_COMPILER) || defined(__LFORTRAN__) -# define ASSERT_MULTI_IMAGE 0 -# else -# define ASSERT_MULTI_IMAGE 1 -# endif +#define ASSERT_MULTI_IMAGE 0 #endif #endif From 5bae74035683179125d3bcfc607d8ee3daaf300f Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Mon, 14 Sep 2026 08:11:48 -0700 Subject: [PATCH 4/9] Reformat code whitespacing There are zero code changes in this commit, just whitespace adjustment. --- src/assert_m.F90 | 102 +++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/assert_m.F90 b/src/assert_m.F90 index cebc599..cdeac0d 100644 --- a/src/assert_m.F90 +++ b/src/assert_m.F90 @@ -69,14 +69,14 @@ pure subroutine assert_error_stop_interface(stop_code_char) contains - pure subroutine assert(assertion, description) - !! If assertion is .false. and enforcement is enabled (e.g. via -DASSERTIONS=1), - !! then error-terminate with a character stop code that contains the description argument if present - implicit none - logical, intent(in) :: assertion - !! Most assertions will be expressions such as i>0 - character(len=*), intent(in) :: description - !! A brief statement of what is being asserted such as "i>0" or "positive i" + pure subroutine assert(assertion, description) + !! If assertion is .false. and enforcement is enabled (e.g. via -DASSERTIONS=1), + !! then error-terminate with a character stop code that contains the description argument if present + implicit none + logical, intent(in) :: assertion + !! Most assertions will be expressions such as i>0 + character(len=*), intent(in) :: description + !! A brief statement of what is being asserted such as "i>0" or "positive i" toggle_assertions: & if (enforce_assertions) then @@ -85,38 +85,38 @@ pure subroutine assert(assertion, description) end subroutine - pure subroutine assert_always(assertion, description, file, line) - !! Same as above but always enforces the assertion (regardless of ASSERTIONS) - implicit none - logical, intent(in) :: assertion - character(len=*), intent(in) :: description - character(len=*), intent(in), optional :: file - integer, intent(in), optional :: line + pure subroutine assert_always(assertion, description, file, line) + !! Same as above but always enforces the assertion (regardless of ASSERTIONS) + implicit none + logical, intent(in) :: assertion + character(len=*), intent(in) :: description + character(len=*), intent(in), optional :: file + integer, intent(in), optional :: line + character(len=:), allocatable :: message character(len=:), allocatable :: location integer me - check_assertion: & - if (.not. assertion) then - ! Avoid harmless warnings from Cray Fortran: - allocate(character(len=0)::message) - allocate(character(len=0)::location) - - - ! format source location, if known - location = '' - if (present(file)) then - location = ' at ' // file // ':' - if (present(line)) then ! only print line number if file is also known - block - character(len=128) line_str - write(line_str, '(i0)') line - location = location // trim(adjustl(line_str)) - end block - else - location = location // '' - end if + check_assertion: & + if (.not. assertion) then + ! Avoid harmless warnings from Cray Fortran: + allocate(character(len=0)::message) + allocate(character(len=0)::location) + + ! format source location, if known + location = '' + if (present(file)) then + location = ' at ' // file // ':' + if (present(line)) then ! only print line number if file is also known + block + character(len=128) line_str + write(line_str, '(i0)') line + location = location // trim(adjustl(line_str)) + end block + else + location = location // '' end if + end if # if ASSERT_MULTI_IMAGE me = this_image() @@ -130,27 +130,27 @@ pure subroutine assert_always(assertion, description, file, line) block character(len=128) image_number write(image_number, *) me - message = 'Assertion failure on image ' // trim(adjustl(image_number)) // location // ': ' // description + message = 'Assertion failure on image ' // trim(adjustl(image_number)) & + // location // ': ' // description end block - else - message = 'Assertion failure' // location // ': ' // description - end if - - if (associated(assert_error_stop)) then - call assert_error_stop(message) - end if + else + message = 'Assertion failure' // location // ': ' // description + end if + + if (associated(assert_error_stop)) then + call assert_error_stop(message) + end if #ifdef __LFORTRAN__ - ! workaround a defect observed in LFortran 0.54: - ! error stop with an allocatable character argument prints garbage - error stop message//'', QUIET=.false. + ! workaround a defect observed in LFortran 0.54: + ! error stop with an allocatable character argument prints garbage + error stop message//'', QUIET=.false. #elif __GNUC__ && __GNUC__ < 12 - ! old GFortran lacks the QUIET optional arg added in F2018 - error stop message + ! old GFortran lacks the QUIET optional arg added in F2018 + error stop message #else - error stop message, QUIET=.false. + error stop message, QUIET=.false. #endif - - end if check_assertion + end if check_assertion end subroutine From 49d67384b20acafa726b1c949f28c26e0577053e Mon Sep 17 00:00:00 2001 From: bonachea Date: Mon, 14 Sep 2026 10:32:47 -0700 Subject: [PATCH 5/9] README: Update NAG instructions Based on testing on Linux/X64 with NAG 7.1.7114 and 7.2.7251 --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d69a829..697874d 100644 --- a/README.md +++ b/README.md @@ -176,17 +176,13 @@ fpm test --compiler lfortran --profile release --flag --cpp #### Single-image (serial) execution With `nagfor` version 7.1 or later, use ``` -fpm test --compiler nagfor --flag -fpp +fpm test --compiler nagfor -DASSERTIONS ``` #### Multi-image execution -With `nagfor` 7.1, use +With `nagfor` 7.1 or later, use ``` -fpm test --compiler nagfor --profile release --flag "-fpp -coarray=cosmp -f2018 -DASSERT_MULTI_IMAGE" -``` -With `nagfor` 7.2 or later, use -``` -fpm test --compiler nagfor --flag "-fpp -DASSERT_MULTI_IMAGE" +fpm test --compiler nagfor --flag -DASSERT_MULTI_IMAGE ``` Documentation From c4ad64c4a88b0a77b80eeebaf0f64ee0b217fc0a Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Sun, 13 Sep 2026 20:45:02 -0700 Subject: [PATCH 6/9] CI: Add LFortran 0.66 Remove redundant 0.63 run --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5729635..bf63d54 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -181,11 +181,6 @@ jobs: version: 0.62.0 container: phhargrove/lfortran:0.62.0-1 - - os: ubuntu-24.04 - compiler: lfortran - version: 0.63.0 - container: phhargrove/lfortran:0.63.0-1 - # https://github.com/lfortran/lfortran/pkgs/container/lfortran - os: ubuntu-22.04 compiler: lfortran @@ -202,6 +197,11 @@ jobs: version: 0.65.0 container: ghcr.io/lfortran/lfortran:v0.65.0 + - os: ubuntu-22.04 + compiler: lfortran + version: 0.66.0 + container: ghcr.io/lfortran/lfortran:v0.66.0 + - os: ubuntu-22.04 compiler: lfortran version: latest From 8377e1930c7dcc875f6e67fde4bcf75b336a46a3 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Mon, 14 Sep 2026 13:39:23 -0700 Subject: [PATCH 7/9] README: Other misc cleanups --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 697874d..dcb9dcc 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ preprocessor ASSERTIONS to non-zero, e.g., ``` fpm build --flag "-DASSERTIONS" ``` -The program [example/invoke-via-macro.F90] demonstrates the preferred way to invoke assertions via the three provided macros. +The program [example/invoke-via-macro.F90] demonstrates the preferred way to invoke assertions via the provided macros. Invoking assertions this way ensures such calls will be completely removed whenever the `ASSERTIONS` macro is undefined (or defined to zero) during compilation. Due to a limitation of `fpm`, this approach works best if the project using Assert is also a `fpm` project. If instead `fpm install` is used, then either the user must copy `include/assert_macros.h` to the installation directory (default: `~/.local/include`) or @@ -84,7 +84,7 @@ Building and Testing - [GNU Compiler Collection (GCC) `gfortran`](#gnu-compiler-collection-gcc-gfortran)) - [Intel `ifx`](#intel-ifx)) - [LFortran `lfortran`](#lfortran-lfortran) -- [LLVM `flang-new`](#llvm-flang-new) +- [LLVM `flang`](#llvm-flang) - [Numerical Algorithms Group (NAG) `nagfor`](#numerical-algorithms-group-nag-nagfor) ### General Build Knobs @@ -100,10 +100,17 @@ using syntax like: `fpm --flag "-DASSERTIONS=1"` Fortran features (e.g. to report the image number of an assertion failure). Default is disabled, multi-image support can be enabled using `-DASSERT_MULTI_IMAGE`. -### Cray Compiler Environment (CCE) `ftn` -Because `fpm` uses the compiler name to determine the compiler identity and because -CCE provides one compiler wrapper, `ftn`, for invoking all compilers, you will -need to invoke `ftn` in a shell script named to identify CCE compiler. For example, +### Cray Compiler Environment (CCE) `crayftn` + +The simplest way to compile with CCE is to invoke the Cray compiler +directly: +``` +fpm test --compiler crayftn --profile release +``` + +If instead you prefer to use the Cray PE compiler wrappers, note that `fpm` uses +the compiler name to determine the compiler identity, so you will +need to invoke `ftn` in a shell script named to identify the CCE compiler. For example, place a script named `crayftn.sh` in your path with the following contents and with executable privileges set appropriately: ``` @@ -234,15 +241,15 @@ In the case of gfortran, this appears to have been resolved by default starting #### Line breaks in macro invocations The preprocessor is not currently specified by any Fortran standard, and -as of 2025 its operation differs in subtle ways between compilers. +as of 2026 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 +For example, GNU `gfortran` and LLVM `flang` both accept backslash `\` continuation character for line-breaks in a macro invocation: ```fortran -! OK for flang-new and gfortran +! OK for flang and gfortran call_assert_describe( computed_checksum == expected_checksum, \ "Checksum mismatch failure!" \ ) @@ -268,7 +275,7 @@ Fortran does not support comments with an end delimiter, 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 (on gfortran and flang-new): +after macro expansion (on gfortran and flang): ```fortran ! INCORRECT: cannot use Fortran comments inside macro invocation From 0b2ff5951f387cd5f350a7d161caac3f0028fb79 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Mon, 14 Sep 2026 15:26:14 -0700 Subject: [PATCH 8/9] CI: Add flang-23 Linux/ARM64 coverage --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf63d54..cc46dde 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,6 +78,11 @@ jobs: container: snowstep/llvm:jammy # https://hub.docker.com/r/phhargrove/llvm-flang/tags + - os: ubuntu-24.04-arm + compiler: flang + version: 23 + container: phhargrove/llvm-flang:23.1.0-latest-arm64 + - os: ubuntu-24.04 compiler: flang version: 23 From 1fe7514c205d8a279d0d79ae905e827377bf4c7c Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Mon, 14 Sep 2026 15:34:09 -0700 Subject: [PATCH 9/9] CI: Adjust Build FPM action Ensure FPM build artifacts land in an isolated directory --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc46dde..2e71a3c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -328,10 +328,11 @@ jobs: if: ${{ runner.os == 'Linux' && runner.arch == 'ARM64' }} run: | export FPM_VERSION=0.13.0 + mkdir -p fpm-temp/bin + cd fpm-temp curl --retry 5 -LOsS https://github.com/fortran-lang/fpm/releases/download/v$FPM_VERSION/fpm-$FPM_VERSION.F90 - mkdir fpm-temp - gfortran-14 -o fpm-temp/fpm fpm-$FPM_VERSION.F90 - echo "PATH=${PWD}/fpm-temp:${PATH}" >> "$GITHUB_ENV" + gfortran-14 -o bin/fpm fpm-$FPM_VERSION.F90 + echo "PATH=$PWD/bin:${PATH}" >> "$GITHUB_ENV" - name: Version info run: |