[clang] [clang] Move `ExceptionHandling` from `LangOptions` to `CodeGenOptions` (PR #148982)
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 15 15:49:31 PDT 2025
https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/148982
This PR removes the command line parsing workaround introduced in https://github.com/llvm/llvm-project/pull/146342 by moving `LangOptions::ExceptionHandling` to `CodeGenOptions` that get parsed even for IR input. Additionally, this improves layering, where the codegen library now checks `CodeGenOptions` instead of `LangOptions` for exception handling. (This got enabled by https://github.com/llvm/llvm-project/pull/146422.)
>From 1bee2ee316d0ab413966114328b419f7966b3c81 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 15 Jul 2025 15:43:12 -0700
Subject: [PATCH] [clang] Move `ExceptionHandling` from `LangOptions` to
`CodeGenOptions`
This PR removes the workaround introduced in https://github.com/llvm/llvm-project/pull/146342 by moving `LangOptions::ExceptionHandling` to `CodeGenOptions` that get parsed even for IR input. This got enabled by https://github.com/llvm/llvm-project/pull/146422.
---
clang/include/clang/Basic/CodeGenOptions.def | 2 +
clang/include/clang/Basic/CodeGenOptions.h | 19 ++++++++
clang/include/clang/Basic/LangOptions.def | 2 -
clang/include/clang/Basic/LangOptions.h | 19 --------
clang/include/clang/Driver/Options.td | 4 +-
clang/lib/CodeGen/BackendUtil.cpp | 8 +--
clang/lib/CodeGen/CGException.cpp | 51 +++++++++++---------
clang/lib/Frontend/CompilerInvocation.cpp | 45 ++---------------
clang/lib/Frontend/InitPreprocessor.cpp | 8 +--
9 files changed, 61 insertions(+), 97 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a11e12d495cd2..cfffeb71f09d1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -56,6 +56,8 @@ CODEGENOPT(XCOFFReadOnlyPointers, 1, 0, Benign) ///< Set for -mxcoff-roptr.
CODEGENOPT(AllTocData, 1, 0, Benign) ///< AIX -mtocdata
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None, Benign) /// frame-pointer: all,non-leaf,reserved,none
+ENUM_CODEGENOPT(ExceptionHandling, ExceptionHandlingKind, 3, ExceptionHandlingKind::None, NotCompatible)
+
CODEGENOPT(ClearASTBeforeBackend , 1, 0, Benign) ///< Free the AST before running backend code generation. Only works with -disable-free.
CODEGENOPT(DisableFree , 1, 0, Benign) ///< Don't free memory.
CODEGENOPT(DiscardValueNames , 1, 0, Benign) ///< Discard Value Names from the IR (LLVMContext flag)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index df4403ace5fe3..cdeedd5b4eac6 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -176,6 +176,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
llvm_unreachable("invalid FramePointerKind");
}
+ /// Possible exception handling behavior.
+ enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
+
enum class SwiftAsyncFramePointerKind {
Auto, // Choose Swift async extended frame info based on deployment target.
Always, // Unconditionally emit Swift async extended frame info.
@@ -552,6 +555,22 @@ class CodeGenOptions : public CodeGenOptionsBase {
return NoBuiltinFuncs;
}
+ bool hasSjLjExceptions() const {
+ return getExceptionHandling() == ExceptionHandlingKind::SjLj;
+ }
+
+ bool hasSEHExceptions() const {
+ return getExceptionHandling() == ExceptionHandlingKind::WinEH;
+ }
+
+ bool hasDWARFExceptions() const {
+ return getExceptionHandling() == ExceptionHandlingKind::DwarfCFI;
+ }
+
+ bool hasWasmExceptions() const {
+ return getExceptionHandling() == ExceptionHandlingKind::Wasm;
+ }
+
/// Check if Clang profile instrumenation is on.
bool hasProfileClangInstr() const {
return getProfileInstr() ==
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 6c47107796236..6ac8d496f1494 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -98,8 +98,6 @@ LANGOPT(Exceptions , 1, 0, NotCompatible, "exception handling")
LANGOPT(ObjCExceptions , 1, 0, NotCompatible, "Objective-C exceptions")
LANGOPT(CXXExceptions , 1, 0, NotCompatible, "C++ exceptions")
LANGOPT(EHAsynch , 1, 0, NotCompatible, "C/C++ EH Asynch exceptions")
-ENUM_LANGOPT(ExceptionHandling, ExceptionHandlingKind, 3,
- ExceptionHandlingKind::None, NotCompatible, "exception handling")
LANGOPT(IgnoreExceptions , 1, 0, NotCompatible, "ignore exceptions")
LANGOPT(ExternCNoUnwind , 1, 0, NotCompatible, "Assume extern C functions don't unwind")
LANGOPT(AssumeNothrowExceptionDtor , 1, 0, NotCompatible, "Assume exception object's destructor is nothrow")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 4c642c9e10c91..937cbff4e3ea3 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -337,9 +337,6 @@ class LangOptionsBase {
enum ExcessPrecisionKind { FPP_Standard, FPP_Fast, FPP_None };
- /// Possible exception handling behavior.
- enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
-
enum class LaxVectorConversionKind {
/// Permit no implicit vector bitcasts.
None,
@@ -788,22 +785,6 @@ class LangOptions : public LangOptionsBase {
return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
}
- bool hasSjLjExceptions() const {
- return getExceptionHandling() == ExceptionHandlingKind::SjLj;
- }
-
- bool hasSEHExceptions() const {
- return getExceptionHandling() == ExceptionHandlingKind::WinEH;
- }
-
- bool hasDWARFExceptions() const {
- return getExceptionHandling() == ExceptionHandlingKind::DwarfCFI;
- }
-
- bool hasWasmExceptions() const {
- return getExceptionHandling() == ExceptionHandlingKind::Wasm;
- }
-
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
bool hasDefaultVisibilityExportMapping() const {
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index bce29a76f3ac7..9ea15de132df1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2177,9 +2177,9 @@ def fwasm_exceptions : Flag<["-"], "fwasm-exceptions">, Group<f_Group>,
def exception_model : Separate<["-"], "exception-model">,
Visibility<[CC1Option]>, HelpText<"The exception model">,
Values<"dwarf,sjlj,seh,wasm">,
- NormalizedValuesScope<"LangOptions::ExceptionHandlingKind">,
+ NormalizedValuesScope<"CodeGenOptions::ExceptionHandlingKind">,
NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm"]>,
- MarshallingInfoEnum<LangOpts<"ExceptionHandling">, "None">;
+ MarshallingInfoEnum<CodeGenOpts<"ExceptionHandling">, "None">;
def exception_model_EQ : Joined<["-"], "exception-model=">,
Visibility<[CC1Option]>, Alias<exception_model>;
def fignore_exceptions : Flag<["-"], "fignore-exceptions">, Group<f_Group>,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 2f6d4c414e737..1b7257857dd3b 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -407,13 +407,13 @@ static bool initTargetOptions(const CompilerInstance &CI,
// Set EABI version.
Options.EABIVersion = TargetOpts.EABIVersion;
- if (LangOpts.hasSjLjExceptions())
+ if (CodeGenOpts.hasSjLjExceptions())
Options.ExceptionModel = llvm::ExceptionHandling::SjLj;
- if (LangOpts.hasSEHExceptions())
+ if (CodeGenOpts.hasSEHExceptions())
Options.ExceptionModel = llvm::ExceptionHandling::WinEH;
- if (LangOpts.hasDWARFExceptions())
+ if (CodeGenOpts.hasDWARFExceptions())
Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI;
- if (LangOpts.hasWasmExceptions())
+ if (CodeGenOpts.hasWasmExceptions())
Options.ExceptionModel = llvm::ExceptionHandling::Wasm;
Options.NoInfsFPMath = LangOpts.NoHonorInfs;
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index ad138b9876e8c..f86af4581c345 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -131,20 +131,21 @@ const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2",
nullptr};
static const EHPersonality &getCPersonality(const TargetInfo &Target,
- const LangOptions &L) {
+ const CodeGenOptions &CGOpts) {
const llvm::Triple &T = Target.getTriple();
if (T.isWindowsMSVCEnvironment())
return EHPersonality::MSVC_CxxFrameHandler3;
- if (L.hasSjLjExceptions())
+ if (CGOpts.hasSjLjExceptions())
return EHPersonality::GNU_C_SJLJ;
- if (L.hasDWARFExceptions())
+ if (CGOpts.hasDWARFExceptions())
return EHPersonality::GNU_C;
- if (L.hasSEHExceptions())
+ if (CGOpts.hasSEHExceptions())
return EHPersonality::GNU_C_SEH;
return EHPersonality::GNU_C;
}
static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
+ const CodeGenOptions &CGOpts,
const LangOptions &L) {
const llvm::Triple &T = Target.getTriple();
if (T.isWindowsMSVCEnvironment())
@@ -152,7 +153,7 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
switch (L.ObjCRuntime.getKind()) {
case ObjCRuntime::FragileMacOSX:
- return getCPersonality(Target, L);
+ return getCPersonality(Target, CGOpts);
case ObjCRuntime::MacOSX:
case ObjCRuntime::iOS:
case ObjCRuntime::WatchOS:
@@ -165,9 +166,9 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
[[fallthrough]];
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
- if (L.hasSjLjExceptions())
+ if (CGOpts.hasSjLjExceptions())
return EHPersonality::GNU_ObjC_SJLJ;
- if (L.hasSEHExceptions())
+ if (CGOpts.hasSEHExceptions())
return EHPersonality::GNU_ObjC_SEH;
return EHPersonality::GNU_ObjC;
}
@@ -175,19 +176,19 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
}
static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
- const LangOptions &L) {
+ const CodeGenOptions &CGOpts) {
const llvm::Triple &T = Target.getTriple();
if (T.isWindowsMSVCEnvironment())
return EHPersonality::MSVC_CxxFrameHandler3;
if (T.isOSAIX())
return EHPersonality::XL_CPlusPlus;
- if (L.hasSjLjExceptions())
+ if (CGOpts.hasSjLjExceptions())
return EHPersonality::GNU_CPlusPlus_SJLJ;
- if (L.hasDWARFExceptions())
+ if (CGOpts.hasDWARFExceptions())
return EHPersonality::GNU_CPlusPlus;
- if (L.hasSEHExceptions())
+ if (CGOpts.hasSEHExceptions())
return EHPersonality::GNU_CPlusPlus_SEH;
- if (L.hasWasmExceptions())
+ if (CGOpts.hasWasmExceptions())
return EHPersonality::GNU_Wasm_CPlusPlus;
if (T.isOSzOS())
return EHPersonality::ZOS_CPlusPlus;
@@ -197,6 +198,7 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
/// Determines the personality function to use when both C++
/// and Objective-C exceptions are being caught.
static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
+ const CodeGenOptions &CGOpts,
const LangOptions &L) {
if (Target.getTriple().isWindowsMSVCEnvironment())
return EHPersonality::MSVC_CxxFrameHandler3;
@@ -205,7 +207,7 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
// In the fragile ABI, just use C++ exception handling and hope
// they're not doing crazy exception mixing.
case ObjCRuntime::FragileMacOSX:
- return getCXXPersonality(Target, L);
+ return getCXXPersonality(Target, CGOpts);
// The ObjC personality defers to the C++ personality for non-ObjC
// handlers. Unlike the C++ case, we use the same personality
@@ -213,7 +215,7 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
case ObjCRuntime::MacOSX:
case ObjCRuntime::iOS:
case ObjCRuntime::WatchOS:
- return getObjCPersonality(Target, L);
+ return getObjCPersonality(Target, CGOpts, L);
case ObjCRuntime::GNUstep:
return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH
@@ -223,7 +225,7 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
// mixed EH. Use the ObjC personality just to avoid returning null.
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
- return getObjCPersonality(Target, L);
+ return getObjCPersonality(Target, CGOpts, L);
}
llvm_unreachable("bad runtime kind");
}
@@ -237,6 +239,7 @@ static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) {
const EHPersonality &EHPersonality::get(CodeGenModule &CGM,
const FunctionDecl *FD) {
const llvm::Triple &T = CGM.getTarget().getTriple();
+ const CodeGenOptions &CGOpts = CGM.getCodeGenOpts();
const LangOptions &L = CGM.getLangOpts();
const TargetInfo &Target = CGM.getTarget();
@@ -245,10 +248,10 @@ const EHPersonality &EHPersonality::get(CodeGenModule &CGM,
return getSEHPersonalityMSVC(T);
if (L.ObjC)
- return L.CPlusPlus ? getObjCXXPersonality(Target, L)
- : getObjCPersonality(Target, L);
- return L.CPlusPlus ? getCXXPersonality(Target, L)
- : getCPersonality(Target, L);
+ return L.CPlusPlus ? getObjCXXPersonality(Target, CGOpts, L)
+ : getObjCPersonality(Target, CGOpts, L);
+ return L.CPlusPlus ? getCXXPersonality(Target, CGOpts)
+ : getCPersonality(Target, CGOpts);
}
const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {
@@ -344,7 +347,7 @@ void CodeGenModule::SimplifyPersonality() {
return;
const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr);
- const EHPersonality &CXX = getCXXPersonality(getTarget(), LangOpts);
+ const EHPersonality &CXX = getCXXPersonality(getTarget(), CodeGenOpts);
if (&ObjCXX == &CXX)
return;
@@ -500,7 +503,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
// In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In
// case of throw with types, we ignore it and print a warning for now.
// TODO Correctly handle exception specification in Wasm EH
- if (CGM.getLangOpts().hasWasmExceptions()) {
+ if (CGM.getCodeGenOpts().hasWasmExceptions()) {
if (EST == EST_DynamicNone)
EHStack.pushTerminate();
else
@@ -515,8 +518,8 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
// throw with types.
// TODO Correctly handle exception specification in Emscripten EH
if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly &&
- CGM.getLangOpts().getExceptionHandling() ==
- LangOptions::ExceptionHandlingKind::None &&
+ CGM.getCodeGenOpts().getExceptionHandling() ==
+ CodeGenOptions::ExceptionHandlingKind::None &&
EST == EST_Dynamic)
CGM.getDiags().Report(D->getLocation(),
diag::warn_wasm_dynamic_exception_spec_ignored)
@@ -604,7 +607,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
// In wasm we currently treat 'throw()' in the same way as 'noexcept'. In
// case of throw with types, we ignore it and print a warning for now.
// TODO Correctly handle exception specification in wasm
- if (CGM.getLangOpts().hasWasmExceptions()) {
+ if (CGM.getCodeGenOpts().hasWasmExceptions()) {
if (EST == EST_DynamicNone)
EHStack.popTerminate();
return;
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 56d10ceb986b3..6ab36d8675966 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -593,11 +593,11 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
CodeGenOpts.CodeModel = TargetOpts.CodeModel;
CodeGenOpts.LargeDataThreshold = TargetOpts.LargeDataThreshold;
- if (LangOpts.getExceptionHandling() !=
- LangOptions::ExceptionHandlingKind::None &&
+ if (CodeGenOpts.getExceptionHandling() !=
+ CodeGenOptions::ExceptionHandlingKind::None &&
T.isWindowsMSVCEnvironment())
Diags.Report(diag::err_fe_invalid_exception_model)
- << static_cast<unsigned>(LangOpts.getExceptionHandling()) << T.str();
+ << static_cast<unsigned>(CodeGenOpts.getExceptionHandling()) << T.str();
if (LangOpts.AppleKext && !LangOpts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
@@ -3713,23 +3713,6 @@ static StringRef GetInputKindName(InputKind IK) {
llvm_unreachable("unknown input language");
}
-static StringRef getExceptionHandlingName(unsigned EHK) {
- switch (static_cast<LangOptions::ExceptionHandlingKind>(EHK)) {
- case LangOptions::ExceptionHandlingKind::None:
- return "none";
- case LangOptions::ExceptionHandlingKind::DwarfCFI:
- return "dwarf";
- case LangOptions::ExceptionHandlingKind::SjLj:
- return "sjlj";
- case LangOptions::ExceptionHandlingKind::WinEH:
- return "seh";
- case LangOptions::ExceptionHandlingKind::Wasm:
- return "wasm";
- }
-
- llvm_unreachable("covered switch");
-}
-
void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
ArgumentConsumer Consumer,
const llvm::Triple &T,
@@ -3745,10 +3728,6 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_pic_is_pie);
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
- if (Opts.ExceptionHandling) {
- GenerateArg(Consumer, OPT_exception_model,
- getExceptionHandlingName(Opts.ExceptionHandling));
- }
return;
}
@@ -4057,24 +4036,6 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
- if (const Arg *A = Args.getLastArg(options::OPT_exception_model)) {
- std::optional<LangOptions::ExceptionHandlingKind> EMValue =
- llvm::StringSwitch<std::optional<LangOptions::ExceptionHandlingKind>>(
- A->getValue())
- .Case("dwarf", LangOptions::ExceptionHandlingKind::DwarfCFI)
- .Case("sjlj", LangOptions::ExceptionHandlingKind::SjLj)
- .Case("seh", LangOptions::ExceptionHandlingKind::WinEH)
- .Case("wasm", LangOptions::ExceptionHandlingKind::Wasm)
- .Case("none", LangOptions::ExceptionHandlingKind::None)
- .Default(std::nullopt);
- if (EMValue) {
- Opts.ExceptionHandling = static_cast<unsigned>(*EMValue);
- } else {
- Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue();
- }
- }
-
return Diags.getNumErrors() == NumErrorsBefore;
}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 136bc55847cc1..38b2e0cf1ca59 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1032,14 +1032,14 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.GNUCVersion && LangOpts.RTTI)
Builder.defineMacro("__GXX_RTTI");
- if (LangOpts.hasSjLjExceptions())
+ if (CGOpts.hasSjLjExceptions())
Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
- else if (LangOpts.hasSEHExceptions())
+ else if (CGOpts.hasSEHExceptions())
Builder.defineMacro("__SEH__");
- else if (LangOpts.hasDWARFExceptions() &&
+ else if (CGOpts.hasDWARFExceptions() &&
(TI.getTriple().isThumb() || TI.getTriple().isARM()))
Builder.defineMacro("__ARM_DWARF_EH__");
- else if (LangOpts.hasWasmExceptions() && TI.getTriple().isWasm())
+ else if (CGOpts.hasWasmExceptions() && TI.getTriple().isWasm())
Builder.defineMacro("__WASM_EXCEPTIONS__");
if (LangOpts.Deprecated)
More information about the cfe-commits
mailing list