https://github.com/maarcosrmz updated 
https://github.com/llvm/llvm-project/pull/199009

>From 6e71dee1be6b8156e82b1ecb746933549c7dedb3 Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Sun, 17 May 2026 22:43:47 +0200
Subject: [PATCH 1/8] Add clang warning if fp exception functions are called
 without appropriate flags/pragmas (#187860)

Fixes https://github.com/llvm/llvm-project/issues/128239

The implementation adds warnings for floating-point exception function
calls (fenv.h) made without enabling floating-point exception behavior
via `-ffp-exception-behavior=maytrap/strict` or `#pragma STDC
FENV_ACCESS ON`. To support recognition of all fenv.h builtins,
`fexcept_t` and `fenv_t` were added as builtin types.
---
 clang/include/clang/AST/ASTContext.h          | 35 +++++++++-
 clang/include/clang/Basic/BuiltinHeaders.def  |  1 +
 clang/include/clang/Basic/Builtins.td         | 55 +++++++++++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 ++
 clang/include/clang/Basic/TokenKinds.def      |  2 +
 clang/include/clang/Sema/Sema.h               |  4 ++
 .../include/clang/Serialization/ASTBitCodes.h |  8 ++-
 clang/lib/AST/ASTContext.cpp                  | 19 ++++++
 clang/lib/Sema/SemaChecking.cpp               | 18 +++++
 clang/lib/Sema/SemaDecl.cpp                   |  8 +++
 clang/lib/Serialization/ASTReader.cpp         | 36 ++++++++++
 clang/lib/Serialization/ASTWriter.cpp         |  2 +
 clang/test/PCH/builtins-fenv.c                | 25 +++++++
 clang/test/PCH/builtins-fenv.h                | 18 +++++
 clang/test/Sema/builtin-fenv.c                | 51 ++++++++++++++
 clang/test/Sema/fenv-access-implicit.c        | 35 ++++++++++
 clang/test/Sema/fenv-access-unevaluated.cpp   | 31 +++++++++
 clang/test/Sema/fenv-access.c                 | 68 +++++++++++++++++++
 clang/utils/TableGen/ClangBuiltinsEmitter.cpp |  2 +
 19 files changed, 421 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/PCH/builtins-fenv.c
 create mode 100644 clang/test/PCH/builtins-fenv.h
 create mode 100644 clang/test/Sema/builtin-fenv.c
 create mode 100644 clang/test/Sema/fenv-access-implicit.c
 create mode 100644 clang/test/Sema/fenv-access-unevaluated.cpp
 create mode 100644 clang/test/Sema/fenv-access.c

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 2f7d39599c477..9f9b9695cafe9 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -521,6 +521,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// The type for the C ucontext_t type.
   TypeDecl *ucontext_tDecl = nullptr;
 
+  /// The type for the C fexcept_t type.
+  TypeDecl *fexcept_tDecl = nullptr;
+
+  /// The type for the C fenv_t type.
+  TypeDecl *fenv_tDecl = nullptr;
+
   /// Type for the Block descriptor for Blocks CodeGen.
   ///
   /// Since this is only used for generation of debug info, it is not
@@ -2432,6 +2438,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
     return QualType();
   }
 
+  /// Set the type for the C fexcept_t type.
+  void setfexcept_tDecl(TypeDecl *fexcept_tDecl) {
+    this->fexcept_tDecl = fexcept_tDecl;
+  }
+
+  /// Retrieve the C fexcept_t type.
+  QualType getfexcept_tType() const {
+    if (fexcept_tDecl)
+      return getTypeDeclType(ElaboratedTypeKeyword::None,
+                             /*Qualifier=*/std::nullopt, fexcept_tDecl);
+    return QualType();
+  }
+
+  /// Set the type for the C fenv_t type.
+  void setfenv_tDecl(TypeDecl *fenv_tDecl) { this->fenv_tDecl = fenv_tDecl; }
+
+  /// Retrieve the C fenv_t type.
+  QualType getfenv_tType() const {
+    if (fenv_tDecl)
+      return getTypeDeclType(ElaboratedTypeKeyword::None,
+                             /*Qualifier=*/std::nullopt, fenv_tDecl);
+    return QualType();
+  }
+
   /// The result type of logical operations, '<', '>', '!=', etc.
   CanQualType getLogicalOperationType() const {
     return getLangOpts().CPlusPlus ? BoolTy : IntTy;
@@ -2728,7 +2758,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
     GE_Missing_setjmp,
 
     /// Missing a type from <ucontext.h>
-    GE_Missing_ucontext
+    GE_Missing_ucontext,
+
+    /// Missing a type from <fenv.h>
+    GE_Missing_fenv
   };
 
   QualType DecodeTypeStr(const char *&Str, const ASTContext &Context,
diff --git a/clang/include/clang/Basic/BuiltinHeaders.def 
b/clang/include/clang/Basic/BuiltinHeaders.def
index b18e470a8bd25..d47803aafafa7 100644
--- a/clang/include/clang/Basic/BuiltinHeaders.def
+++ b/clang/include/clang/Basic/BuiltinHeaders.def
@@ -17,6 +17,7 @@ HEADER(BLOCKS_H, "Blocks.h")
 HEADER(COMPLEX_H, "complex.h")
 HEADER(CTYPE_H, "ctype.h")
 HEADER(EMMINTRIN_H, "emmintrin.h")
+HEADER(FENV_H, "fenv.h")
 HEADER(FOUNDATION_NSOBJCRUNTIME_H, "Foundation/NSObjCRuntime.h")
 HEADER(IMMINTRIN_H, "immintrin.h")
 HEADER(INTRIN_H, "intrin.h")
diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 90340ad7f812c..103f49d743bec 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4698,6 +4698,61 @@ def BlockObjectDispose : LibBuiltin<"blocks.h"> {
 }
 // FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
 
+def FeClearExcept : LibBuiltin<"fenv.h"> {
+  let Spellings = ["feclearexcept"];
+  let Prototype = "int(int)";
+}
+
+def FeGetExceptFlag : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fegetexceptflag"];
+  let Prototype = "int(fexcept_t*, int)";
+}
+
+def FeRaiseExcept : LibBuiltin<"fenv.h"> {
+  let Spellings = ["feraiseexcept"];
+  let Prototype = "int(int)";
+}
+
+def FeSetExceptFlag : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fesetexceptflag"];
+  let Prototype = "int(fexcept_t const*, int)";
+}
+
+def FeTestExcept : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fetestexcept"];
+  let Prototype = "int(int)";
+}
+
+def FeGetRound : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fegetround"];
+  let Prototype = "int()";
+}
+
+def FeSetRound : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fesetround"];
+  let Prototype = "int(int)";
+}
+
+def FeGetEnv : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fegetenv"];
+  let Prototype = "int(fenv_t*)";
+}
+
+def FeHoldExcept : LibBuiltin<"fenv.h"> {
+  let Spellings = ["feholdexcept"];
+  let Prototype = "int(fenv_t*)";
+}
+
+def FeSetEnv : LibBuiltin<"fenv.h"> {
+  let Spellings = ["fesetenv"];
+  let Prototype = "int(fenv_t const*)";
+}
+
+def FeUpdateEnv : LibBuiltin<"fenv.h"> {
+  let Spellings = ["feupdateenv"];
+  let Prototype = "int(fenv_t const*)";
+}
+
 def __Addressof : LangBuiltin<"CXX_LANG"> {
   let Spellings = ["__addressof"];
   let Attributes = [FunctionWithoutBuiltinPrefix, NoThrow, Const,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 485145addad01..d61e2870d14f3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1093,6 +1093,11 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : 
Error<
   "%select{subtraction|addition}0 of address-of-label expressions is not "
   "supported with ptrauth indirect gotos">;
 
+def warn_fe_access_without_fenv_access : Warning<
+  "'%0' used without enabling floating-point exception behavior; use 'pragma 
STDC "
+  "FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'">,
+  InGroup<DiagGroup<"fenv-access">>;
+
 // __ptrauth qualifier
 def err_ptrauth_qualifier_invalid : Error<
   "%select{return type|parameter type|property}1 may not be qualified with "
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index dc9c7d8109467..59c0b98365e20 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -730,6 +730,8 @@ NOTABLE_IDENTIFIER(FILE)
 NOTABLE_IDENTIFIER(jmp_buf)
 NOTABLE_IDENTIFIER(sigjmp_buf)
 NOTABLE_IDENTIFIER(ucontext_t)
+NOTABLE_IDENTIFIER(fexcept_t)
+NOTABLE_IDENTIFIER(fenv_t)
 NOTABLE_IDENTIFIER(float_t)
 NOTABLE_IDENTIFIER(double_t)
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0864337a9374c..c8e9173d2ae2c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8210,6 +8210,10 @@ class Sema final : public SemaBase {
     return currentEvaluationContext().isUnevaluated();
   }
 
+  bool isPotentiallyEvaluatedContext() const {
+    return currentEvaluationContext().isPotentiallyEvaluated();
+  }
+
   bool isImmediateFunctionContext() const {
     return currentEvaluationContext().isImmediateFunctionContext();
   }
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h 
b/clang/include/clang/Serialization/ASTBitCodes.h
index 6a52a9e4fa780..71dee22488a96 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1220,7 +1220,13 @@ enum SpecialTypeIDs {
   SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6,
 
   /// C ucontext_t typedef type
-  SPECIAL_TYPE_UCONTEXT_T = 7
+  SPECIAL_TYPE_UCONTEXT_T = 7,
+
+  /// C fexcept_t typedef type
+  SPECIAL_TYPE_FEXCEPT_T = 8,
+
+  /// C fenv_t typedef type
+  SPECIAL_TYPE_FENV_T = 9
 };
 
 /// The number of special type IDs.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ef3e6e87ec1fe..b01e9cc2f46e1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12920,6 +12920,25 @@ static QualType DecodeTypeFromStr(const char *&Str, 
const ASTContext &Context,
   case 'm':
     Type = Context.MFloat8Ty;
     break;
+  case 'T':
+    switch (*Str++) {
+    case 'x': {
+      Type = Context.getfexcept_tType();
+      break;
+    }
+    case 'e': {
+      Type = Context.getfenv_tType();
+      break;
+    }
+    default: {
+      llvm_unreachable("Unexpected target builtin type");
+    }
+    }
+    if (Type.isNull()) {
+      Error = ASTContext::GE_Missing_fenv;
+      return {};
+    }
+    break;
   }
 
   // If there are modifiers and if we're allowed to parse them, go for it.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dcf91e901f57e..1e50a5e146fd8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4190,6 +4190,24 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
     if (BuiltinCountedByRef(TheCall))
       return ExprError();
     break;
+
+  case Builtin::BIfeclearexcept:
+  case Builtin::BIfegetexceptflag:
+  case Builtin::BIferaiseexcept:
+  case Builtin::BIfesetexceptflag:
+  case Builtin::BIfetestexcept:
+  case Builtin::BIfegetround:
+  case Builtin::BIfesetround:
+  case Builtin::BIfegetenv:
+  case Builtin::BIfeholdexcept:
+  case Builtin::BIfesetenv:
+  case Builtin::BIfeupdateenv:
+    if (TheCall->getFPFeaturesInEffect(getLangOpts()).getExceptionMode() ==
+            LangOptions::FPE_Ignore &&
+        isPotentiallyEvaluatedContext()) {
+      Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access)
+          << FDecl->getName() << TheCall->getSourceRange();
+    }
   }
 
   if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, 
TheCall))
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 88f25903d97c3..98b86613d4264 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2410,6 +2410,8 @@ static StringRef getHeaderName(Builtin::Context 
&BuiltinInfo, unsigned ID,
     return "setjmp.h";
   case ASTContext::GE_Missing_ucontext:
     return "ucontext.h";
+  case ASTContext::GE_Missing_fenv:
+    return "fenv.h";
   }
   llvm_unreachable("unhandled error kind");
 }
@@ -7079,6 +7081,12 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, 
TypedefNameDecl *NewTD,
       case tok::NotableIdentifierKind::ucontext_t:
         Context.setucontext_tDecl(NewTD);
         break;
+      case tok::NotableIdentifierKind::fexcept_t:
+        Context.setfexcept_tDecl(NewTD);
+        break;
+      case tok::NotableIdentifierKind::fenv_t:
+        Context.setfenv_tDecl(NewTD);
+        break;
       case tok::NotableIdentifierKind::float_t:
       case tok::NotableIdentifierKind::double_t:
         NewTD->addAttr(AvailableOnlyInDefaultEvalMethodAttr::Create(Context));
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index a9c230d767c50..22eff77781ca7 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -5774,6 +5774,42 @@ void ASTReader::InitializeContext() {
         }
       }
     }
+
+    if (TypeID Fexcept_t = SpecialTypes[SPECIAL_TYPE_FEXCEPT_T]) {
+      QualType Fexcept_tType = GetType(Fexcept_t);
+      if (Fexcept_tType.isNull()) {
+        Error("fexcept_t type is NULL");
+        return;
+      }
+
+      if (!Context.fexcept_tDecl) {
+        if (const TypedefType *Typedef = Fexcept_tType->getAs<TypedefType>())
+          Context.setfexcept_tDecl(Typedef->getDecl());
+        else {
+          const TagType *Tag = Fexcept_tType->getAs<TagType>();
+          assert(Tag && "Invalid fexcept_t type in AST file");
+          Context.setfexcept_tDecl(Tag->getDecl());
+        }
+      }
+    }
+
+    if (TypeID Fenv_t = SpecialTypes[SPECIAL_TYPE_FENV_T]) {
+      QualType Fenv_tType = GetType(Fenv_t);
+      if (Fenv_tType.isNull()) {
+        Error("fenv_t type is NULL");
+        return;
+      }
+
+      if (!Context.fenv_tDecl) {
+        if (const TypedefType *Typedef = Fenv_tType->getAs<TypedefType>())
+          Context.setfenv_tDecl(Typedef->getDecl());
+        else {
+          const TagType *Tag = Fenv_tType->getAs<TagType>();
+          assert(Tag && "Invalid fenv_t type in AST file");
+          Context.setfenv_tDecl(Tag->getDecl());
+        }
+      }
+    }
   }
 
   ReadPragmaDiagnosticMappings(Context.getDiagnostics());
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 944e68ea6481d..e8e5dddfd0033 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -6162,6 +6162,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema *SemaPtr, 
StringRef isysroot,
     AddTypeRef(Context, Context.ObjCClassRedefinitionType, SpecialTypes);
     AddTypeRef(Context, Context.ObjCSelRedefinitionType, SpecialTypes);
     AddTypeRef(Context, Context.getucontext_tType(), SpecialTypes);
+    AddTypeRef(Context, Context.getfexcept_tType(), SpecialTypes);
+    AddTypeRef(Context, Context.getfenv_tType(), SpecialTypes);
   }
 
   if (SemaPtr)
diff --git a/clang/test/PCH/builtins-fenv.c b/clang/test/PCH/builtins-fenv.c
new file mode 100644
index 0000000000000..72bcf4a134730
--- /dev/null
+++ b/clang/test/PCH/builtins-fenv.c
@@ -0,0 +1,25 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/builtins-fenv.h -fsyntax-only -verify %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %S/builtins-fenv.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s 
+
+// expected-no-diagnostics
+fexcept_t *flagp = 0;
+fenv_t *envp = 0;
+
+void f(void) {
+  #pragma STDC FENV_ACCESS ON
+  feclearexcept(FE_INVALID);
+  fegetexceptflag(flagp, FE_INVALID);
+  feraiseexcept(FE_INVALID);
+  fesetexceptflag(flagp, FE_INVALID);
+  fetestexcept(FE_INVALID);
+  fegetround();
+  fesetround(0);
+  fegetenv(envp);
+  feholdexcept(envp);
+  fesetenv(envp);
+  feupdateenv(envp);
+}
diff --git a/clang/test/PCH/builtins-fenv.h b/clang/test/PCH/builtins-fenv.h
new file mode 100644
index 0000000000000..8397c270df58e
--- /dev/null
+++ b/clang/test/PCH/builtins-fenv.h
@@ -0,0 +1,18 @@
+// Header for PCH test builtins-fenv.c
+
+#define FE_INVALID 1
+
+typedef struct {} fenv_t;
+typedef unsigned short int fexcept_t;
+
+int feclearexcept(int excepts);
+int fegetexceptflag(fexcept_t *flagp, int excepts);
+int feraiseexcept(int excepts);
+int fesetexceptflag(const fexcept_t *flagp, int excepts);
+int fetestexcept(int excepts);
+int fegetround(void);
+int fesetround(int rounding_mode);
+int fegetenv(fenv_t *envp);
+int feholdexcept(fenv_t *envp);
+int fesetenv(const fenv_t *envp);
+int feupdateenv(const fenv_t *envp);
diff --git a/clang/test/Sema/builtin-fenv.c b/clang/test/Sema/builtin-fenv.c
new file mode 100644
index 0000000000000..db8a5334d1073
--- /dev/null
+++ b/clang/test/Sema/builtin-fenv.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify=c,expected 
-DWRONG_FEXCEPT_T %s -ast-dump | FileCheck %s --check-prefixes=CHECK1,CHECK2
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify=c,expected 
-DRIGHT_FEXCEPT_T %s -ast-dump | FileCheck %s --check-prefixes=CHECK1,CHECK2
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify=c,expected 
-DONLY_FEXCEPT_T %s -ast-dump | FileCheck %s --check-prefixes=CHECK1,CHECK2
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify=c,expected 
-DNO_FEGETEXCEPTFLAG %s -ast-dump 2>&1 | FileCheck %s --check-prefixes=CHECK1
+
+// tests inspired by clang/test/Sema/builtin-setjmp.c
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if WRONG_FEXCEPT_T
+typedef unsigned short int fexcept_t;
+extern int fegetexceptflag(int, int); // c-warning {{incompatible 
redeclaration of library function 'fegetexceptflag'}}
+                                      // c-note@-1 {{'fegetexceptflag' is a 
builtin with type 'int (fexcept_t *, int)' (aka 'int (unsigned short *, int)')}}
+#elif RIGHT_FEXCEPT_T
+// c-no-diagnostics
+typedef unsigned short int fexcept_t;
+extern int fegetexceptflag(unsigned short int *, int); // OK, right type.
+#elif ONLY_FEXCEPT_T
+typedef long *fexcept_t;
+#endif
+
+void use(void) {
+  #pragma STDC FENV_ACCESS ON
+  fegetexceptflag(0, 0);
+  #if NO_FEGETEXCEPTFLAG
+  // cxx-error@-2 {{undeclared identifier 'fegetexceptflag'}}
+  // c-error@-3 {{call to undeclared function 'fegetexceptflag'; ISO C99 and 
later do not support implicit function declarations}}
+  // c-warning@-4 {{declaration of built-in function 'fegetexceptflag' 
requires inclusion of the header <fenv.h>}}
+  #elif ONLY_FEXCEPT_T
+  // cxx-error@-6 {{undeclared identifier 'fegetexceptflag'}}
+  // c-error@-7 {{call to undeclared library function 'fegetexceptflag' with 
type 'int (fexcept_t *, int)' (aka 'int (long **, int)'); ISO C99 and later do 
not support implicit function declarations}}
+  // c-note@-8 {{include the header <fenv.h> or explicitly provide a 
declaration for 'fegetexceptflag'}}
+  #else
+  // cxx-no-diagnostics
+  #endif
+
+  #ifdef NO_FEGETEXCEPTFLAG
+  // In this case, the regular AST dump doesn't dump the implicit declaration 
of 'fegetexceptflag'.
+  #pragma clang __debug dump fegetexceptflag 
+  #endif
+}
+
+// CHECK1: FunctionDecl {{.*}} used fegetexceptflag
+// CHECK2: BuiltinAttr {{.*}} Implicit
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/clang/test/Sema/fenv-access-implicit.c 
b/clang/test/Sema/fenv-access-implicit.c
new file mode 100644
index 0000000000000..0c4bd6b0eb855
--- /dev/null
+++ b/clang/test/Sema/fenv-access-implicit.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -verify -Wfenv-access %s
+
+typedef struct {} fenv_t;
+typedef unsigned short int fexcept_t;
+
+fexcept_t *flagp = 0;
+fenv_t *envp = 0;
+
+#define FE_INVALID 1
+
+void test_fenv_access_undeclared(void) {
+  #pragma STDC FENV_ACCESS ON
+  feclearexcept(FE_INVALID); // expected-note {{include the header <fenv.h> or 
explicitly provide a declaration for 'feclearexcept'}} \
+   expected-error {{call to undeclared library function 'feclearexcept' with 
type 'int (int)'; ISO C99 and later do not support implicit function 
declarations}}
+  fegetexceptflag(flagp, FE_INVALID); // expected-note {{include the header 
<fenv.h> or explicitly provide a declaration for 'fegetexceptflag'}} \
+   expected-error {{call to undeclared library function 'fegetexceptflag' with 
type 'int (fexcept_t *, int)' (aka 'int (unsigned short *, int)'); ISO C99 and 
later do not support implicit function declarations}}
+  feraiseexcept(FE_INVALID); // expected-note {{include the header <fenv.h> or 
explicitly provide a declaration for 'feraiseexcept'}} \
+   expected-error {{call to undeclared library function 'feraiseexcept' with 
type 'int (int)'; ISO C99 and later do not support implicit function 
declarations}}
+  fesetexceptflag(flagp, FE_INVALID); // expected-note {{include the header 
<fenv.h> or explicitly provide a declaration for 'fesetexceptflag'}} \
+   expected-error {{call to undeclared library function 'fesetexceptflag' with 
type 'int (const fexcept_t *, int)' (aka 'int (const unsigned short *, int)'); 
ISO C99 and later do not support implicit function declarations}}
+  fetestexcept(FE_INVALID); // expected-note {{include the header <fenv.h> or 
explicitly provide a declaration for 'fetestexcept'}} \
+   expected-error {{call to undeclared library function 'fetestexcept' with 
type 'int (int)'; ISO C99 and later do not support implicit function 
declarations}}
+  fegetround(); // expected-note {{include the header <fenv.h> or explicitly 
provide a declaration for 'fegetround'}} \
+   expected-error {{call to undeclared library function 'fegetround' with type 
'int (void)'; ISO C99 and later do not support implicit function declarations}}
+  fesetround(0); // expected-note {{include the header <fenv.h> or explicitly 
provide a declaration for 'fesetround'}} \
+   expected-error {{call to undeclared library function 'fesetround' with type 
'int (int)'; ISO C99 and later do not support implicit function declarations}}
+  fegetenv(envp); // expected-note {{include the header <fenv.h> or explicitly 
provide a declaration for 'fegetenv'}} \
+   expected-error {{call to undeclared library function 'fegetenv' with type 
'int (fenv_t *)'; ISO C99 and later do not support implicit function 
declarations}}
+  feholdexcept(envp); // expected-note {{include the header <fenv.h> or 
explicitly provide a declaration for 'feholdexcept'}} \
+   expected-error {{call to undeclared library function 'feholdexcept' with 
type 'int (fenv_t *)'; ISO C99 and later do not support implicit function 
declarations}}
+  fesetenv(envp); // expected-note {{include the header <fenv.h> or explicitly 
provide a declaration for 'fesetenv'}} \
+   expected-error {{call to undeclared library function 'fesetenv' with type 
'int (const fenv_t *)'; ISO C99 and later do not support implicit function 
declarations}}
+  feupdateenv(envp); // expected-note {{include the header <fenv.h> or 
explicitly provide a declaration for 'feupdateenv'}} \
+   expected-error {{call to undeclared library function 'feupdateenv' with 
type 'int (const fenv_t *)'; ISO C99 and later do not support implicit function 
declarations}}
+}
diff --git a/clang/test/Sema/fenv-access-unevaluated.cpp 
b/clang/test/Sema/fenv-access-unevaluated.cpp
new file mode 100644
index 0000000000000..14752ba3c377e
--- /dev/null
+++ b/clang/test/Sema/fenv-access-unevaluated.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -verify -Wfenv-access %s
+
+typedef struct {} fenv_t;
+typedef unsigned short int fexcept_t;
+
+int feclearexcept(int excepts);
+int fegetexceptflag(fexcept_t *flagp, int excepts);
+int feraiseexcept(int excepts);
+int fesetexceptflag(const fexcept_t *flagp, int excepts);
+int fetestexcept(int excepts);
+int fegetround(void);
+int fesetround(int rounding_mode);
+int fegetenv(fenv_t *envp);
+int feholdexcept(fenv_t *envp);
+int fesetenv(const fenv_t *envp);
+int feupdateenv(const fenv_t *envp);
+
+// expected-no-diagnostics
+void test_fenv_access_unevaluated() {
+  decltype(::feclearexcept) a;
+  decltype(::fegetexceptflag) b;
+  decltype(::feraiseexcept) c;
+  decltype(::fesetexceptflag) d;
+  decltype(::fetestexcept) e;
+  decltype(::fegetround) f;
+  decltype(::fesetround) g;
+  decltype(::fegetenv) h;
+  decltype(::feholdexcept) i;
+  decltype(::fesetenv) j;
+  decltype(::feupdateenv) k;
+}
diff --git a/clang/test/Sema/fenv-access.c b/clang/test/Sema/fenv-access.c
new file mode 100644
index 0000000000000..3a7b95af7ab4c
--- /dev/null
+++ b/clang/test/Sema/fenv-access.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -verify -Wfenv-access %s
+// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=maytrap 
-DNO_WARN %s
+// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=strict 
-DNO_WARN %s
+
+typedef struct {} fenv_t;
+typedef unsigned short int fexcept_t;
+
+int feclearexcept(int excepts);
+int fegetexceptflag(fexcept_t *flagp, int excepts);
+int feraiseexcept(int excepts);
+int fesetexceptflag(const fexcept_t *flagp, int excepts);
+int fetestexcept(int excepts);
+int fegetround(void);
+int fesetround(int rounding_mode);
+int fegetenv(fenv_t *envp);
+int feholdexcept(fenv_t *envp);
+int fesetenv(const fenv_t *envp);
+int feupdateenv(const fenv_t *envp);
+
+#define FE_INVALID 1
+
+fexcept_t *flagp = 0;
+fenv_t *envp = 0;
+
+void test_fenv_access_off(void) {
+#ifdef NO_WARN
+  // expected-no-diagnostics
+  feclearexcept(FE_INVALID);
+  fegetexceptflag(flagp, FE_INVALID);
+  feraiseexcept(FE_INVALID);
+  fesetexceptflag(flagp, FE_INVALID);
+  fetestexcept(FE_INVALID);
+  fegetround();
+  fesetround(0);
+  fegetenv(envp);
+  feholdexcept(envp);
+  fesetenv(envp);
+  feupdateenv(envp);
+#else 
+  feclearexcept(FE_INVALID); // expected-warning {{'feclearexcept' used 
without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
+  fegetexceptflag(flagp, FE_INVALID); // expected-warning {{'fegetexceptflag' 
used without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
+  feraiseexcept(FE_INVALID); // expected-warning {{'feraiseexcept' used 
without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
+  fesetexceptflag(flagp, FE_INVALID); // expected-warning {{'fesetexceptflag' 
used without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
+  fetestexcept(FE_INVALID); // expected-warning {{'fetestexcept' used without 
enabling floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or 
compile with '-ffp-exception-behavior=maytrap'}}
+  fegetround(); // expected-warning {{'fegetround' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+  fesetround(0); // expected-warning {{'fesetround' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+  fegetenv(envp); // expected-warning {{'fegetenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+  feholdexcept(envp); // expected-warning {{'feholdexcept' used without 
enabling floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or 
compile with '-ffp-exception-behavior=maytrap'}}
+  fesetenv(envp); // expected-warning {{'fesetenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+  feupdateenv(envp); // expected-warning {{'feupdateenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+#endif
+}
+
+void test_fenv_access_on(void) {
+  #pragma STDC FENV_ACCESS ON
+  fesetround(0);
+  feclearexcept(FE_INVALID);
+  fegetexceptflag(flagp, FE_INVALID);
+  feraiseexcept(FE_INVALID);
+  fesetexceptflag(flagp, FE_INVALID);
+  fetestexcept(FE_INVALID);
+  fegetround();
+  fesetround(0);
+  fegetenv(envp);
+  feholdexcept(envp);
+  fesetenv(envp);
+  feupdateenv(envp);
+}
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp 
b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 22c81522f9e41..3c378fe8bd746 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -383,6 +383,8 @@ class PrototypeParser {
                                .Case("uint64_t", "UWi")
                                .Case("void", "v")
                                .Case("wchar_t", "w")
+                               .Case("fexcept_t", "Tx")
+                               .Case("fenv_t", "Te")
                                .Case("...", ".")
                                .Default("error");
       if (ReturnTypeVal == "error")

>From a5b67c7eb83f6307efc038c485d7910fedd5591e Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Thu, 21 May 2026 15:10:06 +0200
Subject: [PATCH 2/8] Added check for strict FP support before warning

---
 clang/lib/Sema/SemaChecking.cpp | 4 +++-
 clang/test/Sema/fenv-access.c   | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1e50a5e146fd8..03e38b74ee52e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4204,7 +4204,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
   case Builtin::BIfeupdateenv:
     if (TheCall->getFPFeaturesInEffect(getLangOpts()).getExceptionMode() ==
             LangOptions::FPE_Ignore &&
-        isPotentiallyEvaluatedContext()) {
+        isPotentiallyEvaluatedContext() &&
+        (getASTContext().getTargetInfo().hasStrictFP() ||
+         getLangOpts().ExpStrictFP)) {
       Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access)
           << FDecl->getName() << TheCall->getSourceRange();
     }
