Skip to content

Workaround some lingering problems with LFortran and deploy CI #69

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ jobs:
error_stop_code: 128
container: intel/fortran-essentials:2025.0.0-0-devel-ubuntu22.04

# --- LFortran coverage ---

# 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

container:
image: ${{ matrix.container }}

Expand Down Expand Up @@ -122,6 +130,9 @@ jobs:
echo "FPM_FC=flang-new" >> "$GITHUB_ENV" ; \
elif test "$FC" = "ifx" ; then \
echo "FPM_FC=ifx" >> "$GITHUB_ENV" ; \
elif test "$FC" = "lfortran" ; then \
echo "FPM_FC=lfortran" >> "$GITHUB_ENV" ; \
echo "FFLAGS=--cpp $FFLAGS" >> "$GITHUB_ENV" ; \
else \
echo "FPM_FC=gfortran-${COMPILER_VERSION}" >> "$GITHUB_ENV" ; \
echo "FFLAGS=-ffree-line-length-0 $FFLAGS" >> "$GITHUB_ENV" ; \
Expand Down Expand Up @@ -163,21 +174,26 @@ jobs:
set -x
fpm test ${FPM_FLAGS} --flag "$FFLAGS"
fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS"
fpm run --example simple-assertions ${FPM_FLAGS} --flag "$FFLAGS"
fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS"

- name: Build and Test (Assertions ON)
env:
FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERTIONS
run: |
set -x
fpm test ${FPM_FLAGS} --flag "$FFLAGS"
( set +e ; fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
( set +e ; fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
fpm test ${FPM_FLAGS} --flag "$FFLAGS"
( set +e ; fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
( set +e ; fpm run --example simple-assertions ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
( set +e ; fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )

- name: Test Assertions w/ Parallel Callbacks
if: ${{ matrix.compiler != 'lfortran' }} # issue #68
env:
FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERTIONS --flag -DASSERT_MULTI_IMAGE --flag -DASSERT_PARALLEL_CALLBACKS
FPM_FLAGS: ${{ env.FPM_FLAGS }} --flag -DASSERT_MULTI_IMAGE --flag -DASSERT_PARALLEL_CALLBACKS
run: |
set -x
( set +e ; fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
( set +e ; fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS" ; test $? = $ERROR_STOP_CODE )
fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS"
fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS"
( set +e ; fpm run --example false-assertion ${FPM_FLAGS} --flag "$FFLAGS -DASSERTIONS" ; test $? = $ERROR_STOP_CODE )
( set +e ; fpm run --example invoke-via-macro ${FPM_FLAGS} --flag "$FFLAGS -DASSERTIONS" ; test $? = $ERROR_STOP_CODE )
10 changes: 5 additions & 5 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fpm run --example invoke-via-macro --flag "-DASSERTIONS"
Simple examples
---------------

The [simple_assertions.f90] example demonstrates a precondition and a
The [simple-assertions.f90] example demonstrates a precondition and a
postcondition, each with an assertion that checks the truth of a logical
expression based on scalar, real values.

Expand All @@ -32,20 +32,20 @@ Running the examples

### Single-image execution
```
fpm run --example simple_assertions
fpm run --example simple-assertions --flag "-DASSERTIONS"
```
where `fpm run` automatically invokes `fpm build` if necessary, .e.g., if the package's source code
has changed since the most recent build. If `assert` is working correctly, the `fpm run` above
will error-terminate with the character stop code similar to the following
```
Assertion failure on image 1: reciprocal: abs(error) < tolerance
Assertion failure on image 1: All residuals within tolerance
```

### Multi-image execution with `gfortran` and OpenCoarrays
```
git clone [email protected]/sourceryinstitute/assert
cd assert
fpm run --compiler caf --runner "cafrun -n 2" --example simple_assertions
fpm run --compiler caf --runner "cafrun -n 2" --example simple-assertions --flag "-DASSERTIONS"
```
Replace either instance of `2` above with the desired number of images to run for parallel execution.
If `assert` is working correctly, both of the latter `fpm run` commands will error-terminate with one
Expand All @@ -55,7 +55,7 @@ or more images providing stop codes analogous to those quoted in the [Single-ima
[OpenCoarrays]: https://github.com/sourceryinstitute/opencoarrays
[Enforcing programming contracts]: #enforcing-programming-contracts
[Single-image execution]: #single-image-execution
[simple_assertions.f90]: ./simple_assertions.f90
[simple-assertions.f90]: ./simple-assertions.f90
[invoke-via-macro.F90]: ./invoke-via-macro.F90
[UML]: https://en.wikipedia.org/wiki/Unified_Modeling_Language
[OCL]: https://en.wikipedia.org/wiki/Object_Constraint_Language
Expand Down
3 changes: 3 additions & 0 deletions example/simple-assertions.f90
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ pure function roots(a,b,c) result(zeros)

associate(discriminant => b**2 - 4*a*c)
call assert(assertion = discriminant >= 0., description = "discriminant >= 0") ! precondition
allocate(zeros(2))
! there's a deliberate math bug in the following line, to help demonstrate assertion failure
zeros = -b + [sqrt(discriminant), -sqrt(discriminant)]
end associate

! This assertion will fail (due to the defect above) when ASSERTIONS are enabled:
call assert(all(abs(a*zeros**2 + b*zeros + c) < tolerance), "All residuals within tolerance.") ! postcondition
end function

Expand Down
7 changes: 7 additions & 0 deletions src/assert_m.F90
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pure subroutine assert_always(assertion, description, file, line)
allocate(character(len=0)::message)
allocate(character(len=0)::location)


! format source location, if known
location = ''
if (present(file)) then
Expand Down Expand Up @@ -146,7 +147,13 @@ pure subroutine assert_always(assertion, description, file, line)
; ! deliberate fall-thru
endif
#endif
#ifdef __LFORTRAN__
! workaround a defect observed in LFortran 0.54:
! error stop with an allocatable character argument prints garbage
error stop message//'', QUIET=.false.
#else
error stop message, QUIET=.false.
#endif

end if check_assertion

Expand Down