[clang] [flang] [llvm] [flang][flang-rt] Add -ffpe-trap= to set the initial FP exception halting mode (PR #208828)
Vineet Kumar via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 28 08:56:00 PDT 2026
https://github.com/vntkmr updated https://github.com/llvm/llvm-project/pull/208828
>From b1dcf4961ea85b7ea3c9f3a92da068e0e7bd5e76 Mon Sep 17 00:00:00 2001
From: Vineet Kumar <vineetk at hpe.com>
Date: Fri, 10 Jul 2026 14:42:25 -0500
Subject: [PATCH 1/4] [flang][flang-rt] Add -ffpe-trap= to set the initial FP
exception halting mode
Implement the gfortran-style `-ffpe-trap=<list>` option, which sets the
initial floating-point exception halting mode for the main program unit.
The Fortran 2023 standard (17.6) permits the initial halting mode to be
processor defined, so honoring this at program start is conforming.
`<list>` is a comma-separated set of exception mnemonics: `invalid`,
`zero`, `overflow`, `underflow`, and `inexact`, corresponding to the
IEEE_FLAG_TYPE values IEEE_INVALID, IEEE_DIVIDE_BY_ZERO, IEEE_OVERFLOW,
IEEE_UNDERFLOW, and IEEE_INEXACT. As a non-standard, gfortran-compatible
extension, `denormal` halts on the x86 denormal-operand exception. An
empty list or the value `none` disables halting, and the last
`-ffpe-trap=` on the command line wins (allowing an earlier request to be
overridden).
Changes by component:
- clang/Driver: give `-ffpe-trap=` FlangOption/FC1Option visibility and a
one-line HelpText plus a detailed DocBrief (moved into f_Group); forward
the flag to -fc1. Emit a target-based warning when halting control is
unavailable (non-x86 and non-Linux targets), and a denormal-specific
warning on non-x86 targets. The check is intentionally conservative and
only ever under-warns; the runtime remains authoritative.
- flang/Frontend: parse the list into a LangOptions bitmask
(FPExceptionTrapKind), error on unknown mnemonics, and propagate the
mask to the lowering options.
- flang/Lower: genMain() injects a call to _FortranAEnableFPETraps into
the main program unit only (after ProgramStart, before _QQmain), so the
mode persists across procedures as required by F2023 17.6.
- flang-rt: add EnableFPETraps(), which enables halting only for the
exceptions whose halting control is supported on the target
(IEEE_SUPPORT_HALTING, F2023 17.11.40); it is a no-op elsewhere.
Testing:
- Driver tests for forwarding, "none"/empty, last-wins, bad-argument
errors, and the unsupported-target / denormal warnings.
- FIR lowering tests for the emitted call and constant mask, including a
negative test that a non-main compilation unit emits no call.
- flang-rt execution tests that verify each exception (invalid, zero,
overflow, underflow, inexact, denormal) actually terminates the program
with SIGFPE, plus a selectivity test that an unrelated enabled trap does
not halt. The denormal execution test is gated to x86.
These changes were generated with the assistance of AI tooling and have
been reviewed, tested, and validated by the author.
Resolves #198657
---
clang/include/clang/Options/FlangOptions.td | 26 +++++++-
clang/lib/Driver/ToolChains/Flang.cpp | 30 ++++++++-
clang/test/Driver/gfortran.f90 | 2 -
flang-rt/lib/runtime/exceptions.cpp | 19 ++++++
.../test/Driver/fpe-trap-exec-denormal.f90 | 33 ++++++++++
.../test/Driver/fpe-trap-exec-divzero.f90 | 35 ++++++++++
.../test/Driver/fpe-trap-exec-inexact.f90 | 30 +++++++++
.../test/Driver/fpe-trap-exec-overflow.f90 | 29 +++++++++
.../test/Driver/fpe-trap-exec-underflow.f90 | 30 +++++++++
flang-rt/test/Driver/fpe-trap-exec.f90 | 30 +++++++++
flang/docs/ReleaseNotes.md | 10 +++
flang/include/flang/Lower/LoweringOptions.def | 3 +
.../flang/Optimizer/Builder/Runtime/Main.h | 3 +-
flang/include/flang/Runtime/exceptions.h | 5 ++
flang/include/flang/Support/LangOptions.def | 2 +
flang/include/flang/Support/LangOptions.h | 12 ++++
flang/lib/Frontend/CompilerInvocation.cpp | 42 ++++++++++++
flang/lib/Lower/Bridge.cpp | 13 ++--
flang/lib/Optimizer/Builder/Runtime/Main.cpp | 13 +++-
flang/test/Driver/fpe-trap.f90 | 65 +++++++++++++++++++
flang/test/Lower/fpe-trap-nonmain.f90 | 20 ++++++
flang/test/Lower/fpe-trap.f90 | 31 +++++++++
22 files changed, 470 insertions(+), 13 deletions(-)
create mode 100644 flang-rt/test/Driver/fpe-trap-exec-denormal.f90
create mode 100644 flang-rt/test/Driver/fpe-trap-exec-divzero.f90
create mode 100644 flang-rt/test/Driver/fpe-trap-exec-inexact.f90
create mode 100644 flang-rt/test/Driver/fpe-trap-exec-overflow.f90
create mode 100644 flang-rt/test/Driver/fpe-trap-exec-underflow.f90
create mode 100644 flang-rt/test/Driver/fpe-trap-exec.f90
create mode 100644 flang/test/Driver/fpe-trap.f90
create mode 100644 flang/test/Lower/fpe-trap-nonmain.f90
create mode 100644 flang/test/Lower/fpe-trap.f90
diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index bafc063663fe2..b3e7ce0732c8a 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -21,7 +21,6 @@ def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group
// "f" options with values for gfortran.
def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>;
def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
-def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
def finit_integer_EQ : Joined<["-"], "finit-integer=">, Group<gfortran_Group>;
@@ -327,6 +326,31 @@ defm real_sum_reassociation
standard-conforming Fortran semantics.
}]>;
+def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<f_Group>,
+ HelpText<"Set the initial floating-point exception halting mode for the main program">,
+ DocBrief<[{The ``-ffpe-trap=[list]`` option sets the initial floating-point
+exception halting mode for the main program unit. ``[list]`` is a comma-separated
+list of the exceptions to halt on: ``invalid``, ``zero``, ``overflow``,
+``underflow``, and ``inexact``, corresponding to the Fortran 2023 (17.6)
+``IEEE_FLAG_TYPE`` values ``IEEE_INVALID``, ``IEEE_DIVIDE_BY_ZERO``,
+``IEEE_OVERFLOW``, ``IEEE_UNDERFLOW``, and ``IEEE_INEXACT``. As a non-standard
+GFortran-compatible extension, ``denormal`` halts on the hardware denormal
+(subnormal) operand exception. An empty list, or the value ``none``, disables
+halting. Multiple occurrences are allowed; the last ``-ffpe-trap=`` wins.
+
+Halting is enabled only for exceptions the target's floating-point environment
+can trap on. Halting control is implemented for x86 targets and for glibc-based
+(Linux) targets; for other targets the compiler emits a warning that the option
+is ignored. The ``denormal`` exception is an x86-only extension, so requesting
+it for a non-x86 target likewise produces a warning and is ignored.
+
+The warning is based on the target triple and is intentionally conservative: it
+is emitted only when the target is known not to support halting. On a non-x86
+target whose C library does not provide the required support (for example, a
+non-glibc Linux such as musl), the option may still be silently ignored at run
+time without a compile-time warning. The runtime is the definitive authority on
+which exceptions can be trapped.}]>;
+
defm init_global_zero : BoolOptionWithoutMarshalling<"f", "init-global-zero",
PosFlag<SetTrue, [], [], "Zero initialize globals without default initialization (default)">,
NegFlag<SetFalse, [], [], "Do not zero initialize globals without default initialization">>;
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index d900037230f20..8c63ca530f609 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -776,7 +776,8 @@ void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
}
static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
- ArgStringList &CmdArgs) {
+ ArgStringList &CmdArgs,
+ const llvm::Triple &Triple) {
StringRef FPContract;
bool HonorINFs = true;
bool HonorNaNs = true;
@@ -950,6 +951,31 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
if (ReciprocalMath)
CmdArgs.push_back("-freciprocal-math");
+
+ // Set the initial floating-point exception halting mode for the main program.
+ if (const Arg *A = Args.getLastArg(options::OPT_ffpe_trap_EQ)) {
+ // Halting on floating-point exceptions is implemented in flang-rt only for
+ // x86 targets and for glibc-based (Linux) targets. Warn if the target
+ // cannot honor the request; the runtime otherwise ignores it.
+ if (!Triple.isX86() && !Triple.isOSLinux()) {
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << A->getAsString(Args) << Triple.str();
+ } else if (!Triple.isX86()) {
+ // The "denormal" exception is an x86-only extension. On other (otherwise
+ // supported) targets it cannot be trapped, so warn if it is requested.
+ llvm::SmallVector<StringRef, 6> Traps;
+ StringRef(A->getValue())
+ .split(Traps, ',', /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ for (StringRef Trap : Traps)
+ if (Trap == "denormal") {
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << "-ffpe-trap=denormal" << Triple.str();
+ break;
+ }
+ }
+ A->render(Args, CmdArgs);
+ }
}
static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
@@ -1126,7 +1152,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
addPicOptions(Args, CmdArgs);
// Floating point related options
- addFloatingPointOptions(D, Args, CmdArgs);
+ addFloatingPointOptions(D, Args, CmdArgs, Triple);
// Add target args, features, etc.
addTargetOptions(Args, CmdArgs, JA.getOffloadingArch(),
diff --git a/clang/test/Driver/gfortran.f90 b/clang/test/Driver/gfortran.f90
index c985428650ecd..2eb20c802f187 100644
--- a/clang/test/Driver/gfortran.f90
+++ b/clang/test/Driver/gfortran.f90
@@ -68,7 +68,6 @@
! RUN: -ff2c \
! RUN: -ffixed-form \
! RUN: -ffixed-line-length-42 \
-! RUN: -ffpe-trap=list \
! RUN: -ffree-form \
! RUN: -ffree-line-length-42 \
! RUN: -ffrontend-optimize \
@@ -188,7 +187,6 @@
! CHECK: "-ff2c"
! CHECK: "-ffixed-form"
! CHECK: "-ffixed-line-length-42"
-! CHECK: "-ffpe-trap=list"
! CHECK: "-ffree-form"
! CHECK: "-ffree-line-length-42"
! CHECK: "-ffrontend-optimize"
diff --git a/flang-rt/lib/runtime/exceptions.cpp b/flang-rt/lib/runtime/exceptions.cpp
index 2b1a4f14b1f36..eba59b98e3820 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -161,6 +161,25 @@ bool RTNAME(SupportHalting)([[maybe_unused]] uint32_t except) {
#endif
}
+void RTNAME(EnableFPETraps)(uint32_t excepts) {
+ // Enable halting only for those exceptions whose halting control is supported
+ // by the processor. The Fortran standard restricts IEEE_SET_HALTING_MODE to
+ // flags for which IEEE_SUPPORT_HALTING is true (F2023 17.11.40); on targets
+ // without halting control (e.g. non-glibc), this is a no-op.
+ uint32_t supported = 0;
+ for (uint32_t flag = 1; flag <= excepts; flag <<= 1) {
+ if ((excepts & flag) && RTNAME(SupportHalting)(flag)) {
+ supported |= flag;
+ }
+ }
+ if (supported == 0) {
+ return;
+ }
+ uint32_t mapped = RTNAME(MapException)(supported);
+ RTNAME(feclearexcept)(mapped);
+ RTNAME(feenableexcept)(mapped);
+}
+
// A hardware FZ (flush to zero) bit is the negation of the
// ieee_[get|set]_underflow_mode GRADUAL argument.
#if defined(_MM_FLUSH_ZERO_MASK)
diff --git a/flang-rt/test/Driver/fpe-trap-exec-denormal.f90 b/flang-rt/test/Driver/fpe-trap-exec-denormal.f90
new file mode 100644
index 0000000000000..97490e2bdd6db
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec-denormal.f90
@@ -0,0 +1,33 @@
+! Test that -ffpe-trap=denormal enables run-time halting on the (non-standard,
+! gfortran-compatible) denormal-operand exception.
+
+! The denormal-operand exception is an x86 SSE feature (__FE_DENORM); on other
+! architectures it is not available, so restrict this test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the operation on a subnormal operand completes and the
+! program exits normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=denormal: adding a subnormal operand raises the
+! denormal-operand exception and halting terminates the program with SIGFPE
+! (signal 8, i.e. shell exit 136).
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=denormal %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+program fpe_trap_denormal
+ real :: x, y
+ ! Build a subnormal value at runtime. Its operands are normal, so this does
+ ! not itself raise the denormal-operand exception, and 2**-127 is an exact
+ ! subnormal, so it does not raise underflow either.
+ x = tiny(0.0) * (0.5 + real(command_argument_count()))
+ ! x is subnormal, so this operation has a denormal operand.
+ y = x + x
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang-rt/test/Driver/fpe-trap-exec-divzero.f90 b/flang-rt/test/Driver/fpe-trap-exec-divzero.f90
new file mode 100644
index 0000000000000..cc588e94ddf88
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec-divzero.f90
@@ -0,0 +1,35 @@
+! Test that -ffpe-trap=zero enables run-time halting on an IEEE_DIVIDE_BY_ZERO
+! exception, and that trapping is selective (a different enabled trap does not
+! halt on a divide-by-zero).
+
+! Halting control (feenableexcept) is only available on glibc targets.
+! REQUIRES: target={{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the division by zero yields infinity and the program
+! exits normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=zero: the division by zero raises IEEE_DIVIDE_BY_ZERO
+! and halting terminates the program with SIGFPE (signal 8, i.e. shell exit 136).
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=zero %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+! Selectivity: trapping on overflow only must not halt on a divide-by-zero.
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=overflow %s -o %t.other
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.other \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+program fpe_trap_divzero
+ real :: x, y
+ ! command_argument_count() is not known at compile time, which prevents the
+ ! division from being folded away by the compiler.
+ x = real(command_argument_count())
+ y = 1.0 / x
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang-rt/test/Driver/fpe-trap-exec-inexact.f90 b/flang-rt/test/Driver/fpe-trap-exec-inexact.f90
new file mode 100644
index 0000000000000..5ac609315a1ca
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec-inexact.f90
@@ -0,0 +1,30 @@
+! Test that -ffpe-trap=inexact enables run-time halting on an IEEE_INEXACT
+! exception.
+
+! Halting control (feenableexcept) is only available on glibc targets.
+! REQUIRES: target={{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the inexact division completes and the program exits
+! normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=inexact: the division 1.0/3.0 is inexact and halting
+! terminates the program with SIGFPE (signal 8, i.e. shell exit 136). This is
+! the first floating-point operation, so the trap is deterministic.
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=inexact %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+program fpe_trap_inexact
+ real :: x, y
+ ! real(3 + count) is exact for the runtime-unknown small integer, so the
+ ! division below is the first inexact operation.
+ x = real(3 + command_argument_count())
+ y = 1.0 / x
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang-rt/test/Driver/fpe-trap-exec-overflow.f90 b/flang-rt/test/Driver/fpe-trap-exec-overflow.f90
new file mode 100644
index 0000000000000..08b4bee805d87
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec-overflow.f90
@@ -0,0 +1,29 @@
+! Test that -ffpe-trap=overflow enables run-time halting on an IEEE_OVERFLOW
+! exception.
+
+! Halting control (feenableexcept) is only available on glibc targets.
+! REQUIRES: target={{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the overflowing multiplication yields infinity and the
+! program exits normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=overflow: the multiplication raises IEEE_OVERFLOW and
+! halting terminates the program with SIGFPE (signal 8, i.e. shell exit 136).
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=overflow %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+program fpe_trap_overflow
+ real :: x, y
+ ! Subtracting a runtime-unknown value keeps x == huge while preventing the
+ ! compiler from folding the overflowing multiplication.
+ x = huge(0.0) - real(command_argument_count())
+ y = x * x
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang-rt/test/Driver/fpe-trap-exec-underflow.f90 b/flang-rt/test/Driver/fpe-trap-exec-underflow.f90
new file mode 100644
index 0000000000000..e2b9705598e08
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec-underflow.f90
@@ -0,0 +1,30 @@
+! Test that -ffpe-trap=underflow enables run-time halting on an IEEE_UNDERFLOW
+! exception.
+
+! Halting control (feenableexcept) is only available on glibc targets.
+! REQUIRES: target={{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the underflowing multiplication completes and the
+! program exits normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=underflow: squaring the smallest normal value yields a
+! result below the subnormal range, raising IEEE_UNDERFLOW, and halting
+! terminates the program with SIGFPE (signal 8, i.e. shell exit 136).
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=underflow %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+program fpe_trap_underflow
+ real :: x, y
+ ! x == tiny (the smallest normal), computed via a runtime-unknown factor so
+ ! the multiplication below is not folded. tiny*1.0 is exact (no underflow).
+ x = tiny(0.0) * real(command_argument_count() + 1)
+ y = x * x
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang-rt/test/Driver/fpe-trap-exec.f90 b/flang-rt/test/Driver/fpe-trap-exec.f90
new file mode 100644
index 0000000000000..326ff68f73058
--- /dev/null
+++ b/flang-rt/test/Driver/fpe-trap-exec.f90
@@ -0,0 +1,30 @@
+! Test that -ffpe-trap= actually enables halting at run time: an invalid
+! floating-point operation must terminate the program with a signal (SIGFPE)
+! when the corresponding trap is enabled, and must complete normally otherwise.
+
+! Halting control (feenableexcept) is only available on glibc targets.
+! REQUIRES: target={{.*}}-linux-gnu
+! UNSUPPORTED: offload-cuda
+
+! Built without traps: the invalid operation yields a NaN and the program exits
+! normally.
+! RUN: %flang %isysroot -L"%libdir" %s -o %t.notrap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t.notrap \
+! RUN: | FileCheck --check-prefix=NOTRAP %s
+
+! Built with -ffpe-trap=invalid: the invalid operation raises IEEE_INVALID and
+! halting terminates the program with SIGFPE (signal 8, i.e. shell exit 136).
+! RUN: %flang %isysroot -L"%libdir" -ffpe-trap=invalid %s -o %t.trap
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" sh -c 'ulimit -c 0; %t.trap; test $? -eq 136'
+
+program fpe_trap_exec
+ real :: x, y
+ ! command_argument_count() is not known at compile time, which prevents the
+ ! invalid operation from being folded away by the compiler.
+ x = real(command_argument_count()) - 1.0
+ y = sqrt(x)
+ print '(A)', "no-trap"
+ print *, y
+end program
+
+! NOTRAP: no-trap
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 888da4d58b868..9024eef59ba32 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -34,6 +34,16 @@ page](https://llvm.org/releases/).
## Non-comprehensive list of changes in this release
## New Compiler Flags
+- The `-ffpe-trap=` flag is now supported. It sets the initial floating-point
+ exception halting mode for the main program to a comma-separated list of
+ `invalid`, `zero`, `overflow`, `underflow`, and `inexact` (plus the
+ non-standard, gfortran-compatible extension `denormal`). Use `none` or an
+ empty list to disable halting. The last `-ffpe-trap=` on the command line is
+ effective. The Fortran standard permits the initial halting mode to be
+ processor defined (Fortran 2023, 17.6). Halting control is implemented for x86
+ and glibc-based (Linux) targets; on other targets a warning is emitted and the
+ option is ignored. The `denormal` exception is an x86-only extension, so
+ requesting it for a non-x86 target also warns and is ignored.
## Windows Support
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 0b02ffd5a3b22..0a2fdc5936a88 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -92,6 +92,9 @@ ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0)
/// FP max/min behavior for max/min intrinsics and [max|min][loc|val] (Legacy,
/// Portable, Extremum, ExtremeNum). Default: Legacy.
ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0)
+/// Bitmask of floating-point exceptions to trap on (from -ffpe-trap=).
+/// 0 means no trapping. Bit values match IEEE_FLAG_TYPE encoding.
+ENUM_LOWERINGOPT(FPExceptionTraps, unsigned, 8, 0)
#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Main.h b/flang/include/flang/Optimizer/Builder/Runtime/Main.h
index d4067b367f73e..1acc3cbed35c5 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Main.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Main.h
@@ -25,7 +25,8 @@ namespace fir::runtime {
void genMain(fir::FirOpBuilder &builder, mlir::Location loc,
const std::vector<Fortran::lower::EnvironmentDefault> &defs,
- bool initCuda = false, bool initCoarrayEnv = false);
+ bool initCuda = false, bool initCoarrayEnv = false,
+ unsigned fpExceptionTraps = 0);
}
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_MAIN_H
diff --git a/flang/include/flang/Runtime/exceptions.h b/flang/include/flang/Runtime/exceptions.h
index 2497a48402233..99cb8788f7c50 100644
--- a/flang/include/flang/Runtime/exceptions.h
+++ b/flang/include/flang/Runtime/exceptions.h
@@ -47,6 +47,11 @@ void RTNAME(SetUnderflowMode)(bool flag);
std::size_t RTNAME(GetModesTypeSize)(void);
std::size_t RTNAME(GetStatusTypeSize)(void);
+// Enable trapping on the specified floating-point exceptions.
+// The excepts argument is a bitmask of IEEE_FLAG_TYPE values
+// (as used by MapException).
+void RTNAME(EnableFPETraps)(std::uint32_t excepts);
+
} // extern "C"
} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_EXCEPTIONS_H_
diff --git a/flang/include/flang/Support/LangOptions.def b/flang/include/flang/Support/LangOptions.def
index 7ae73c6755b57..80d2302cc8c72 100644
--- a/flang/include/flang/Support/LangOptions.def
+++ b/flang/include/flang/Support/LangOptions.def
@@ -69,6 +69,8 @@ LANGOPT(OpenMPSimd, 1, false)
LANGOPT(NoReallocateLHS, 1, false)
/// Enable fast MOD operations for REAL
LANGOPT(FastRealMod, 1, false)
+/// Bitmask of floating-point exceptions to trap on (from -ffpe-trap=)
+LANGOPT(FPExceptionTraps, 8, 0)
LANGOPT(VScaleMin, 32, 0) ///< Minimum vscale range value
LANGOPT(VScaleMax, 32, 0) ///< Maximum vscale range value
diff --git a/flang/include/flang/Support/LangOptions.h b/flang/include/flang/Support/LangOptions.h
index 1dd676e62a9e5..42b488c3d18a3 100644
--- a/flang/include/flang/Support/LangOptions.h
+++ b/flang/include/flang/Support/LangOptions.h
@@ -43,6 +43,18 @@ class LangOptionsBase {
FPM_Fast,
};
+ /// Floating-point exception trap kinds for -ffpe-trap=.
+ /// Bit values match the Fortran IEEE_FLAG_TYPE encoding used by
+ /// the runtime's MapException().
+ enum FPExceptionTrapKind : unsigned {
+ FPE_Invalid = 1,
+ FPE_Denormal = 2,
+ FPE_DivByZero = 4,
+ FPE_Overflow = 8,
+ FPE_Underflow = 16,
+ FPE_Inexact = 32,
+ };
+
#define LANGOPT(Name, Bits, Default) unsigned Name : Bits;
#define ENUM_LANGOPT(Name, Type, Bits, Default)
#include "LangOptions.def"
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 79ad08353b64c..a3efe4df5533b 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1485,6 +1485,46 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
opts.FastRealMod = false;
}
+ // Only the last -ffpe-trap= on the command line is effective. The list is a
+ // comma-separated set of exception mnemonics. The mnemonics "invalid",
+ // "zero", "overflow", "underflow", and "inexact" correspond to the Fortran
+ // 2023 IEEE_FLAG_TYPE values IEEE_INVALID, IEEE_DIVIDE_BY_ZERO,
+ // IEEE_OVERFLOW, IEEE_UNDERFLOW, and IEEE_INEXACT (F2023 17.2). The mnemonic
+ // "denormal" is a non-standard, gfortran-compatible extension (subnormal is
+ // an IEEE_FEATURES feature, not an exception flag). The mnemonic "none", as
+ // well as an empty list, requests no halting, allowing a later -ffpe-trap= to
+ // override an earlier one.
+ if (const llvm::opt::Arg *a =
+ args.getLastArg(clang::options::OPT_ffpe_trap_EQ)) {
+ using LangOptions = Fortran::common::LangOptions;
+ llvm::StringRef val = a->getValue();
+ unsigned traps = 0;
+ llvm::SmallVector<llvm::StringRef> trapList;
+ val.split(trapList, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (llvm::StringRef trap : trapList) {
+ if (trap == "none") {
+ // Reset to no halting; a later mnemonic can re-enable.
+ traps = 0;
+ continue;
+ }
+ unsigned bit = llvm::StringSwitch<unsigned>(trap)
+ .Case("invalid", LangOptions::FPE_Invalid)
+ .Case("denormal", LangOptions::FPE_Denormal)
+ .Case("zero", LangOptions::FPE_DivByZero)
+ .Case("overflow", LangOptions::FPE_Overflow)
+ .Case("underflow", LangOptions::FPE_Underflow)
+ .Case("inexact", LangOptions::FPE_Inexact)
+ .Default(0);
+ if (bit == 0) {
+ diags.Report(clang::diag::err_drv_unsupported_option_argument)
+ << a->getSpelling() << trap;
+ return false;
+ }
+ traps |= bit;
+ }
+ opts.FPExceptionTraps = traps;
+ }
+
return true;
}
@@ -2026,4 +2066,6 @@ void CompilerInvocation::setLoweringOptions() {
codegenOpts.getComplexRange() ==
CodeGenOptions::ComplexRangeKind::CX_Basic)
loweringOpts.setComplexDivisionToRuntime(false);
+
+ loweringOpts.setFPExceptionTraps(langOptions.FPExceptionTraps);
}
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 7cde3ae492e14..6d2e777a7f099 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -614,14 +614,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// Generate the `main` entry point if necessary
if (hasMainProgram)
createBuilderOutsideOfFuncOpAndDo([&]() {
- fir::runtime::genMain(*builder, toLocation(),
- bridge.getEnvironmentDefaults(),
+ fir::runtime::genMain(
+ *builder, toLocation(), bridge.getEnvironmentDefaults(),
(getFoldingContext().languageFeatures().IsEnabled(
Fortran::common::LanguageFeature::CUDA) &&
- getFoldingContext().languageFeatures().IsEnabled(
- Fortran::common::LanguageFeature::CUDAInit)),
- getFoldingContext().languageFeatures().IsEnabled(
- Fortran::common::LanguageFeature::Coarray));
+ getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::CUDAInit)),
+ getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::Coarray),
+ bridge.getLoweringOptions().getFPExceptionTraps());
});
finalizeOpenMPLowering(globalOmpRequiresSymbols);
diff --git a/flang/lib/Optimizer/Builder/Runtime/Main.cpp b/flang/lib/Optimizer/Builder/Runtime/Main.cpp
index acc7700891805..2427088ec7f83 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Main.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Main.cpp
@@ -14,6 +14,7 @@
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/MIF/MIFOps.h"
#include "flang/Runtime/CUDA/init.h"
+#include "flang/Runtime/exceptions.h"
#include "flang/Runtime/main.h"
#include "flang/Runtime/stop.h"
@@ -23,7 +24,7 @@ using namespace Fortran::runtime;
void fir::runtime::genMain(
fir::FirOpBuilder &builder, mlir::Location loc,
const std::vector<Fortran::lower::EnvironmentDefault> &defs, bool initCuda,
- bool initCoarrayEnv) {
+ bool initCoarrayEnv, unsigned fpExceptionTraps) {
auto *context = builder.getContext();
auto argcTy = builder.getDefaultIntegerType();
auto ptrTy = mlir::LLVM::LLVMPointerType::get(context);
@@ -71,6 +72,16 @@ void fir::runtime::genMain(
if (initCoarrayEnv)
mif::InitOp::create(builder, loc);
+ if (fpExceptionTraps != 0) {
+ auto i32Ty = builder.getI32Type();
+ auto enableFn =
+ builder.createFunction(loc, RTNAME_STRING(EnableFPETraps),
+ mlir::FunctionType::get(context, {i32Ty}, {}));
+ mlir::Value trapsVal =
+ builder.createIntegerConstant(loc, i32Ty, fpExceptionTraps);
+ fir::CallOp::create(builder, loc, enableFn, mlir::ValueRange{trapsVal});
+ }
+
fir::CallOp::create(builder, loc, qqMainFn);
mlir::Value ret = builder.createIntegerConstant(loc, argcTy, 0);
diff --git a/flang/test/Driver/fpe-trap.f90 b/flang/test/Driver/fpe-trap.f90
new file mode 100644
index 0000000000000..9517209ffffcf
--- /dev/null
+++ b/flang/test/Driver/fpe-trap.f90
@@ -0,0 +1,65 @@
+! Test that -ffpe-trap= is forwarded from the Flang driver to the frontend.
+
+! RUN: %flang -ffpe-trap=invalid,zero,overflow -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-FORWARD %s
+! CHECK-FORWARD: -fc1
+! CHECK-FORWARD-SAME: -ffpe-trap=invalid,zero,overflow
+
+! Test all supported exception types
+! RUN: %flang -ffpe-trap=invalid,zero,overflow,underflow,inexact,denormal -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-ALL %s
+! CHECK-ALL: -fc1
+! CHECK-ALL-SAME: -ffpe-trap=invalid,zero,overflow,underflow,inexact,denormal
+
+! Test a single exception type
+! RUN: %flang -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-SINGLE %s
+! CHECK-SINGLE: -fc1
+! CHECK-SINGLE-SAME: -ffpe-trap=invalid
+
+! Only the last -ffpe-trap= is forwarded to the frontend.
+! RUN: %flang -ffpe-trap=invalid -ffpe-trap=overflow -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-LAST %s
+! CHECK-LAST: -fc1
+! CHECK-LAST-SAME: -ffpe-trap=overflow
+! CHECK-LAST-NOT: -ffpe-trap=invalid
+
+! "none" and an empty list are accepted and disable halting.
+! RUN: %flang_fc1 -ffpe-trap=none -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
+! RUN: %flang_fc1 -ffpe-trap= -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
+! RUN: %flang_fc1 -ffpe-trap=invalid,none -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
+! CHECK-OK-NOT: error:
+
+! On a target without floating-point halting support, the driver warns and still
+! forwards the option (the runtime ignores it at execution time).
+! RUN: %flang --target=powerpc64-ibm-aix -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-WARN %s
+! CHECK-WARN: warning: ignoring '-ffpe-trap=invalid' option as it is not currently supported for target 'powerpc64-ibm-aix'
+! CHECK-WARN: -ffpe-trap=invalid
+
+! On a supported non-x86 target (glibc/Linux), no warning is emitted.
+! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-NOWARN %s
+! CHECK-NOWARN-NOT: ignoring '-ffpe-trap
+! CHECK-NOWARN: -ffpe-trap=invalid
+
+! The "denormal" exception is an x86-only extension: requesting it for a non-x86
+! target warns even though the target is otherwise supported. The rest of the
+! list is still honored, so the option is still forwarded.
+! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid,denormal -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-DENORM %s
+! CHECK-DENORM: warning: ignoring '-ffpe-trap=denormal' option as it is not currently supported for target 'aarch64-unknown-linux-gnu'
+! CHECK-DENORM: -ffpe-trap=invalid,denormal
+
+! On x86 the "denormal" exception is supported, so no warning is emitted.
+! RUN: %flang --target=x86_64-unknown-linux-gnu -ffpe-trap=denormal -fsyntax-only -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-X86DENORM %s
+! CHECK-X86DENORM-NOT: ignoring '-ffpe-trap
+! CHECK-X86DENORM: -ffpe-trap=denormal
+
+! Test invalid exception type
+! RUN: not %flang_fc1 -ffpe-trap=bogus -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-INVALID %s
+! CHECK-INVALID: error: unsupported argument 'bogus' to option '-ffpe-trap='
+
+end program
diff --git a/flang/test/Lower/fpe-trap-nonmain.f90 b/flang/test/Lower/fpe-trap-nonmain.f90
new file mode 100644
index 0000000000000..18a4e4f7cc089
--- /dev/null
+++ b/flang/test/Lower/fpe-trap-nonmain.f90
@@ -0,0 +1,20 @@
+! Test that -ffpe-trap= only affects the main program unit: a compilation unit
+! without a main program must not generate a call to _FortranAEnableFPETraps.
+
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=invalid,zero,overflow %s -o - | FileCheck %s
+
+subroutine sub(x)
+ real :: x
+ x = x + 1.0
+end subroutine
+
+module m
+contains
+ function f(y) result(z)
+ real :: y, z
+ z = y * 2.0
+ end function
+end module
+
+! CHECK-NOT: fir.call @_FortranAEnableFPETraps
+! CHECK-NOT: @_QQmain
diff --git a/flang/test/Lower/fpe-trap.f90 b/flang/test/Lower/fpe-trap.f90
new file mode 100644
index 0000000000000..040232fb94894
--- /dev/null
+++ b/flang/test/Lower/fpe-trap.f90
@@ -0,0 +1,31 @@
+! Test that -ffpe-trap= generates a call to _FortranAEnableFPETraps in main().
+
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=invalid %s -o - | FileCheck --check-prefix=CHECK-INVALID %s
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=invalid,zero,overflow %s -o - | FileCheck --check-prefix=CHECK-MULTI %s
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=invalid,underflow,inexact,denormal %s -o - | FileCheck --check-prefix=CHECK-EXT %s
+! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck --check-prefix=CHECK-NONE %s
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=none %s -o - | FileCheck --check-prefix=CHECK-NONE %s
+! RUN: %flang_fc1 -emit-fir -ffpe-trap=invalid,none %s -o - | FileCheck --check-prefix=CHECK-NONE %s
+
+program test
+ continue
+end
+
+! CHECK-INVALID: %[[TRAPS:.*]] = arith.constant 1 : i32
+! CHECK-INVALID: fir.call @_FortranAProgramStart(
+! CHECK-INVALID: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-INVALID: fir.call @_QQmain
+
+! invalid=1, zero=4, overflow=8 => 13
+! CHECK-MULTI: %[[TRAPS:.*]] = arith.constant 13 : i32
+! CHECK-MULTI: fir.call @_FortranAProgramStart(
+! CHECK-MULTI: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-MULTI: fir.call @_QQmain
+
+! invalid=1, denormal=2, underflow=16, inexact=32 => 51
+! CHECK-EXT: %[[TRAPS:.*]] = arith.constant 51 : i32
+! CHECK-EXT: fir.call @_FortranAProgramStart(
+! CHECK-EXT: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-EXT: fir.call @_QQmain
+
+! CHECK-NONE-NOT: @_FortranAEnableFPETraps
>From e743cbe95d6ae2e7ff5a80ca28236effffb1cd50 Mon Sep 17 00:00:00 2001
From: Vineet Kumar <vineetk at hpe.com>
Date: Mon, 13 Jul 2026 15:18:03 -0500
Subject: [PATCH 2/4] [flang][fpe-trap] Update test requirements to restrict
run-time tests to x86 glibc for FP exception handling
---
clang/include/clang/Options/FlangOptions.td | 4 +++-
flang-rt/test/Driver/fpe-trap-exec-divzero.f90 | 7 +++++--
flang-rt/test/Driver/fpe-trap-exec-inexact.f90 | 7 +++++--
flang-rt/test/Driver/fpe-trap-exec-overflow.f90 | 7 +++++--
flang-rt/test/Driver/fpe-trap-exec-underflow.f90 | 7 +++++--
flang-rt/test/Driver/fpe-trap-exec.f90 | 7 +++++--
flang/docs/ReleaseNotes.md | 11 ++++++-----
flang/lib/Lower/Bridge.cpp | 4 ++--
8 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index b3e7ce0732c8a..a9cf3ad7ee801 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -336,7 +336,9 @@ list of the exceptions to halt on: ``invalid``, ``zero``, ``overflow``,
``IEEE_OVERFLOW``, ``IEEE_UNDERFLOW``, and ``IEEE_INEXACT``. As a non-standard
GFortran-compatible extension, ``denormal`` halts on the hardware denormal
(subnormal) operand exception. An empty list, or the value ``none``, disables
-halting. Multiple occurrences are allowed; the last ``-ffpe-trap=`` wins.
+halting. In the absence of this option, the program runs with traps disabled
+(equivalent to passing ``none``). Multiple occurrences are allowed; only the
+last ``-ffpe-trap=`` takes effect.
Halting is enabled only for exceptions the target's floating-point environment
can trap on. Halting control is implemented for x86 targets and for glibc-based
diff --git a/flang-rt/test/Driver/fpe-trap-exec-divzero.f90 b/flang-rt/test/Driver/fpe-trap-exec-divzero.f90
index cc588e94ddf88..b68494c72da1b 100644
--- a/flang-rt/test/Driver/fpe-trap-exec-divzero.f90
+++ b/flang-rt/test/Driver/fpe-trap-exec-divzero.f90
@@ -2,8 +2,11 @@
! exception, and that trapping is selective (a different enabled trap does not
! halt on a divide-by-zero).
-! Halting control (feenableexcept) is only available on glibc targets.
-! REQUIRES: target={{.*}}-linux-gnu
+! Halting requires both glibc (feenableexcept) and hardware that delivers a
+! trap when an enabled FP exception is raised. Arm makes FP-exception trapping
+! optional, and the AArch64 CI hardware does not deliver SIGFPE, so restrict
+! this run-time test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
! UNSUPPORTED: offload-cuda
! Built without traps: the division by zero yields infinity and the program
diff --git a/flang-rt/test/Driver/fpe-trap-exec-inexact.f90 b/flang-rt/test/Driver/fpe-trap-exec-inexact.f90
index 5ac609315a1ca..db1a9ac9a41c3 100644
--- a/flang-rt/test/Driver/fpe-trap-exec-inexact.f90
+++ b/flang-rt/test/Driver/fpe-trap-exec-inexact.f90
@@ -1,8 +1,11 @@
! Test that -ffpe-trap=inexact enables run-time halting on an IEEE_INEXACT
! exception.
-! Halting control (feenableexcept) is only available on glibc targets.
-! REQUIRES: target={{.*}}-linux-gnu
+! Halting requires both glibc (feenableexcept) and hardware that delivers a
+! trap when an enabled FP exception is raised. Arm makes FP-exception trapping
+! optional, and the AArch64 CI hardware does not deliver SIGFPE, so restrict
+! this run-time test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
! UNSUPPORTED: offload-cuda
! Built without traps: the inexact division completes and the program exits
diff --git a/flang-rt/test/Driver/fpe-trap-exec-overflow.f90 b/flang-rt/test/Driver/fpe-trap-exec-overflow.f90
index 08b4bee805d87..7fb3b990fbf07 100644
--- a/flang-rt/test/Driver/fpe-trap-exec-overflow.f90
+++ b/flang-rt/test/Driver/fpe-trap-exec-overflow.f90
@@ -1,8 +1,11 @@
! Test that -ffpe-trap=overflow enables run-time halting on an IEEE_OVERFLOW
! exception.
-! Halting control (feenableexcept) is only available on glibc targets.
-! REQUIRES: target={{.*}}-linux-gnu
+! Halting requires both glibc (feenableexcept) and hardware that delivers a
+! trap when an enabled FP exception is raised. Arm makes FP-exception trapping
+! optional, and the AArch64 CI hardware does not deliver SIGFPE, so restrict
+! this run-time test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
! UNSUPPORTED: offload-cuda
! Built without traps: the overflowing multiplication yields infinity and the
diff --git a/flang-rt/test/Driver/fpe-trap-exec-underflow.f90 b/flang-rt/test/Driver/fpe-trap-exec-underflow.f90
index e2b9705598e08..1e7d8aa8d198f 100644
--- a/flang-rt/test/Driver/fpe-trap-exec-underflow.f90
+++ b/flang-rt/test/Driver/fpe-trap-exec-underflow.f90
@@ -1,8 +1,11 @@
! Test that -ffpe-trap=underflow enables run-time halting on an IEEE_UNDERFLOW
! exception.
-! Halting control (feenableexcept) is only available on glibc targets.
-! REQUIRES: target={{.*}}-linux-gnu
+! Halting requires both glibc (feenableexcept) and hardware that delivers a
+! trap when an enabled FP exception is raised. Arm makes FP-exception trapping
+! optional, and the AArch64 CI hardware does not deliver SIGFPE, so restrict
+! this run-time test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
! UNSUPPORTED: offload-cuda
! Built without traps: the underflowing multiplication completes and the
diff --git a/flang-rt/test/Driver/fpe-trap-exec.f90 b/flang-rt/test/Driver/fpe-trap-exec.f90
index 326ff68f73058..b5c5d6cae1d61 100644
--- a/flang-rt/test/Driver/fpe-trap-exec.f90
+++ b/flang-rt/test/Driver/fpe-trap-exec.f90
@@ -2,8 +2,11 @@
! floating-point operation must terminate the program with a signal (SIGFPE)
! when the corresponding trap is enabled, and must complete normally otherwise.
-! Halting control (feenableexcept) is only available on glibc targets.
-! REQUIRES: target={{.*}}-linux-gnu
+! Halting requires both glibc (feenableexcept) and hardware that delivers a
+! trap when an enabled FP exception is raised. Arm makes FP-exception trapping
+! optional, and the AArch64 CI hardware does not deliver SIGFPE, so restrict
+! this run-time test to x86 glibc.
+! REQUIRES: target=x86_64{{.*}}-linux-gnu
! UNSUPPORTED: offload-cuda
! Built without traps: the invalid operation yields a NaN and the program exits
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 9024eef59ba32..08014b06aa548 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -38,11 +38,12 @@ page](https://llvm.org/releases/).
exception halting mode for the main program to a comma-separated list of
`invalid`, `zero`, `overflow`, `underflow`, and `inexact` (plus the
non-standard, gfortran-compatible extension `denormal`). Use `none` or an
- empty list to disable halting. The last `-ffpe-trap=` on the command line is
- effective. The Fortran standard permits the initial halting mode to be
- processor defined (Fortran 2023, 17.6). Halting control is implemented for x86
- and glibc-based (Linux) targets; on other targets a warning is emitted and the
- option is ignored. The `denormal` exception is an x86-only extension, so
+ empty list to disable halting. In the absence of this option, the program runs
+ with traps disabled (equivalent to passing `none`). If `-ffpe-trap=` occurs
+ more than once, only the last one takes effect. Processor dependent (Fortran
+ 2023, 17.6) initial halting control is implemented for x86 and glibc-based
+ (Linux) targets only; on other targets a warning is emitted and the option is
+ ignored. Note that the `denormal` exception is an x86-only extension, so
requesting it for a non-x86 target also warns and is ignored.
## Windows Support
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 6d2e777a7f099..b68d53dfeeca1 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -616,8 +616,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
createBuilderOutsideOfFuncOpAndDo([&]() {
fir::runtime::genMain(
*builder, toLocation(), bridge.getEnvironmentDefaults(),
- (getFoldingContext().languageFeatures().IsEnabled(
- Fortran::common::LanguageFeature::CUDA) &&
+ (getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::CUDA) &&
getFoldingContext().languageFeatures().IsEnabled(
Fortran::common::LanguageFeature::CUDAInit)),
getFoldingContext().languageFeatures().IsEnabled(
>From 9b053fff8c0c9d89e30902e4f2fefbdff26853f6 Mon Sep 17 00:00:00 2001
From: Vineet Kumar <vineetk at hpe.com>
Date: Mon, 27 Jul 2026 10:51:01 -0500
Subject: [PATCH 3/4] [flang][clang][flang-rt] Move -ffpe-trap= validation into
the frontend
Address review feedback.
Parse and validate -ffpe-trap= in the frontend so a
direct `flang -fc1` invocation is self-validating; the driver now just
forwards the flag (like -fdebug-info-kind= and -fveclib). This avoids
splitting the diagnostics between driver and frontend.
- Flang.cpp: drop the target-support warnings and the Triple parameter
from addFloatingPointOptions(); only forward the last -ffpe-trap=.
- CompilerInvocation.cpp: emit the (conservative, triple-based) warnings
here; rename the loop variable `bit` to `flag`.
- FlangOptions.td: rewrite the DocBrief and add a target-support table.
- exceptions.cpp: add a TODO for x86-without-glibc halting.
- ReleaseNotes.md: trim to a concise entry.
- tests: cover driver forwarding and the default case, guard the
frontend warning checks with *-registered-target, and rename a reused
FileCheck capture in the Lower test.
Note: Changes in the commit are AI-assisted and reviewed by me.
---
clang/include/clang/Options/FlangOptions.td | 53 +++++++++----
clang/lib/Driver/ToolChains/Flang.cpp | 34 ++-------
flang-rt/lib/runtime/exceptions.cpp | 6 ++
flang/docs/ReleaseNotes.md | 16 ++--
flang/lib/Frontend/CompilerInvocation.cpp | 62 ++++++++++-----
flang/test/Driver/fpe-trap.f90 | 83 ++++++++++++---------
flang/test/Lower/fpe-trap.f90 | 12 +--
7 files changed, 154 insertions(+), 112 deletions(-)
diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index a9cf3ad7ee801..7373ba5b1340c 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -329,10 +329,12 @@ defm real_sum_reassociation
def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<f_Group>,
HelpText<"Set the initial floating-point exception halting mode for the main program">,
DocBrief<[{The ``-ffpe-trap=[list]`` option sets the initial floating-point
-exception halting mode for the main program unit. ``[list]`` is a comma-separated
-list of the exceptions to halt on: ``invalid``, ``zero``, ``overflow``,
-``underflow``, and ``inexact``, corresponding to the Fortran 2023 (17.6)
-``IEEE_FLAG_TYPE`` values ``IEEE_INVALID``, ``IEEE_DIVIDE_BY_ZERO``,
+exception halting mode for the main program unit. This is the halting mode in
+effect when the main program begins execution; the program may subsequently
+change it (for example, with ``IEEE_SET_HALTING_MODE``). ``[list]`` is a
+comma-separated list of the exceptions to halt on: ``invalid``, ``zero``,
+``overflow``, ``underflow``, and ``inexact``, corresponding to the Fortran 2023
+(17.6) ``IEEE_FLAG_TYPE`` values ``IEEE_INVALID``, ``IEEE_DIVIDE_BY_ZERO``,
``IEEE_OVERFLOW``, ``IEEE_UNDERFLOW``, and ``IEEE_INEXACT``. As a non-standard
GFortran-compatible extension, ``denormal`` halts on the hardware denormal
(subnormal) operand exception. An empty list, or the value ``none``, disables
@@ -340,18 +342,37 @@ halting. In the absence of this option, the program runs with traps disabled
(equivalent to passing ``none``). Multiple occurrences are allowed; only the
last ``-ffpe-trap=`` takes effect.
-Halting is enabled only for exceptions the target's floating-point environment
-can trap on. Halting control is implemented for x86 targets and for glibc-based
-(Linux) targets; for other targets the compiler emits a warning that the option
-is ignored. The ``denormal`` exception is an x86-only extension, so requesting
-it for a non-x86 target likewise produces a warning and is ignored.
-
-The warning is based on the target triple and is intentionally conservative: it
-is emitted only when the target is known not to support halting. On a non-x86
-target whose C library does not provide the required support (for example, a
-non-glibc Linux such as musl), the option may still be silently ignored at run
-time without a compile-time warning. The runtime is the definitive authority on
-which exceptions can be trapped.}]>;
+Run-time halting relies on glibc's ``feenableexcept`` (exposed as
+``IEEE_SUPPORT_HALTING``). The compile-time warning is a conservative
+approximation from the target triple; the runtime is the definitive authority on
+which exceptions can be trapped.
+
+The table below summarizes the halting behavior for different system
+configurations. In it, ``halts`` = the exception is trapped, ``ignored`` = no
+run-time effect, "Standard" = ``invalid``, ``zero``, ``overflow``,
+``underflow``, ``inexact`` exceptions, and "Others" = any non-x86 architecture
+(AArch64, PowerPC, RISC-V, ...):
+
++--------+-----------+----------+----------+-------------------+
+| Arch | C library | Standard | denormal | Warning |
++========+===========+==========+==========+===================+
+| x86 | glibc | halts | halts | none |
++--------+-----------+----------+----------+-------------------+
+| Others | glibc | halts | ignored | ``denormal`` only |
++--------+-----------+----------+----------+-------------------+
+| x86 | non-glibc | ignored | ignored | none (silent) |
++--------+-----------+----------+----------+-------------------+
+| Others | non-glibc | ignored | ignored | always |
++--------+-----------+----------+----------+-------------------+
+
+Notes:
+
+* On non-x86 targets, an exception halts only if the target's glibc
+ ``feenableexcept`` supports it; the runtime probes each requested exception at
+ start-up (via ``IEEE_SUPPORT_HALTING``) and enables only those it can.
+* ``denormal`` is honored only on x86_64; on 32-bit x86 it is silently ignored.
+* The "always" case excludes non-glibc *Linux* (for example musl), where -- as
+ on the x86 rows -- the option is silently ignored without a warning.}]>;
defm init_global_zero : BoolOptionWithoutMarshalling<"f", "init-global-zero",
PosFlag<SetTrue, [], [], "Zero initialize globals without default initialization (default)">,
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 8c63ca530f609..5beda55d23c8b 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -776,8 +776,7 @@ void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
}
static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
- ArgStringList &CmdArgs,
- const llvm::Triple &Triple) {
+ ArgStringList &CmdArgs) {
StringRef FPContract;
bool HonorINFs = true;
bool HonorNaNs = true;
@@ -952,30 +951,13 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
if (ReciprocalMath)
CmdArgs.push_back("-freciprocal-math");
- // Set the initial floating-point exception halting mode for the main program.
- if (const Arg *A = Args.getLastArg(options::OPT_ffpe_trap_EQ)) {
- // Halting on floating-point exceptions is implemented in flang-rt only for
- // x86 targets and for glibc-based (Linux) targets. Warn if the target
- // cannot honor the request; the runtime otherwise ignores it.
- if (!Triple.isX86() && !Triple.isOSLinux()) {
- D.Diag(diag::warn_drv_unsupported_option_for_target)
- << A->getAsString(Args) << Triple.str();
- } else if (!Triple.isX86()) {
- // The "denormal" exception is an x86-only extension. On other (otherwise
- // supported) targets it cannot be trapped, so warn if it is requested.
- llvm::SmallVector<StringRef, 6> Traps;
- StringRef(A->getValue())
- .split(Traps, ',', /*MaxSplit=*/-1,
- /*KeepEmpty=*/false);
- for (StringRef Trap : Traps)
- if (Trap == "denormal") {
- D.Diag(diag::warn_drv_unsupported_option_for_target)
- << "-ffpe-trap=denormal" << Triple.str();
- break;
- }
- }
+ // Forward -ffpe-trap= to the frontend unchanged. The value is parsed and
+ // validated in the frontend (flang -fc1 is a supported entry point, so it
+ // validates its own arguments): that is where an unknown mnemonic becomes an
+ // error and where the target-support warnings are emitted. See
+ // parseFloatingPointArgs() in flang/lib/Frontend/CompilerInvocation.cpp.
+ if (const Arg *A = Args.getLastArg(options::OPT_ffpe_trap_EQ))
A->render(Args, CmdArgs);
- }
}
static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
@@ -1152,7 +1134,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
addPicOptions(Args, CmdArgs);
// Floating point related options
- addFloatingPointOptions(D, Args, CmdArgs, Triple);
+ addFloatingPointOptions(D, Args, CmdArgs);
// Add target args, features, etc.
addTargetOptions(Args, CmdArgs, JA.getOffloadingArch(),
diff --git a/flang-rt/lib/runtime/exceptions.cpp b/flang-rt/lib/runtime/exceptions.cpp
index eba59b98e3820..5fb83f0375227 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -142,6 +142,12 @@ uint32_t RTNAME(fegetexcept)() {
// Check if the processor has the ability to control whether to halt or
// continue execution when a given exception is raised.
+//
+// TODO: Support halting on x86 without glibc. The MXCSR helpers above (guarded
+// by _MM_EXCEPT_DENORM) already provide the machinery, so this gate could be
+// widened to `#if defined(__USE_GNU) || defined(_MM_EXCEPT_DENORM)` to cover
+// x86_64 macOS/BSD and musl-Linux. Doing so also needs the x87 control word for
+// REAL(10), 32-bit x86 (__i386__), and Windows SEH handling; see PR discussion.
bool RTNAME(SupportHalting)([[maybe_unused]] uint32_t except) {
#ifdef __USE_GNU
except = RTNAME(MapException)(except);
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 08014b06aa548..eaf339c7db11b 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -34,17 +34,11 @@ page](https://llvm.org/releases/).
## Non-comprehensive list of changes in this release
## New Compiler Flags
-- The `-ffpe-trap=` flag is now supported. It sets the initial floating-point
- exception halting mode for the main program to a comma-separated list of
- `invalid`, `zero`, `overflow`, `underflow`, and `inexact` (plus the
- non-standard, gfortran-compatible extension `denormal`). Use `none` or an
- empty list to disable halting. In the absence of this option, the program runs
- with traps disabled (equivalent to passing `none`). If `-ffpe-trap=` occurs
- more than once, only the last one takes effect. Processor dependent (Fortran
- 2023, 17.6) initial halting control is implemented for x86 and glibc-based
- (Linux) targets only; on other targets a warning is emitted and the option is
- ignored. Note that the `denormal` exception is an x86-only extension, so
- requesting it for a non-x86 target also warns and is ignored.
+- Added the gfortran-compatible `-ffpe-trap=` flag, which sets the initial
+ floating-point exception halting mode of the main program. It takes a
+ comma-separated list of `invalid`, `zero`, `overflow`, `underflow`, `inexact`,
+ and the extension `denormal`, or `none` to disable halting. See the Flang
+ command line reference for the supported targets and details.
## Windows Support
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index a3efe4df5533b..9e14f756f8580 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1485,15 +1485,30 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
opts.FastRealMod = false;
}
- // Only the last -ffpe-trap= on the command line is effective. The list is a
- // comma-separated set of exception mnemonics. The mnemonics "invalid",
+ // -ffpe-trap= sets the initial floating-point exception halting mode for the
+ // main program. Only the last -ffpe-trap= on the command line is effective.
+ //
+ // The value is a comma-separated set of exception mnemonics. "invalid",
// "zero", "overflow", "underflow", and "inexact" correspond to the Fortran
// 2023 IEEE_FLAG_TYPE values IEEE_INVALID, IEEE_DIVIDE_BY_ZERO,
- // IEEE_OVERFLOW, IEEE_UNDERFLOW, and IEEE_INEXACT (F2023 17.2). The mnemonic
- // "denormal" is a non-standard, gfortran-compatible extension (subnormal is
- // an IEEE_FEATURES feature, not an exception flag). The mnemonic "none", as
- // well as an empty list, requests no halting, allowing a later -ffpe-trap= to
- // override an earlier one.
+ // IEEE_OVERFLOW, IEEE_UNDERFLOW, and IEEE_INEXACT (F2023 17.2). "denormal" is
+ // a non-standard, gfortran-compatible extension (subnormal is an
+ // IEEE_FEATURES feature, not an exception flag). "none", as well as an empty
+ // list, requests no halting, allowing a later -ffpe-trap= to override an
+ // earlier one.
+ //
+ // The option is validated here in the frontend (rather than the driver) so
+ // that a direct `flang -fc1` invocation is self-checking; the driver only
+ // forwards the flag. An unknown mnemonic is an error. In addition, run-time
+ // halting is implemented in flang-rt only where the target's floating-point
+ // environment can trap: it relies on glibc's feenableexcept (exposed as
+ // IEEE_SUPPORT_HALTING), so it takes effect only with a glibc-based C library
+ // on all targets (in practice Linux), and the "denormal" exception
+ // additionally requires an x86 target. When the target cannot honor the
+ // request we warn and the runtime ignores it. The check is triple-based and
+ // intentionally conservative: it only ever under-warns (for example, it does
+ // not warn for non-glibc x86 such as macOS/Windows/musl), with the runtime
+ // remaining the definitive authority.
if (const llvm::opt::Arg *a =
args.getLastArg(clang::options::OPT_ffpe_trap_EQ)) {
using LangOptions = Fortran::common::LangOptions;
@@ -1507,21 +1522,34 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
traps = 0;
continue;
}
- unsigned bit = llvm::StringSwitch<unsigned>(trap)
- .Case("invalid", LangOptions::FPE_Invalid)
- .Case("denormal", LangOptions::FPE_Denormal)
- .Case("zero", LangOptions::FPE_DivByZero)
- .Case("overflow", LangOptions::FPE_Overflow)
- .Case("underflow", LangOptions::FPE_Underflow)
- .Case("inexact", LangOptions::FPE_Inexact)
- .Default(0);
- if (bit == 0) {
+ unsigned flag = llvm::StringSwitch<unsigned>(trap)
+ .Case("invalid", LangOptions::FPE_Invalid)
+ .Case("denormal", LangOptions::FPE_Denormal)
+ .Case("zero", LangOptions::FPE_DivByZero)
+ .Case("overflow", LangOptions::FPE_Overflow)
+ .Case("underflow", LangOptions::FPE_Underflow)
+ .Case("inexact", LangOptions::FPE_Inexact)
+ .Default(0);
+ if (flag == 0) {
diags.Report(clang::diag::err_drv_unsupported_option_argument)
<< a->getSpelling() << trap;
return false;
}
- traps |= bit;
+ traps |= flag;
}
+
+ // Warn if the target cannot honor the request; the runtime ignores it.
+ llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);
+ if (traps != 0 && !triple.isX86() && !triple.isOSLinux()) {
+ diags.Report(clang::diag::warn_drv_unsupported_option_for_target)
+ << a->getAsString(args) << triple.str();
+ } else if ((traps & LangOptions::FPE_Denormal) && !triple.isX86()) {
+ // The "denormal" exception is an x86-only extension; on other (otherwise
+ // supported) targets it cannot be trapped.
+ diags.Report(clang::diag::warn_drv_unsupported_option_for_target)
+ << "-ffpe-trap=denormal" << triple.str();
+ }
+
opts.FPExceptionTraps = traps;
}
diff --git a/flang/test/Driver/fpe-trap.f90 b/flang/test/Driver/fpe-trap.f90
index 9517209ffffcf..822b95c54d940 100644
--- a/flang/test/Driver/fpe-trap.f90
+++ b/flang/test/Driver/fpe-trap.f90
@@ -1,65 +1,76 @@
-! Test that -ffpe-trap= is forwarded from the Flang driver to the frontend.
+! Test the -ffpe-trap= option: driver forwarding, and frontend validation and
+! target-support warnings.
-! RUN: %flang -ffpe-trap=invalid,zero,overflow -fsyntax-only -### %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-FORWARD %s
-! CHECK-FORWARD: -fc1
-! CHECK-FORWARD-SAME: -ffpe-trap=invalid,zero,overflow
+!--- The driver forwards -ffpe-trap= to the frontend ---------------------------
-! Test all supported exception types
-! RUN: %flang -ffpe-trap=invalid,zero,overflow,underflow,inexact,denormal -fsyntax-only -### %s 2>&1 \
+! Test all supported exception types are forwarded to -fc1.
+! RUN: %flang -ffpe-trap=invalid,zero,overflow,underflow,inexact,denormal -### %s 2>&1 \
! RUN: | FileCheck --check-prefix=CHECK-ALL %s
! CHECK-ALL: -fc1
! CHECK-ALL-SAME: -ffpe-trap=invalid,zero,overflow,underflow,inexact,denormal
-! Test a single exception type
-! RUN: %flang -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
+! Test a single exception type.
+! RUN: %flang -ffpe-trap=invalid -### %s 2>&1 \
! RUN: | FileCheck --check-prefix=CHECK-SINGLE %s
! CHECK-SINGLE: -fc1
! CHECK-SINGLE-SAME: -ffpe-trap=invalid
! Only the last -ffpe-trap= is forwarded to the frontend.
-! RUN: %flang -ffpe-trap=invalid -ffpe-trap=overflow -fsyntax-only -### %s 2>&1 \
+! RUN: %flang -ffpe-trap=invalid -ffpe-trap=overflow -### %s 2>&1 \
! RUN: | FileCheck --check-prefix=CHECK-LAST %s
! CHECK-LAST: -fc1
! CHECK-LAST-SAME: -ffpe-trap=overflow
! CHECK-LAST-NOT: -ffpe-trap=invalid
-! "none" and an empty list are accepted and disable halting.
-! RUN: %flang_fc1 -ffpe-trap=none -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
-! RUN: %flang_fc1 -ffpe-trap= -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
-! RUN: %flang_fc1 -ffpe-trap=invalid,none -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-OK --allow-empty %s
-! CHECK-OK-NOT: error:
+! By default (no -ffpe-trap=), nothing is forwarded to the frontend.
+! RUN: %flang -### %s 2>&1 | FileCheck --check-prefix=CHECK-DEFAULT %s
+! CHECK-DEFAULT: -fc1
+! CHECK-DEFAULT-NOT: -ffpe-trap
-! On a target without floating-point halting support, the driver warns and still
-! forwards the option (the runtime ignores it at execution time).
-! RUN: %flang --target=powerpc64-ibm-aix -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-WARN %s
+!--- The frontend accepts "none" and an empty list -----------------------------
+
+! "none" and an empty list are accepted and disable halting. A parse error would
+! make these fail with a non-zero exit code.
+! RUN: %flang_fc1 -ffpe-trap=none -fsyntax-only %s
+! RUN: %flang_fc1 -ffpe-trap= -fsyntax-only %s
+! RUN: %flang_fc1 -ffpe-trap=invalid,none -fsyntax-only %s
+
+!--- The frontend rejects an unknown mnemonic ----------------------------------
+
+! RUN: not %flang_fc1 -ffpe-trap=bogus -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-BADARG %s
+! CHECK-BADARG: error: unsupported argument 'bogus' to option '-ffpe-trap='
+
+!--- The frontend warns when the target cannot honor the request ---------------
+!
+! These runs invoke -fc1 with a specific -triple, so they are guarded by the
+! matching *-registered-target feature (the frontend creates a target machine
+! even for -fsyntax-only).
+
+! On a target without floating-point halting support, the frontend warns and the
+! option is ignored at run time.
+! RUN: %if powerpc-registered-target %{ \
+! RUN: %flang_fc1 -triple powerpc64-ibm-aix -ffpe-trap=invalid -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-WARN %s %}
! CHECK-WARN: warning: ignoring '-ffpe-trap=invalid' option as it is not currently supported for target 'powerpc64-ibm-aix'
-! CHECK-WARN: -ffpe-trap=invalid
! On a supported non-x86 target (glibc/Linux), no warning is emitted.
-! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid -fsyntax-only -### %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-NOWARN %s
+! RUN: %if aarch64-registered-target %{ \
+! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -ffpe-trap=invalid -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-NOWARN --allow-empty %s %}
! CHECK-NOWARN-NOT: ignoring '-ffpe-trap
-! CHECK-NOWARN: -ffpe-trap=invalid
! The "denormal" exception is an x86-only extension: requesting it for a non-x86
-! target warns even though the target is otherwise supported. The rest of the
-! list is still honored, so the option is still forwarded.
-! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid,denormal -fsyntax-only -### %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-DENORM %s
+! target warns even though the target is otherwise supported.
+! RUN: %if aarch64-registered-target %{ \
+! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -ffpe-trap=invalid,denormal -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-DENORM %s %}
! CHECK-DENORM: warning: ignoring '-ffpe-trap=denormal' option as it is not currently supported for target 'aarch64-unknown-linux-gnu'
-! CHECK-DENORM: -ffpe-trap=invalid,denormal
! On x86 the "denormal" exception is supported, so no warning is emitted.
-! RUN: %flang --target=x86_64-unknown-linux-gnu -ffpe-trap=denormal -fsyntax-only -### %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-X86DENORM %s
+! RUN: %if x86-registered-target %{ \
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -ffpe-trap=denormal -fsyntax-only %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-X86DENORM --allow-empty %s %}
! CHECK-X86DENORM-NOT: ignoring '-ffpe-trap
-! CHECK-X86DENORM: -ffpe-trap=denormal
-
-! Test invalid exception type
-! RUN: not %flang_fc1 -ffpe-trap=bogus -fsyntax-only %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-INVALID %s
-! CHECK-INVALID: error: unsupported argument 'bogus' to option '-ffpe-trap='
end program
diff --git a/flang/test/Lower/fpe-trap.f90 b/flang/test/Lower/fpe-trap.f90
index 040232fb94894..1e39cfe9fc55f 100644
--- a/flang/test/Lower/fpe-trap.f90
+++ b/flang/test/Lower/fpe-trap.f90
@@ -11,21 +11,21 @@ program test
continue
end
-! CHECK-INVALID: %[[TRAPS:.*]] = arith.constant 1 : i32
+! CHECK-INVALID: %[[INVALID:.*]] = arith.constant 1 : i32
! CHECK-INVALID: fir.call @_FortranAProgramStart(
-! CHECK-INVALID: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-INVALID: fir.call @_FortranAEnableFPETraps(%[[INVALID]])
! CHECK-INVALID: fir.call @_QQmain
! invalid=1, zero=4, overflow=8 => 13
-! CHECK-MULTI: %[[TRAPS:.*]] = arith.constant 13 : i32
+! CHECK-MULTI: %[[MULTI:.*]] = arith.constant 13 : i32
! CHECK-MULTI: fir.call @_FortranAProgramStart(
-! CHECK-MULTI: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-MULTI: fir.call @_FortranAEnableFPETraps(%[[MULTI]])
! CHECK-MULTI: fir.call @_QQmain
! invalid=1, denormal=2, underflow=16, inexact=32 => 51
-! CHECK-EXT: %[[TRAPS:.*]] = arith.constant 51 : i32
+! CHECK-EXT: %[[EXT:.*]] = arith.constant 51 : i32
! CHECK-EXT: fir.call @_FortranAProgramStart(
-! CHECK-EXT: fir.call @_FortranAEnableFPETraps(%[[TRAPS]])
+! CHECK-EXT: fir.call @_FortranAEnableFPETraps(%[[EXT]])
! CHECK-EXT: fir.call @_QQmain
! CHECK-NONE-NOT: @_FortranAEnableFPETraps
>From 8aa544f74da72fb69a3be7ae044861c9151c1731 Mon Sep 17 00:00:00 2001
From: Vineet Kumar <vineetk at hpe.com>
Date: Mon, 27 Jul 2026 15:56:36 -0500
Subject: [PATCH 4/4] [flang] Validate -ffpe-trap= in the driver, simplify
docbrief
Per review, move -ffpe-trap= validation (value check and target-support
warnings) from the frontend to the driver, since neither depends on
frontend-injected state; `-fc1` now only maps the list to its
LangOptions
bitmask.
- Flang.cpp: add renderFPExceptionTrapsOptions() to reject unknown
mnemonics, warn on unsupported targets, and forward the flag. Call it
from ConstructJob so it isn't skipped by the -ffast-math fast path.
- CompilerInvocation.cpp: extract parseFPExceptionTrapsArgs(), which
only
builds the bitmask (unknown mnemonics are ignored, not diagnosed).
- FlangOptions.td: simplify the DocBrief support table.
- test/Driver/fpe-trap.f90: check bad-argument and target warnings at
the driver level (dropping *-registered-target guards); add -Ofast checks.
- Simplify option docbrief.
---
clang/include/clang/Options/FlangOptions.td | 51 +++++----
clang/lib/Driver/ToolChains/Flang.cpp | 76 +++++++++++--
flang/lib/Frontend/CompilerInvocation.cpp | 117 +++++++++-----------
flang/test/Driver/fpe-trap.f90 | 60 +++++-----
4 files changed, 180 insertions(+), 124 deletions(-)
diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index 7373ba5b1340c..4cdd50555e0f3 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -348,31 +348,38 @@ approximation from the target triple; the runtime is the definitive authority on
which exceptions can be trapped.
The table below summarizes the halting behavior for different system
-configurations. In it, ``halts`` = the exception is trapped, ``ignored`` = no
-run-time effect, "Standard" = ``invalid``, ``zero``, ``overflow``,
-``underflow``, ``inexact`` exceptions, and "Others" = any non-x86 architecture
-(AArch64, PowerPC, RISC-V, ...):
-
-+--------+-----------+----------+----------+-------------------+
-| Arch | C library | Standard | denormal | Warning |
-+========+===========+==========+==========+===================+
-| x86 | glibc | halts | halts | none |
-+--------+-----------+----------+----------+-------------------+
-| Others | glibc | halts | ignored | ``denormal`` only |
-+--------+-----------+----------+----------+-------------------+
-| x86 | non-glibc | ignored | ignored | none (silent) |
-+--------+-----------+----------+----------+-------------------+
-| Others | non-glibc | ignored | ignored | always |
-+--------+-----------+----------+----------+-------------------+
+configurations. The C standard library is ``glibc`` (in practice Linux) or
+``non-glibc``; "Standard Exception" covers ``invalid``, ``zero``, ``overflow``,
+``underflow``, and ``inexact``. In the Standard Exception and Denormal columns,
+each cell names the compiler action followed by the run-time action:
+``compiler accepts`` = the compiler forwards the request without a warning,
+``compiler warns`` = the compiler emits a warning, ``runtime halts`` = the
+exception is trapped at run time, and ``runtime ignores`` = the request is
+silently ignored at run time.
+
++--------------+--------------------+--------------------+-------------------+
+| Architecture | C Standard Library | Standard Exception | Denormal |
++==============+====================+====================+===================+
+| x86 | glibc | compiler accepts, | compiler accepts, |
+| | | runtime halts | runtime halts |
++--------------+--------------------+--------------------+-------------------+
+| non-x86 | glibc | compiler accepts, | compiler warns, |
+| | | runtime halts | runtime ignores |
++--------------+--------------------+--------------------+-------------------+
+| x86 | non-glibc | compiler accepts, | compiler accepts, |
+| | | runtime ignores | runtime ignores |
++--------------+--------------------+--------------------+-------------------+
+| non-x86 | non-glibc | compiler warns, | compiler warns, |
+| | | runtime ignores | runtime ignores |
++--------------+--------------------+--------------------+-------------------+
Notes:
-* On non-x86 targets, an exception halts only if the target's glibc
- ``feenableexcept`` supports it; the runtime probes each requested exception at
- start-up (via ``IEEE_SUPPORT_HALTING``) and enables only those it can.
-* ``denormal`` is honored only on x86_64; on 32-bit x86 it is silently ignored.
-* The "always" case excludes non-glibc *Linux* (for example musl), where -- as
- on the x86 rows -- the option is silently ignored without a warning.}]>;
+* On non-x86 targets the standard exceptions halt only where the target's glibc
+ ``feenableexcept`` supports them; the runtime probes each at start-up (via
+ ``IEEE_SUPPORT_HALTING``) and enables only those it can.
+* ``denormal`` is honored only on x86_64; on 32-bit x86 it is silently ignored
+ (no warning).}]>;
defm init_global_zero : BoolOptionWithoutMarshalling<"f", "init-global-zero",
PosFlag<SetTrue, [], [], "Zero initialize globals without default initialization (default)">,
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 5beda55d23c8b..ebc35b1b3d90e 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -950,14 +950,72 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
if (ReciprocalMath)
CmdArgs.push_back("-freciprocal-math");
+}
- // Forward -ffpe-trap= to the frontend unchanged. The value is parsed and
- // validated in the frontend (flang -fc1 is a supported entry point, so it
- // validates its own arguments): that is where an unknown mnemonic becomes an
- // error and where the target-support warnings are emitted. See
- // parseFloatingPointArgs() in flang/lib/Frontend/CompilerInvocation.cpp.
- if (const Arg *A = Args.getLastArg(options::OPT_ffpe_trap_EQ))
- A->render(Args, CmdArgs);
+// Add options related to IEEE Floating point modes
+//
+// Initial halting mode:
+// Validate -ffpe-trap= and forward it to -fc1. This is handled separately from
+// addFloatingPointOptions() on purpose: -ffpe-trap= is not part of the
+// fast-math option set, so it must not be skipped by that function's
+// -ffast-math fast path. The value check and the target-support warnings depend
+// only on the option value and the target triple (no frontend-only state), so
+// they are done here in the driver rather than deferred to -fc1; -fc1 only
+// translates the list into its LangOptions bitmask.
+//
+// TODO:
+// Rounding modes
+// Underflow mode
+static void addIEEEFPModesOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const llvm::Triple &Triple) {
+ const Arg *A = Args.getLastArg(options::OPT_ffpe_trap_EQ);
+ if (!A)
+ return;
+
+ // The value is a comma-separated list of exception mnemonics. "none" and an
+ // empty list request no halting and reset any earlier request in the list;
+ // any other unrecognized mnemonic is an error.
+ llvm::SmallVector<StringRef, 6> Traps;
+ StringRef(A->getValue())
+ .split(Traps, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ bool RequestsTrap = false;
+ bool RequestsDenormal = false;
+ for (StringRef Trap : Traps) {
+ if (Trap == "none") {
+ RequestsTrap = false;
+ RequestsDenormal = false;
+ continue;
+ }
+ bool IsKnown = llvm::StringSwitch<bool>(Trap)
+ .Cases({"invalid", "zero", "overflow", "underflow",
+ "inexact", "denormal"},
+ true)
+ .Default(false);
+ if (!IsKnown) {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Trap;
+ return;
+ }
+ RequestsTrap = true;
+ RequestsDenormal |= (Trap == "denormal");
+ }
+
+ // Run-time halting is implemented in flang-rt only where the target's
+ // floating-point environment can trap: it relies on glibc's feenableexcept
+ // (in practice Linux), and "denormal" additionally requires an x86 target.
+ // Warn (conservatively) when the target cannot honor the request; the runtime
+ // otherwise ignores it. The denormal-specific warning names just
+ // "-ffpe-trap=denormal" to point at the unsupported mnemonic.
+ if (RequestsTrap && !Triple.isX86() && !Triple.isOSLinux())
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << A->getAsString(Args) << Triple.str();
+ else if (RequestsDenormal && !Triple.isX86())
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << "-ffpe-trap=denormal" << Triple.str();
+
+ A->render(Args, CmdArgs);
}
static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
@@ -1136,6 +1194,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Floating point related options
addFloatingPointOptions(D, Args, CmdArgs);
+ // Initial floating-point exception halting mode. Handled separately so it is
+ // not skipped by the -ffast-math fast path in addFloatingPointOptions().
+ addIEEEFPModesOptions(D, Args, CmdArgs, Triple);
+
// Add target args, features, etc.
addTargetOptions(Args, CmdArgs, JA.getOffloadingArch(),
JA.getOffloadingDeviceKind());
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 9e14f756f8580..b7a61b2443c6f 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1411,6 +1411,54 @@ static bool parseIntegerOverflowArgs(CompilerInvocation &invoc,
return true;
}
+/// Set the IEEE Floating point rounding modes, underflow mode and halting mode.
+///
+/// Initial halting mode:
+/// -ffpe-trap= sets the initial floating-point exception halting mode for the
+/// main program. Only the last -ffpe-trap= on the command line is effective.
+/// The value is a comma-separated set of exception mnemonics: "invalid",
+/// "zero", "overflow", "underflow", and "inexact" correspond to the Fortran
+/// 2023 IEEE_FLAG_TYPE values (F2023 17.2), and "denormal" is a non-standard,
+/// gfortran-compatible extension. "none", as well as an empty list, requests no
+/// halting and resets any earlier request.
+///
+/// TODO:
+/// Rounding modes
+/// Underflow mode
+///
+/// The value and the target-support warnings are validated in the driver (see
+/// renderFPExceptionTrapsOptions() in clang/lib/Driver/ToolChains/Flang.cpp);
+/// here we only translate the already-validated list, so an unrecognized
+/// mnemonic maps to 0 and is ignored rather than re-diagnosed.
+static void setIEEEFPModesArgs(Fortran::common::LangOptions &opts,
+ llvm::opt::ArgList &args) {
+ const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_ffpe_trap_EQ);
+ if (!a)
+ return;
+
+ using LangOptions = Fortran::common::LangOptions;
+ unsigned traps = 0;
+ llvm::SmallVector<llvm::StringRef> trapList;
+ llvm::StringRef(a->getValue())
+ .split(trapList, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (llvm::StringRef trap : trapList) {
+ if (trap == "none") {
+ // Reset to no halting; a later mnemonic can re-enable.
+ traps = 0;
+ continue;
+ }
+ traps |= llvm::StringSwitch<unsigned>(trap)
+ .Case("invalid", LangOptions::FPE_Invalid)
+ .Case("denormal", LangOptions::FPE_Denormal)
+ .Case("zero", LangOptions::FPE_DivByZero)
+ .Case("overflow", LangOptions::FPE_Overflow)
+ .Case("underflow", LangOptions::FPE_Underflow)
+ .Case("inexact", LangOptions::FPE_Inexact)
+ .Default(0);
+ }
+ opts.FPExceptionTraps = traps;
+}
+
/// Parses all floating point related arguments and populates the
/// CompilerInvocation accordingly.
/// Returns false if new errors are generated.
@@ -1485,73 +1533,8 @@ static bool parseFloatingPointArgs(CompilerInvocation &invoc,
opts.FastRealMod = false;
}
- // -ffpe-trap= sets the initial floating-point exception halting mode for the
- // main program. Only the last -ffpe-trap= on the command line is effective.
- //
- // The value is a comma-separated set of exception mnemonics. "invalid",
- // "zero", "overflow", "underflow", and "inexact" correspond to the Fortran
- // 2023 IEEE_FLAG_TYPE values IEEE_INVALID, IEEE_DIVIDE_BY_ZERO,
- // IEEE_OVERFLOW, IEEE_UNDERFLOW, and IEEE_INEXACT (F2023 17.2). "denormal" is
- // a non-standard, gfortran-compatible extension (subnormal is an
- // IEEE_FEATURES feature, not an exception flag). "none", as well as an empty
- // list, requests no halting, allowing a later -ffpe-trap= to override an
- // earlier one.
- //
- // The option is validated here in the frontend (rather than the driver) so
- // that a direct `flang -fc1` invocation is self-checking; the driver only
- // forwards the flag. An unknown mnemonic is an error. In addition, run-time
- // halting is implemented in flang-rt only where the target's floating-point
- // environment can trap: it relies on glibc's feenableexcept (exposed as
- // IEEE_SUPPORT_HALTING), so it takes effect only with a glibc-based C library
- // on all targets (in practice Linux), and the "denormal" exception
- // additionally requires an x86 target. When the target cannot honor the
- // request we warn and the runtime ignores it. The check is triple-based and
- // intentionally conservative: it only ever under-warns (for example, it does
- // not warn for non-glibc x86 such as macOS/Windows/musl), with the runtime
- // remaining the definitive authority.
- if (const llvm::opt::Arg *a =
- args.getLastArg(clang::options::OPT_ffpe_trap_EQ)) {
- using LangOptions = Fortran::common::LangOptions;
- llvm::StringRef val = a->getValue();
- unsigned traps = 0;
- llvm::SmallVector<llvm::StringRef> trapList;
- val.split(trapList, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (llvm::StringRef trap : trapList) {
- if (trap == "none") {
- // Reset to no halting; a later mnemonic can re-enable.
- traps = 0;
- continue;
- }
- unsigned flag = llvm::StringSwitch<unsigned>(trap)
- .Case("invalid", LangOptions::FPE_Invalid)
- .Case("denormal", LangOptions::FPE_Denormal)
- .Case("zero", LangOptions::FPE_DivByZero)
- .Case("overflow", LangOptions::FPE_Overflow)
- .Case("underflow", LangOptions::FPE_Underflow)
- .Case("inexact", LangOptions::FPE_Inexact)
- .Default(0);
- if (flag == 0) {
- diags.Report(clang::diag::err_drv_unsupported_option_argument)
- << a->getSpelling() << trap;
- return false;
- }
- traps |= flag;
- }
-
- // Warn if the target cannot honor the request; the runtime ignores it.
- llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);
- if (traps != 0 && !triple.isX86() && !triple.isOSLinux()) {
- diags.Report(clang::diag::warn_drv_unsupported_option_for_target)
- << a->getAsString(args) << triple.str();
- } else if ((traps & LangOptions::FPE_Denormal) && !triple.isX86()) {
- // The "denormal" exception is an x86-only extension; on other (otherwise
- // supported) targets it cannot be trapped.
- diags.Report(clang::diag::warn_drv_unsupported_option_for_target)
- << "-ffpe-trap=denormal" << triple.str();
- }
-
- opts.FPExceptionTraps = traps;
- }
+ // Set the initial IEEE floating point modes
+ setIEEEFPModesArgs(opts, args);
return true;
}
diff --git a/flang/test/Driver/fpe-trap.f90 b/flang/test/Driver/fpe-trap.f90
index 822b95c54d940..71f77c61d5928 100644
--- a/flang/test/Driver/fpe-trap.f90
+++ b/flang/test/Driver/fpe-trap.f90
@@ -1,5 +1,5 @@
-! Test the -ffpe-trap= option: driver forwarding, and frontend validation and
-! target-support warnings.
+! Test the -ffpe-trap= option: driver forwarding and driver-level validation
+! (value checking and target-support warnings).
!--- The driver forwards -ffpe-trap= to the frontend ---------------------------
@@ -27,50 +27,54 @@
! CHECK-DEFAULT: -fc1
! CHECK-DEFAULT-NOT: -ffpe-trap
-!--- The frontend accepts "none" and an empty list -----------------------------
+!--- "none" and an empty list are accepted -------------------------------------
-! "none" and an empty list are accepted and disable halting. A parse error would
-! make these fail with a non-zero exit code.
-! RUN: %flang_fc1 -ffpe-trap=none -fsyntax-only %s
-! RUN: %flang_fc1 -ffpe-trap= -fsyntax-only %s
-! RUN: %flang_fc1 -ffpe-trap=invalid,none -fsyntax-only %s
+! These are valid and must not produce a driver error (a non-zero exit code
+! would make these RUN lines fail).
+! RUN: %flang -ffpe-trap=none -### %s
+! RUN: %flang -ffpe-trap= -### %s
+! RUN: %flang -ffpe-trap=invalid,none -### %s
-!--- The frontend rejects an unknown mnemonic ----------------------------------
+!--- The driver rejects an unknown mnemonic ------------------------------------
-! RUN: not %flang_fc1 -ffpe-trap=bogus -fsyntax-only %s 2>&1 \
+! RUN: not %flang -ffpe-trap=bogus -### %s 2>&1 \
! RUN: | FileCheck --check-prefix=CHECK-BADARG %s
! CHECK-BADARG: error: unsupported argument 'bogus' to option '-ffpe-trap='
-!--- The frontend warns when the target cannot honor the request ---------------
-!
-! These runs invoke -fc1 with a specific -triple, so they are guarded by the
-! matching *-registered-target feature (the frontend creates a target machine
-! even for -fsyntax-only).
+!--- -ffpe-trap= is independent of -ffast-math / -Ofast ------------------------
-! On a target without floating-point halting support, the frontend warns and the
+! -ffpe-trap= is not part of the fast-math option set, so it is still forwarded
+! and still validated when -ffast-math/-Ofast is present.
+! RUN: %flang -Ofast -ffpe-trap=invalid -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-FASTMATH %s
+! CHECK-FASTMATH: -fc1
+! CHECK-FASTMATH-SAME: -ffpe-trap=invalid
+
+! RUN: not %flang -Ofast -ffpe-trap=bogus -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-BADARG %s
+
+!--- The driver warns when the target cannot honor the request -----------------
+
+! On a target without floating-point halting support, the driver warns and the
! option is ignored at run time.
-! RUN: %if powerpc-registered-target %{ \
-! RUN: %flang_fc1 -triple powerpc64-ibm-aix -ffpe-trap=invalid -fsyntax-only %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-WARN %s %}
+! RUN: %flang --target=powerpc64-ibm-aix -ffpe-trap=invalid -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-WARN %s
! CHECK-WARN: warning: ignoring '-ffpe-trap=invalid' option as it is not currently supported for target 'powerpc64-ibm-aix'
! On a supported non-x86 target (glibc/Linux), no warning is emitted.
-! RUN: %if aarch64-registered-target %{ \
-! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -ffpe-trap=invalid -fsyntax-only %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-NOWARN --allow-empty %s %}
+! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-NOWARN --allow-empty %s
! CHECK-NOWARN-NOT: ignoring '-ffpe-trap
! The "denormal" exception is an x86-only extension: requesting it for a non-x86
! target warns even though the target is otherwise supported.
-! RUN: %if aarch64-registered-target %{ \
-! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -ffpe-trap=invalid,denormal -fsyntax-only %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-DENORM %s %}
+! RUN: %flang --target=aarch64-unknown-linux-gnu -ffpe-trap=invalid,denormal -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-DENORM %s
! CHECK-DENORM: warning: ignoring '-ffpe-trap=denormal' option as it is not currently supported for target 'aarch64-unknown-linux-gnu'
! On x86 the "denormal" exception is supported, so no warning is emitted.
-! RUN: %if x86-registered-target %{ \
-! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -ffpe-trap=denormal -fsyntax-only %s 2>&1 \
-! RUN: | FileCheck --check-prefix=CHECK-X86DENORM --allow-empty %s %}
+! RUN: %flang --target=x86_64-unknown-linux-gnu -ffpe-trap=denormal -### %s 2>&1 \
+! RUN: | FileCheck --check-prefix=CHECK-X86DENORM --allow-empty %s
! CHECK-X86DENORM-NOT: ignoring '-ffpe-trap
end program
More information about the cfe-commits
mailing list