diff --git a/clang/test/Sema/fenv-access.c b/clang/test/Sema/fenv-access.c
index 3a7b95af7ab4c..50a4d9fd16aa2 100644
--- a/clang/test/Sema/fenv-access.c
+++ b/clang/test/Sema/fenv-access.c
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -verify -Wfenv-access %s
 // RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=maytrap 
-DNO_WARN %s
 // RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=strict 
-DNO_WARN %s
+// RUN: %clang_cc1 -verify -Wfenv-access -triple armv7-linux-gnueabihf 
-DNO_WARN -DUNSUPPORTED %s
 
 typedef struct {} fenv_t;
 typedef unsigned short int fexcept_t;
@@ -52,7 +53,9 @@ void test_fenv_access_off(void) {
 }
 
 void test_fenv_access_on(void) {
+#ifndef UNSUPPORTED
   #pragma STDC FENV_ACCESS ON
+#endif
   fesetround(0);
   feclearexcept(FE_INVALID);
   fegetexceptflag(flagp, FE_INVALID);

>From 9aef1c78e1d8efcb324af57e5243fe05054638f9 Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Thu, 21 May 2026 15:19:25 +0200
Subject: [PATCH 3/8] Removed redundant extern "C" {} block in builtin-fenv.c

---
 clang/test/Sema/builtin-fenv.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/clang/test/Sema/builtin-fenv.c b/clang/test/Sema/builtin-fenv.c
index db8a5334d1073..c9b2306326326 100644
--- a/clang/test/Sema/builtin-fenv.c
+++ b/clang/test/Sema/builtin-fenv.c
@@ -5,10 +5,6 @@
 
 // tests inspired by clang/test/Sema/builtin-setjmp.c
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #if WRONG_FEXCEPT_T
 typedef unsigned short int fexcept_t;
 extern int fegetexceptflag(int, int); // c-warning {{incompatible 
redeclaration of library function 'fegetexceptflag'}}
@@ -44,8 +40,3 @@ void use(void) {
 
 // CHECK1: FunctionDecl {{.*}} used fegetexceptflag
 // CHECK2: BuiltinAttr {{.*}} Implicit
-
-
-#ifdef __cplusplus
-}
-#endif

