Skip to content

FPE_TRAP_ENABLED does not set the -ffpe-trap flag #3476

Description

@andrew-platt

Bug description

The CMake option FPE_TRAP_ENABLED is documented as "Enable FPE trap in compiler options", but
it adds no compiler option. Setting it to ON has exactly one effect: it defines the
preprocessor macro FPE_TRAP_ENABLED, which compiles out the body of Set_IEEE_Constants in
the Sys*.f90 layer.

Two consequences:

  1. No floating-point trapping is enabled. No -ffpe-trap (GFortran) or -fpe0 (Intel) flag
    is added anywhere in the build system. A user who sets -DFPE_TRAP_ENABLED=ON expecting a
    trapping build gets an ordinary non-trapping build.
  2. The global IEEE constants are left undefined. Set_IEEE_Constants is the only place that
    assigns NaN_D, Inf_D, NaN, Inf, NaN_S, Inf_S. These are module variables in
    NWTC_Num with no initializer, assigned once from SetConstants. With the macro defined the
    whole assignment block is #ifndef-ed out, so they retain indeterminate values for the life
    of the run. The source comment acknowledges this: "note that anything that refers to NaN or
    Inf will be incorrect in that case."

So the option as it stands removes the NaN/Inf definitions — the cost of a trapping build —
without delivering the trapping that would justify it. It is only correct if the user separately
supplies trapping flags through CMAKE_Fortran_FLAGS, which is not what the option's help text
describes.

To Reproduce

  1. Configure twice, changing only the option:
    cmake -B build-off -DCMAKE_BUILD_TYPE=Release -DFPE_TRAP_ENABLED=OFF
    cmake -B build-on  -DCMAKE_BUILD_TYPE=Release -DFPE_TRAP_ENABLED=ON
    
  2. Compare the generated Fortran flags, e.g.
    diff <(grep Fortran_FLAGS build-off/modules/aerodyn/CMakeFiles/aerodynlib.dir/flags.make) \
         <(grep Fortran_FLAGS build-on/modules/aerodyn/CMakeFiles/aerodynlib.dir/flags.make)
    
  3. The flag lines are identical apart from -DFPE_TRAP_ENABLED. No -ffpe-trap appears in
    either; grep -r ffpe-trap over the whole source and build trees returns nothing.

Expected behavior

-DFPE_TRAP_ENABLED=ON should produce a build that traps on floating-point exceptions, since
that is what the option name and help string promise. Suppressing the NaN/Inf generation block
should be a consequence of trapping being enabled, not the entire behaviour.

Relevant code

  • CMakeLists.txt:43 — option(FPE_TRAP_ENABLED "Enable FPE trap in compiler options" off)
  • CMakeLists.txt:104-106 — the option's only effect:
    if (FPE_TRAP_ENABLED)
      add_definitions(-DFPE_TRAP_ENABLED)
    endif (FPE_TRAP_ENABLED)
  • modules/nwtc-library/src/SysGnuLinux.f90:298 — #ifndef FPE_TRAP_ENABLED around the entire
    body of Set_IEEE_Constants. The same guard appears in SysGnuWin.f90:298,
    SysMatlabLinuxGnu.f90:301, SysIVF_Labview.f90:371 and SysFlangLinux.f90:275.
  • modules/nwtc-library/src/NWTC_Num.f90:33,35 (and the ReKi/SiKi equivalents) — the
    variables are declared with no initializer.
  • modules/nwtc-library/src/NWTC_Num.f90:5478 — the single call site, inside SetConstants.

Impact

Low frequency, but silent when it bites. Anyone using the option for its stated purpose gets no
trapping, so the debugging session it was enabled for cannot work. Any code path that reads
NaN/Inf in such a build reads an undefined value rather than the intended IEEE constant;
these are referenced in WAMIT2.f90 and AeroDisk_IO.f90 among others.

There is also a forward-looking reason to fix it. PR #3464 introduces a build rule that uses
NOT FPE_TRAP_ENABLED as a proxy for "this is not a trapping build", in order to decide whether
-fno-trapping-math is safe to apply to the OLAF kernels. That inference is only sound if the
option genuinely tracks trapping builds. As things stand, a user who enables trapping the
conventional way — -DCMAKE_Fortran_FLAGS="-ffpe-trap=invalid,zero,overflow" without also
setting -DFPE_TRAP_ENABLED=ON — would get -fno-trapping-math applied anyway.

Suggested fix

Either of the following would resolve it; the first matches the documented intent.

  1. Make the option add the trapping flags per compiler, for example
    -ffpe-trap=invalid,zero,overflow for GNU and -fpe0 for Intel, alongside the existing
    add_definitions. The Sys*.f90 guard then does what its comment says it does.
  2. Keep the current behaviour but rename and re-document the option to reflect it — something
    like FPE_TRAP_COMPATIBLE, with help text stating that it only suppresses the NaN/Inf
    generation and must be paired with user-supplied trapping flags.

In either case, it would help to have the build fail fast, or at least warn, when -ffpe-trap
appears in CMAKE_Fortran_FLAGS while FPE_TRAP_ENABLED is OFF, since that combination
currently produces a trapping build that still executes the deliberate divide-by-zero in
Set_IEEE_Constants and will abort during initialization.

OpenFAST Version

Reproduced on dev at 386378cdb (v5.0.0-423-g386378cdb). The behaviour is long-standing,
not a recent regression.

System Information

  • OS: Linux (Debian 12, container)
  • Compiler: GNU Fortran (Debian 12.2.0-14+deb12u1) 12.2.0
  • CMake: 3.25.1
  • Build: CMAKE_BUILD_TYPE=Release, DOUBLE_PRECISION=ON

Additional context

This is a build-system issue only; it does not affect results in any default build, since
FPE_TRAP_ENABLED defaults to off and the NaN/Inf constants are then set correctly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions