https://github.com/maarcosrmz updated https://github.com/llvm/llvm-project/pull/199009
>From 8aa17c041db51962fecb13aab05aa47258591fc8 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:18 +0200 Subject: [PATCH 01/17] Added warning for feclearexcept, feraiseexcept, fetestexcept, fegetround, and fesetround being used without appropriate flags/pragmas (#128239) --- clang/include/clang/Basic/BuiltinHeaders.def | 1 + clang/include/clang/Basic/Builtins.td | 25 +++++++++++++++++++ .../clang/Basic/DiagnosticSemaKinds.td | 5 ++++ clang/lib/Sema/SemaChecking.cpp | 11 ++++++++ 4 files changed, 42 insertions(+) diff --git a/clang/include/clang/Basic/BuiltinHeaders.def b/clang/include/clang/Basic/BuiltinHeaders.def index 23889a22769ed..f77665a2e8975 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 40ec94ab75046..b0ca7b5c641d1 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4599,6 +4599,31 @@ def BlockObjectDispose : LibBuiltin<"blocks.h"> { } // FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock. +def FeClearExcept : LibBuiltin<"fenv.h"> { + let Spellings = ["feclearexcept"]; + let Prototype = "int(int)"; +} + +def FeRaiseExcept : LibBuiltin<"fenv.h"> { + let Spellings = ["feraiseexcept"]; + let Prototype = "int(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 __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 142f848f37e50..9b1ccd8ef065b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1041,6 +1041,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/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index cc834bbee23c4..9c2e4f89ca14c 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3928,6 +3928,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (BuiltinCountedByRef(TheCall)) return ExprError(); break; + + case Builtin::BIfeclearexcept: + case Builtin::BIferaiseexcept: + case Builtin::BIfetestexcept: + case Builtin::BIfegetround: + case Builtin::BIfesetround: + if (TheCall->getFPFeaturesInEffect(getLangOpts()).getExceptionMode() == + LangOptions::FPE_Ignore) { + Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access) + << FDecl->getName() << TheCall->getSourceRange(); + } } if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall)) >From c5f16d8e61d12ef385fd787edda8dbe3aacd946a Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:18 +0200 Subject: [PATCH 02/17] Added regression tests for fenv access warning --- clang/test/Sema/fenv-access.c | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 clang/test/Sema/fenv-access.c diff --git a/clang/test/Sema/fenv-access.c b/clang/test/Sema/fenv-access.c new file mode 100644 index 0000000000000..57d4debfa9c73 --- /dev/null +++ b/clang/test/Sema/fenv-access.c @@ -0,0 +1,37 @@ +// 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 + +int feclearexcept(int excepts); +int feraiseexcept(int excepts); +int fetestexcept(int excepts); +int fegetround(void); +int fesetround(int rounding_mode); + +#define FE_INVALID 1 + +void test_fenv_access_off(void) { +#ifdef NO_WARN + // expected-no-diagnostics + feclearexcept(FE_INVALID); + feraiseexcept(FE_INVALID); + fetestexcept(FE_INVALID); + fegetround(); + fesetround(0); +#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'}} + 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'}} + 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'}} +#endif +} + +void test_fenv_access_on(void) { + #pragma STDC FENV_ACCESS ON + feclearexcept(FE_INVALID); + feraiseexcept(FE_INVALID); + fetestexcept(FE_INVALID); + fegetround(); + fesetround(0); +} >From 891bc5f10eb3894691e4f4916319bf2dbf947e01 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:19 +0200 Subject: [PATCH 03/17] Added builtin types fexcept_t and fenv_t (fenv.h) --- clang/include/clang/AST/ASTContext.h | 35 +++++++++++++++++- clang/include/clang/Basic/TokenKinds.def | 2 ++ .../include/clang/Serialization/ASTBitCodes.h | 8 ++++- clang/lib/AST/ASTContext.cpp | 19 ++++++++++ clang/lib/Sema/SemaDecl.cpp | 8 +++++ clang/lib/Serialization/ASTReader.cpp | 36 +++++++++++++++++++ clang/lib/Serialization/ASTWriter.cpp | 2 ++ clang/utils/TableGen/ClangBuiltinsEmitter.cpp | 2 ++ 8 files changed, 110 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b2fd522e6865c..d0a402e59ff60 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -498,6 +498,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 @@ -2350,6 +2356,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; @@ -2630,7 +2660,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/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index f07d8ebb75035..4bd21b4112580 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -877,6 +877,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/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 3c8f3ba59a07e..4bb287af687b5 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1225,7 +1225,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 bc4771aec77d1..412ba583353d2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12849,6 +12849,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/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 62cb9360d1322..30c671269cd00 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2398,6 +2398,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"); } @@ -7020,6 +7022,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 06bc8f8c8c13e..f13b70d695b0d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -5755,6 +5755,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 074b0fccdb65d..9dbbdc0249caf 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6159,6 +6159,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/utils/TableGen/ClangBuiltinsEmitter.cpp b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp index c2e38c0d6aeb8..2394c3b299c81 100644 --- a/clang/utils/TableGen/ClangBuiltinsEmitter.cpp +++ b/clang/utils/TableGen/ClangBuiltinsEmitter.cpp @@ -376,6 +376,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 e1b5360d879a7adfae4c794820779c7667fc02ce Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:20 +0200 Subject: [PATCH 04/17] Added warning for fegetexceptflag, fesetexceptflag, fegetenv, feholdexcept, fesetenv, feupdateenv being used without appropriate flags/pragmas (#128239) --- clang/include/clang/Basic/Builtins.td | 30 +++++++++++++++++++++++++++ clang/lib/Sema/SemaChecking.cpp | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index b0ca7b5c641d1..7b833487e23a2 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4604,11 +4604,21 @@ def FeClearExcept : LibBuiltin<"fenv.h"> { 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)"; @@ -4624,6 +4634,26 @@ def FeSetRound : LibBuiltin<"fenv.h"> { 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/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 9c2e4f89ca14c..8c4c51f403e93 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3930,10 +3930,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, 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) { Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access) >From 85b850e75ba9411716a1504cfe36fde36c4eb6ad Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:20 +0200 Subject: [PATCH 05/17] Added additional regression tests for fenv access warning --- clang/test/Sema/fenv-access.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/clang/test/Sema/fenv-access.c b/clang/test/Sema/fenv-access.c index 57d4debfa9c73..3a7b95af7ab4c 100644 --- a/clang/test/Sema/fenv-access.c +++ b/clang/test/Sema/fenv-access.c @@ -2,36 +2,67 @@ // 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); } >From b62c2c112662f65e7a4b1a08afecdb8581062ae9 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:21 +0200 Subject: [PATCH 06/17] Added isPotentiallyEvaluated() check to avoid diagnostics inside of decltype() or similar constructs --- clang/include/clang/Sema/Sema.h | 4 ++++ clang/lib/Sema/SemaChecking.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e71794b2d92c9..62e4c4eb953be 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8264,6 +8264,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/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8c4c51f403e93..03091f2ba0cfe 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3941,7 +3941,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIfesetenv: case Builtin::BIfeupdateenv: if (TheCall->getFPFeaturesInEffect(getLangOpts()).getExceptionMode() == - LangOptions::FPE_Ignore) { + LangOptions::FPE_Ignore && + isPotentiallyEvaluatedContext()) { Diag(TheCall->getBeginLoc(), diag::warn_fe_access_without_fenv_access) << FDecl->getName() << TheCall->getSourceRange(); } >From ac99205a0fad10f195d6ad7c507f7db3906eb78a Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:21 +0200 Subject: [PATCH 07/17] Added regression tests for unevaluated occurrences of fp exception functions --- clang/test/Sema/fenv-access-unevaluated.cpp | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 clang/test/Sema/fenv-access-unevaluated.cpp 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; +} >From 555678df407fe6345136f2b12835031ffc8e1f66 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:22 +0200 Subject: [PATCH 08/17] Added regression tests for implicit usage of fp exception functions --- clang/test/Sema/fenv-access-implicit.c | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 clang/test/Sema/fenv-access-implicit.c 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}} +} >From f6616616cbc58695ffb9a572225a467a90c72305 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:22 +0200 Subject: [PATCH 09/17] Added regression tests for fexcept_t --- clang/test/Sema/builtin-fenv.c | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 clang/test/Sema/builtin-fenv.c 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 >From eee8e625f52342c904eed6cc3b6e93e8508aede0 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:22 +0200 Subject: [PATCH 10/17] Added regression tests for AST serialization (fenv.h) --- clang/test/PCH/builtins-fenv.c | 25 +++++++++++++++++++++++++ clang/test/PCH/builtins-fenv.h | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 clang/test/PCH/builtins-fenv.c create mode 100644 clang/test/PCH/builtins-fenv.h 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); >From c838bb208208745094573db1dd68b18fb6b48fc9 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Wed, 13 May 2026 22:50:23 +0200 Subject: [PATCH 11/17] Add release notes --- clang/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6838cf3defcc1..dd78896fefd93 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -544,6 +544,9 @@ Improvements to Clang's diagnostics - The diagnostics around ``__block`` now explain why a variable cannot be marked ``__block``. (#GH197213) +- Added warnings for floating-point exception function calls (fenv.h) without enabling + floating-point exception behavior via the appropriate flags or pragmas. (#GH128239) + Improvements to Clang's time-trace ---------------------------------- >From 4ec064c763bea29b0f0e515090e0f137340653c4 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Sun, 17 May 2026 22:43:47 +0200 Subject: [PATCH 12/17] 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/docs/ReleaseNotes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index dd78896fefd93..16a33bf8069d8 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -544,6 +544,9 @@ Improvements to Clang's diagnostics - The diagnostics around ``__block`` now explain why a variable cannot be marked ``__block``. (#GH197213) +- Added warnings for floating-point exception function calls (fenv.h) without enabling + floating-point exception behavior via the appropriate flags or pragmas. (#GH128239) + - Added warnings for floating-point exception function calls (fenv.h) without enabling floating-point exception behavior via the appropriate flags or pragmas. (#GH128239) >From 0d7121644916b57e6f4f7fb8b46a03d73607e1ba Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Thu, 21 May 2026 15:10:06 +0200 Subject: [PATCH 13/17] 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 03091f2ba0cfe..bcb3d17931d6a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3942,7 +3942,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 2d1e9686a845117a8c413c3c0f33b794f71beb48 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Thu, 21 May 2026 15:19:25 +0200 Subject: [PATCH 14/17] 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 7cd89be5bd341db891d974665c16234b38b74e8a Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Thu, 21 May 2026 15:42:31 +0200 Subject: [PATCH 15/17] Updated ReleaseNotes.rst --- clang/docs/ReleaseNotes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4bf8522443a05..6404894415db6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -546,8 +546,8 @@ Improvements to Clang's diagnostics - Extended ``-Wnonportable-include-path`` to warn about trailing whitespace and dots in ``#include`` paths. (#GH190610) -- Added warnings for floating-point exception function calls (fenv.h) without enabling - floating-point exception behavior via the appropriate flags or pragmas. (#GH128239) +- 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 ---------------------------------- >From c94885250ae84c089efe32fbefd0038dd31fa8a2 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Thu, 28 May 2026 15:43:09 +0200 Subject: [PATCH 16/17] [libc] Add #pragma STDC FENV_ACCESS ON to FEnvImpl.h wrappers --- libc/src/__support/FPUtil/FEnvImpl.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h index a21f511bd72b8..208c095170c05 100644 --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -37,26 +37,41 @@ namespace LIBC_NAMESPACE_DECL { namespace fputil { -LIBC_INLINE int clear_except(int excepts) { return feclearexcept(excepts); } +LIBC_INLINE int clear_except(int excepts) { +#pragma STDC FENV_ACCESS ON + return feclearexcept(excepts); +} -LIBC_INLINE int test_except(int excepts) { return fetestexcept(excepts); } +LIBC_INLINE int test_except(int excepts) { +#pragma STDC FENV_ACCESS ON + return fetestexcept(excepts); +} LIBC_INLINE int get_except() { +#pragma STDC FENV_ACCESS ON fexcept_t excepts = 0; fegetexceptflag(&excepts, FE_ALL_EXCEPT); return static_cast<int>(excepts); } LIBC_INLINE int set_except(int excepts) { +#pragma STDC FENV_ACCESS ON fexcept_t exc = static_cast<fexcept_t>(excepts); return fesetexceptflag(&exc, FE_ALL_EXCEPT); } -LIBC_INLINE int raise_except(int excepts) { return feraiseexcept(excepts); } +LIBC_INLINE int raise_except(int excepts) { +#pragma STDC FENV_ACCESS ON + return feraiseexcept(excepts); +} -LIBC_INLINE int get_round() { return fegetround(); } +LIBC_INLINE int get_round() { +#pragma STDC FENV_ACCESS ON + return fegetround(); +} LIBC_INLINE int set_round(int rounding_mode) { +#pragma STDC FENV_ACCESS ON return fesetround(rounding_mode); } @@ -129,6 +144,7 @@ clear_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT +#pragma STDC FENV_ACCESS ON if (math_errhandling & MATH_ERREXCEPT) return clear_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -142,6 +158,7 @@ set_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT +#pragma STDC FENV_ACCESS ON if (math_errhandling & MATH_ERREXCEPT) return set_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -155,6 +172,7 @@ raise_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT +#pragma STDC FENV_ACCESS ON if (math_errhandling & MATH_ERREXCEPT) return raise_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT >From d13a180a553a1359cce22339a1c6ac08faada248 Mon Sep 17 00:00:00 2001 From: Marcos Ramirez Joos <[email protected]> Date: Thu, 28 May 2026 16:43:48 +0200 Subject: [PATCH 17/17] [libc] Add LIBC_FENV_ACCESS_ON macro to abstract fenv pragma per compiler/arch --- libc/src/__support/FPUtil/FEnvImpl.h | 21 +++++----- .../macros/properties/CMakeLists.txt | 9 ++++ .../macros/properties/fenv_support.h | 41 +++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 libc/src/__support/macros/properties/fenv_support.h diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h index 208c095170c05..0cbbf183a019c 100644 --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -19,6 +19,7 @@ #include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/architectures.h" #include "src/__support/macros/properties/compiler.h" +#include "src/__support/macros/properties/fenv_support.h" // In full build mode we are the system fenv in libc. #if defined(LIBC_FULL_BUILD) @@ -38,40 +39,40 @@ namespace LIBC_NAMESPACE_DECL { namespace fputil { LIBC_INLINE int clear_except(int excepts) { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON return feclearexcept(excepts); } LIBC_INLINE int test_except(int excepts) { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON return fetestexcept(excepts); } LIBC_INLINE int get_except() { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON fexcept_t excepts = 0; fegetexceptflag(&excepts, FE_ALL_EXCEPT); return static_cast<int>(excepts); } LIBC_INLINE int set_except(int excepts) { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON fexcept_t exc = static_cast<fexcept_t>(excepts); return fesetexceptflag(&exc, FE_ALL_EXCEPT); } LIBC_INLINE int raise_except(int excepts) { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON return feraiseexcept(excepts); } LIBC_INLINE int get_round() { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON return fegetround(); } LIBC_INLINE int set_round(int rounding_mode) { -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON return fesetround(rounding_mode); } @@ -144,7 +145,7 @@ clear_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return clear_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -158,7 +159,7 @@ set_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return set_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -172,7 +173,7 @@ raise_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT -#pragma STDC FENV_ACCESS ON + LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return raise_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT diff --git a/libc/src/__support/macros/properties/CMakeLists.txt b/libc/src/__support/macros/properties/CMakeLists.txt index dfa2f9c572492..cdcccc97cbbcc 100644 --- a/libc/src/__support/macros/properties/CMakeLists.txt +++ b/libc/src/__support/macros/properties/CMakeLists.txt @@ -48,3 +48,12 @@ add_header_library( libc.include.llvm-libc-types.cfloat16 libc.include.llvm-libc-types.cfloat128 ) + +add_header_library( + fenv_support + HDRS + fenv_support.h + DEPENDS + .architectures + .compiler +) diff --git a/libc/src/__support/macros/properties/fenv_support.h b/libc/src/__support/macros/properties/fenv_support.h new file mode 100644 index 0000000000000..1bfa57abb0980 --- /dev/null +++ b/libc/src/__support/macros/properties/fenv_support.h @@ -0,0 +1,41 @@ +//===-- Compile time enabling of stict floating-point behavior --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_FENV_SUPPORT_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_FENV_SUPPORT_H + +#include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" + +// Check target support of strict floating-point behavior +#if defined(LIBC_TARGET_ARCH_IS_X86_64) || \ + defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ + defined(LIBC_TARGET_ARCH_IS_ARM) || \ + defined(LIBC_TARGET_ARCH_IS_RISCV64) || \ + defined(LIBC_TARGET_ARCH_IS_RISCV32) || \ + defined(LIBC_TARGET_ARCH_IS_SYSTEMZ) || \ + defined(LIBC_TARGET_ARCH_IS_LOONGARCH64) +#define LIBC_TARGET_HAS_STRICT_FP +#endif + +// Enable strict floating-point behavior on supported targets +#ifdef LIBC_TARGET_HAS_STRICT_FP +#if defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG_VER > 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 LIBC_FENV_ACCESS_ON _Pragma("clang fp exceptions(maytrap)") +#else +// Portable fallback for GCC, MSVC, or older clang. +#define LIBC_FENV_ACCESS_ON _Pragma("STDC FENV_ACCESS ON") +#endif +#else +#define LIBC_FENV_ACCESS_ON +#endif + +#endif _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