>From a2a9a1f7db899aae64f18659239be456a66b8f85 Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Sat, 1 Aug 2026 20:24:57 +0200
Subject: [PATCH 4/8] Added release notes to new clang/docs/ReleaseNotes.md
 file

---
 clang/docs/ReleaseNotes.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 18d2895531ea6..1922f9c1d0893 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -513,6 +513,9 @@ features cannot lower the translation-unit ABI level;
 - Improve the input size mismatch diagnostic when calling 
`__builtin_shufflevector` with valid
   vector element types but different sizes. (GH221791)
 
+- Added warnings for floating-point exception function calls (fenv.h) without 
enabling floating-point
+  exception behavior via the appropriate flags or pragmas on supported 
targets. (#GH128239)
+
 ### Improvements to Clang's time-trace
 
 ### Improvements to Coverage Mapping

>From 548764d913f885874ccb464a2e7161a0b917f4ff Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Wed, 1 Jul 2026 15:55:12 +0200
Subject: [PATCH 5/8] Fix conflict in serialization of fenv_t and fexcept_t
 builtin types

---
 clang/lib/AST/ASTContext.cpp                  | 21 +++++++------------
 clang/utils/TableGen/ClangBuiltinsEmitter.cpp |  4 ++--
 2 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b01e9cc2f46e1..1572289c52ed5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12920,20 +12920,15 @@ static QualType DecodeTypeFromStr(const char *&Str, 
const ASTContext &Context,
   case 'm':
     Type = Context.MFloat8Ty;
     break;
-  case 'T':
-    switch (*Str++) {
-    case 'x': {
-      Type = Context.getfexcept_tType();
-      break;
-    }
-    case 'e': {
-      Type = Context.getfenv_tType();
-      break;
-    }
-    default: {
-      llvm_unreachable("Unexpected target builtin type");
-    }
+  case 't':
+    Type = Context.getfexcept_tType();
+    if (Type.isNull()) {
+      Error = ASTContext::GE_Missing_fenv;
+      return {};
     }
+    break;
+  case 'e':
+    Type = Context.getfenv_tType();
     if (Type.isNull()) {
       Error = ASTContext::GE_Missing_fenv;
       return {};
diff --git a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp 
b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
index 3c378fe8bd746..77b9259ffebf0 100644
--- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp
@@ -383,8 +383,8 @@ class PrototypeParser {
                                .Case("uint64_t", "UWi")
                                .Case("void", "v")
                                .Case("wchar_t", "w")
-                               .Case("fexcept_t", "Tx")
-                               .Case("fenv_t", "Te")
+                               .Case("fexcept_t", "t")
+                               .Case("fenv_t", "e")
                                .Case("...", ".")
                                .Default("error");
       if (ReturnTypeVal == "error")

>From a64bbdcd9b692bd6602ffdf5cf2ae0f9876222d3 Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Sun, 9 Aug 2026 18:48:44 +0200
Subject: [PATCH 6/8] Make warning gcc compatible & add rounding mode check to
 warning condition

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 +++---
 clang/lib/Sema/SemaChecking.cpp                  | 8 +++++---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d61e2870d14f3..d7b5d7a935afd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1093,9 +1093,9 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : 
Error<
   "%select{subtraction|addition}0 of address-of-label expressions is not "
   "supported with ptrauth indirect gotos">;
 
-def warn_fe_access_without_fenv_access : Warning<
-  "'%0' used without enabling floating-point exception behavior; use 'pragma 
STDC "
-  "FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'">,
+def warn_fenv_access_no_exception_semantics_or_rounding_mode : Warning<
+  "'%0' used without enabling strict floating-point exception semantics and 
dynamic rounding mode;"
+  " use '#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'">,
   InGroup<DiagGroup<"fenv-access">>;
 
 // __ptrauth qualifier
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 03e38b74ee52e..2d15f2d757fa8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4202,12 +4202,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
   case Builtin::BIfeholdexcept:
   case Builtin::BIfesetenv:
   case Builtin::BIfeupdateenv:
-    if (TheCall->getFPFeaturesInEffect(getLangOpts()).getExceptionMode() ==
-            LangOptions::FPE_Ignore &&
+    const FPOptions &fpOpts = TheCall->getFPFeaturesInEffect(getLangOpts());
+    if ((fpOpts.getExceptionMode() == LangOptions::FPE_Ignore ||
+         fpOpts.getRoundingMode() != LangOptions::RoundingMode::Dynamic) &&
         isPotentiallyEvaluatedContext() &&
         (getASTContext().getTargetInfo().hasStrictFP() ||
          getLangOpts().ExpStrictFP)) {
-      Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access)
+      Diag(TheCall->getBeginLoc(),
+           diag::warn_fenv_access_no_exception_semantics_or_rounding_mode)
           << FDecl->getName() << TheCall->getSourceRange();
     }
   }

>From 6507303deaf4ba5388ee11ec2301fef51fcb6a4e Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Sun, 9 Aug 2026 19:13:05 +0200
Subject: [PATCH 7/8] Fix Sema test for fenv-access warning

---
 clang/test/Sema/fenv-access.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/clang/test/Sema/fenv-access.c b/clang/test/Sema/fenv-access.c
index 50a4d9fd16aa2..2d7d0aa028192 100644
--- a/clang/test/Sema/fenv-access.c
+++ b/clang/test/Sema/fenv-access.c
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -verify -Wfenv-access %s
-// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=maytrap 
-DNO_WARN %s
-// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=strict 
-DNO_WARN %s
+// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=strict %s
+// RUN: %clang_cc1 -verify -Wfenv-access -frounding-math %s
+// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=strict 
-frounding-math -DNO_WARN %s
+// RUN: %clang_cc1 -verify -Wfenv-access -ffp-exception-behavior=maytrap 
-frounding-math -DNO_WARN %s
 // RUN: %clang_cc1 -verify -Wfenv-access -triple armv7-linux-gnueabihf 
-DNO_WARN -DUNSUPPORTED %s
 
 typedef struct {} fenv_t;
@@ -37,18 +39,18 @@ void test_fenv_access_off(void) {
   feholdexcept(envp);
   fesetenv(envp);
   feupdateenv(envp);
-#else 
-  feclearexcept(FE_INVALID); // expected-warning {{'feclearexcept' used 
without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
-  fegetexceptflag(flagp, FE_INVALID); // expected-warning {{'fegetexceptflag' 
used without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
-  feraiseexcept(FE_INVALID); // expected-warning {{'feraiseexcept' used 
without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
-  fesetexceptflag(flagp, FE_INVALID); // expected-warning {{'fesetexceptflag' 
used without enabling floating-point exception behavior; use 'pragma STDC 
FENV_ACCESS ON' or compile with '-ffp-exception-behavior=maytrap'}}
-  fetestexcept(FE_INVALID); // expected-warning {{'fetestexcept' used without 
enabling floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or 
compile with '-ffp-exception-behavior=maytrap'}}
-  fegetround(); // expected-warning {{'fegetround' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
-  fesetround(0); // expected-warning {{'fesetround' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
-  fegetenv(envp); // expected-warning {{'fegetenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
-  feholdexcept(envp); // expected-warning {{'feholdexcept' used without 
enabling floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or 
compile with '-ffp-exception-behavior=maytrap'}}
-  fesetenv(envp); // expected-warning {{'fesetenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
-  feupdateenv(envp); // expected-warning {{'feupdateenv' used without enabling 
floating-point exception behavior; use 'pragma STDC FENV_ACCESS ON' or compile 
with '-ffp-exception-behavior=maytrap'}}
+#else
+  feclearexcept(FE_INVALID); // expected-warning {{'feclearexcept' used 
without enabling strict floating-point exception semantics and dynamic rounding 
mode; use '#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fegetexceptflag(flagp, FE_INVALID); // expected-warning {{'fegetexceptflag' 
used without enabling strict floating-point exception semantics and dynamic 
rounding mode; use '#pragma STDC FENV_ACCESS ON' or compile with 
'-ftrapping-math -frounding-math'}}
+  feraiseexcept(FE_INVALID); // expected-warning {{'feraiseexcept' used 
without enabling strict floating-point exception semantics and dynamic rounding 
mode; use '#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fesetexceptflag(flagp, FE_INVALID); // expected-warning {{'fesetexceptflag' 
used without enabling strict floating-point exception semantics and dynamic 
rounding mode; use '#pragma STDC FENV_ACCESS ON' or compile with 
'-ftrapping-math -frounding-math'}}
+  fetestexcept(FE_INVALID); // expected-warning {{'fetestexcept' used without 
enabling strict floating-point exception semantics and dynamic rounding mode; 
use '#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fegetround(); // expected-warning {{'fegetround' used without enabling 
strict floating-point exception semantics and dynamic rounding mode; use 
'#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fesetround(0); // expected-warning {{'fesetround' used without enabling 
strict floating-point exception semantics and dynamic rounding mode; use 
'#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fegetenv(envp); // expected-warning {{'fegetenv' used without enabling 
strict floating-point exception semantics and dynamic rounding mode; use 
'#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  feholdexcept(envp); // expected-warning {{'feholdexcept' used without 
enabling strict floating-point exception semantics and dynamic rounding mode; 
use '#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  fesetenv(envp); // expected-warning {{'fesetenv' used without enabling 
strict floating-point exception semantics and dynamic rounding mode; use 
'#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
+  feupdateenv(envp); // expected-warning {{'feupdateenv' used without enabling 
strict floating-point exception semantics and dynamic rounding mode; use 
'#pragma STDC FENV_ACCESS ON' or compile with '-ftrapping-math 
-frounding-math'}}
 #endif
 }
 

>From e8bce8579f2d7e70256d7f65f963b4d4d9f635a5 Mon Sep 17 00:00:00 2001
From: Marcos Ramirez Joos <[email protected]>
Date: Fri, 18 Sep 2026 22:12:45 +0100
Subject: [PATCH 8/8] Add build configuration-time check for FP access pragma

---
 flang-rt/CMakeLists.txt                    | 13 -----------
 flang-rt/lib/runtime/edit-input.cpp        |  2 ++
 flang-rt/lib/runtime/exceptions.cpp        |  6 +++---
 flang-rt/unittests/Runtime/Exceptions.cpp  |  8 +++----
 flang/cmake/modules/FlangCommon.cmake      | 25 ++++++++++++++++++++++
 flang/include/flang/Common/fp-control.h    | 20 +++++++----------
 flang/lib/Evaluate/host.cpp                |  3 +++
 llvm/cmake/modules/HandleLLVMOptions.cmake | 25 ++++++++++++++++++++++
 llvm/include/llvm/Support/Compiler.h       |  6 ++++++
 llvm/lib/Analysis/ConstantFolding.cpp      |  2 ++
 10 files changed, 78 insertions(+), 32 deletions(-)

diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 4f480151eb56b..0e4fb82139950 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -171,19 +171,6 @@ if (FLANG_RT_INCLUDE_CUF)
   endif ()
 endif()
 
-# A recently added check in clang emits warnings for feclearexcept and 
fesetround:
-#   'fesetround' used without enabling floating-point exception behavior; use
-#         'pragma STDC FENV_ACCESS ON' or compile with
-#         '-ffp-exception-behavior=maytrap' [-Werror,-Wfenv-access]
-# This breaks the CI build (because of -Werror).
-if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
-  check_cxx_compiler_flag("-Werror -Wno-fenv-access" 
CXX_SUPPORTS_NO_FENV_ACCESS_FLAG)
-  if (CXX_SUPPORTS_NO_FENV_ACCESS_FLAG)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-fenv-access")
-  endif()
-endif()  # Clang
-
-
 ########################
 # System Introspection #
 ########################
diff --git a/flang-rt/lib/runtime/edit-input.cpp 
b/flang-rt/lib/runtime/edit-input.cpp
index 6a05974893e51..69fc309dc79a1 100644
--- a/flang-rt/lib/runtime/edit-input.cpp
+++ b/flang-rt/lib/runtime/edit-input.cpp
@@ -12,6 +12,7 @@
 #include "flang/Common/optional.h"
 #include "flang/Common/real.h"
 #include "flang/Common/uint128.h"
+#include "flang/Common/fp-control.h"
 #include "flang/Runtime/freestanding-tools.h"
 #include <algorithm>
 #include <cfenv>
@@ -559,6 +560,7 @@ static RT_API_ATTRS ScannedRealInput ScanRealInput(
 
 static RT_API_ATTRS void RaiseFPExceptions(
     decimal::ConversionResultFlags flags) {
+  FLANG_FENV_ACCESS_ON
 #undef RAISE
 #if defined(RT_DEVICE_COMPILATION)
   Terminator terminator(__FILE__, __LINE__);
diff --git a/flang-rt/lib/runtime/exceptions.cpp 
b/flang-rt/lib/runtime/exceptions.cpp
index 33cb9945c863a..2f02de5624abc 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -89,7 +89,7 @@ uint32_t RTDEF(MapException)(uint32_t excepts) {
 // component; both are needed.
 
 void RTNAME(feclearexcept)(uint32_t excepts) {
-  FLANG_FP_TRAP_ON
+  FLANG_FENV_ACCESS_ON
   feclearexcept(excepts);
 #if defined(_MM_EXCEPT_DENORM)
   _mm_setcsr(_mm_getcsr() & ~(excepts & _MM_EXCEPT_MASK));
@@ -97,7 +97,7 @@ void RTNAME(feclearexcept)(uint32_t excepts) {
 }
 void RTDEF(feraiseexcept)(uint32_t excepts) {
 #if !defined(RT_DEVICE_COMPILATION)
-  FLANG_FP_TRAP_ON
+  FLANG_FENV_ACCESS_ON
   feraiseexcept(excepts);
 #if defined(_MM_EXCEPT_DENORM)
   _mm_setcsr(_mm_getcsr() | (excepts & _MM_EXCEPT_MASK));
@@ -105,7 +105,7 @@ void RTDEF(feraiseexcept)(uint32_t excepts) {
 #endif
 }
 uint32_t RTNAME(fetestexcept)(uint32_t excepts) {
-  FLANG_FP_TRAP_ON
+  FLANG_FENV_ACCESS_ON
 #if defined(_MM_EXCEPT_DENORM)
   return (_mm_getcsr() & _MM_EXCEPT_MASK & excepts) | fetestexcept(excepts);
 #else
diff --git a/flang-rt/unittests/Runtime/Exceptions.cpp 
b/flang-rt/unittests/Runtime/Exceptions.cpp
index 2b2526b6cf1e3..2ccc03b845c69 100644
--- a/flang-rt/unittests/Runtime/Exceptions.cpp
+++ b/flang-rt/unittests/Runtime/Exceptions.cpp
@@ -13,8 +13,8 @@
 /// calls: under clang's default `-ffp-exception-behavior=ignore`, the
 /// compiler is free to drop calls to fenv functions, which would silently
 /// break ieee_arithmetic flag handling.  exceptions.cpp uses
-/// `FLANG_FP_TRAP_ON` to disable that optimization; if it were ever removed
-/// or weakened, the round-trip assertions below would fail.
+/// `FLANG_FENV_ACCESS_ON` to disable that optimization; if it were ever
+/// removed or weakened, the round-trip assertions below would fail.
 //
 
//===----------------------------------------------------------------------===//
 
@@ -35,11 +35,11 @@ namespace {
 class FenvScope {
 public:
   FenvScope() {
-    FLANG_FP_TRAP_ON
+    FLANG_FENV_ACCESS_ON
     fegetenv(&saved_);
   }
   ~FenvScope() {
-    FLANG_FP_TRAP_ON
+    FLANG_FENV_ACCESS_ON
     fesetenv(&saved_);
   }
 
diff --git a/flang/cmake/modules/FlangCommon.cmake 
b/flang/cmake/modules/FlangCommon.cmake
index a1e80f737e543..d5ace5386aeb0 100644
--- a/flang/cmake/modules/FlangCommon.cmake
+++ b/flang/cmake/modules/FlangCommon.cmake
@@ -11,9 +11,34 @@
 
#===------------------------------------------------------------------------===#
 
 include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
 include(CheckIncludeFile)
 include(CMakePushCheckState)
 
+# Check whether the compiler honors '#pragma STDC FENV_ACCESS ON'
+set(FLANG_SAVED_TRY_COMPILE_TARGET_TYPE "${CMAKE_TRY_COMPILE_TARGET_TYPE}")
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+cmake_push_check_state()
+if(MSVC)
+  string(APPEND CMAKE_REQUIRED_FLAGS " /WX")
+else()
+  string(APPEND CMAKE_REQUIRED_FLAGS " -Wall -Werror")
+endif()
+check_cxx_source_compiles(
+  "int probe() {
+   #pragma STDC FENV_ACCESS ON
+     return 0;
+   }
+  "
+  COMPILER_SUPPORTS_STDC_FENV_ACCESS_PRAGMA)
+cmake_pop_check_state()
+set(CMAKE_TRY_COMPILE_TARGET_TYPE "${FLANG_SAVED_TRY_COMPILE_TARGET_TYPE}")
+unset(FLANG_SAVED_TRY_COMPILE_TARGET_TYPE)
+
+if(COMPILER_SUPPORTS_STDC_FENV_ACCESS_PRAGMA)
+  add_compile_definitions(HAVE_STDC_FENV_ACCESS)
+endif()
+
 # The out of tree builds of the compiler and the Fortran runtime
 # must use the same setting of FLANG_RUNTIME_F128_MATH_LIB
 # to be composable. Failure to synchronize this setting may result
diff --git a/flang/include/flang/Common/fp-control.h 
b/flang/include/flang/Common/fp-control.h
index a6e5c3bda3335..a231b8352aeee 100644
--- a/flang/include/flang/Common/fp-control.h
+++ b/flang/include/flang/Common/fp-control.h
@@ -6,29 +6,25 @@
 //
 
//===----------------------------------------------------------------------===//
 
-// FLANG_FP_TRAP_ON enables floating-point exception access in the
-// enclosing scope.  It silences clang's -Wfenv-access warning on calls to
-// fenv.h primitives (feraiseexcept, fesetround, fetestexcept, ...).
+// FLANG_FENV_ACCESS_ON enables floating-point environment access in the
+// enclosing scope, so that the compiler does not reorder or elide calls to
+// fenv.h primitives (feraiseexcept, fesetround, fetestexcept, ...).  It also
+// silences clang's -Wfenv-access diagnostic on those calls.
 //
 // Use as a statement at the top of a function body:
 //
 //   void f() {
-//     FLANG_FP_TRAP_ON
+//     FLANG_FENV_ACCESS_ON
 //     feraiseexcept(FE_INVALID);
 //   }
-//
 
 #ifndef FORTRAN_COMMON_FP_CONTROL_H_
 #define FORTRAN_COMMON_FP_CONTROL_H_
 
-#if defined(__clang__) && (__clang_major__ >= 10)
-// Clang >= 10 supports `#pragma clang fp exceptions(maytrap)`, which is the
-// local-scope equivalent of `-ffp-exception-behavior=maytrap` and is what the
-// -Wfenv-access diagnostic recommends.
-#define FLANG_FP_TRAP_ON _Pragma("clang fp exceptions(maytrap)")
+#ifdef HAVE_STDC_FENV_ACCESS 
+#define FLANG_FENV_ACCESS_ON _Pragma("STDC FENV_ACCESS ON")
 #else
-// Portable fallback for GCC, MSVC, or older clang.
-#define FLANG_FP_TRAP_ON _Pragma("STDC FENV_ACCESS ON")
+#define FLANG_FENV_ACCESS_ON
 #endif
 
 #endif // FORTRAN_COMMON_FP_CONTROL_H_
diff --git a/flang/lib/Evaluate/host.cpp b/flang/lib/Evaluate/host.cpp
index bf0249647162a..880a8add6dfc8 100644
--- a/flang/lib/Evaluate/host.cpp
+++ b/flang/lib/Evaluate/host.cpp
@@ -8,6 +8,7 @@
 
 #include "host.h"
 
+#include "flang/Common/fp-control.h"
 #include "flang/Common/idioms.h"
 #include "llvm/Support/Errno.h"
 #include <cfenv>
@@ -20,6 +21,7 @@ using namespace Fortran::parser::literals;
 
 void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(
     FoldingContext &context) {
+  FLANG_FENV_ACCESS_ON
   errno = 0;
   std::fenv_t currentFenv;
   if (feholdexcept(&originalFenv_) != 0) {
@@ -109,6 +111,7 @@ void 
HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(
 }
 void HostFloatingPointEnvironment::CheckAndRestoreFloatingPointEnvironment(
     FoldingContext &context) {
+  FLANG_FENV_ACCESS_ON
   int errnoCapture{errno};
   if (hardwareFlagsAreReliable()) {
     int exceptions{fetestexcept(FE_ALL_EXCEPT)};
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake 
b/llvm/cmake/modules/HandleLLVMOptions.cmake
index 4ff38fbb4c09c..593d3bbdc3ae3 100644
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -1560,6 +1560,31 @@ function(get_compile_definitions)
 endfunction()
 get_compile_definitions()
 
+# Check whether the compiler honors '#pragma STDC FENV_ACCESS ON'
+include(CMakePushCheckState)
+set(LLVM_SAVED_TRY_COMPILE_TARGET_TYPE "${CMAKE_TRY_COMPILE_TARGET_TYPE}")
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+cmake_push_check_state()
+if(MSVC)
+  string(APPEND CMAKE_REQUIRED_FLAGS " /WX")
+else()
+  string(APPEND CMAKE_REQUIRED_FLAGS " -Wall -Werror")
+endif()
+check_cxx_source_compiles(
+  "int probe() {
+   #pragma STDC FENV_ACCESS ON
+     return 0;
+   }
+  "
+  COMPILER_SUPPORTS_STDC_FENV_ACCESS_PRAGMA)
+cmake_pop_check_state()
+set(CMAKE_TRY_COMPILE_TARGET_TYPE "${LLVM_SAVED_TRY_COMPILE_TARGET_TYPE}")
+unset(LLVM_SAVED_TRY_COMPILE_TARGET_TYPE)
+
+if(COMPILER_SUPPORTS_STDC_FENV_ACCESS_PRAGMA)
+  add_compile_definitions(HAVE_STDC_FENV_ACCESS)
+endif()
+
 option(LLVM_FORCE_ENABLE_STATS "Enable statistics collection for builds that 
wouldn't normally enable it" OFF)
 
 check_symbol_exists(os_signpost_interval_begin "os/signpost.h" 
macos_signposts_available)
diff --git a/llvm/include/llvm/Support/Compiler.h 
b/llvm/include/llvm/Support/Compiler.h
index 33ea019a87be5..9a08b01bdd45f 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -811,4 +811,10 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
 #define LLVM_CPU_SUPPORTS_SSE42 LLVM_CPU_SUPPORTS("sse4.2")
 #endif
 
+#ifdef HAVE_STDC_FENV_ACCESS 
+#define LLVM_FENV_ACCESS_ON _Pragma("STDC FENV_ACCESS ON")
+#else
+#define LLVM_FENV_ACCESS_ON
+#endif
+
 #endif
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp 
b/llvm/lib/Analysis/ConstantFolding.cpp
index 9b29d5fa6d593..080e4b6f48e98 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2240,6 +2240,7 @@ Constant *GetConstantFoldFPValue128(float128 V, Type *Ty) 
{
 /// Clear the floating-point exception state.
 inline void llvm_fenv_clearexcept() {
 #if defined(FE_ALL_EXCEPT)
+  LLVM_FENV_ACCESS_ON
   feclearexcept(FE_ALL_EXCEPT);
 #endif
   errno = 0;
@@ -2247,6 +2248,7 @@ inline void llvm_fenv_clearexcept() {
 
 /// Test if a floating-point exception was raised.
 inline bool llvm_fenv_testexcept() {
+  LLVM_FENV_ACCESS_ON
   int errno_val = errno;
   if (errno_val == ERANGE || errno_val == EDOM)
     return true;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to