https://github.com/smeenai updated https://github.com/llvm/llvm-project/pull/104899
>From e0a1a4d57d2801f68adc0f4fe26d33d509956490 Mon Sep 17 00:00:00 2001 From: Shoaib Meenai <smee...@fb.com> Date: Mon, 19 Aug 2024 18:05:52 -0700 Subject: [PATCH 1/2] [clang] Add support for omitting only global destructors For mobile applications, it's common for global destructors to never be called (because the applications have their own lifecycle independent of the standard C runtime), but threads are created and destroyed as normal and so thread-local destructors are still called. -fno-static-c++-destructors omits unnecessary global destructors, which is useful for code size, but it also omits thread-local destructors, which is unsuitable. Add a ternary `-fc++-static-destructors={all,none,thread-local}` option instead to allow omitting only global destructors. --- clang/include/clang/Basic/LangOptions.def | 4 ++- clang/include/clang/Basic/LangOptions.h | 10 +++++++ clang/include/clang/Driver/Options.td | 17 +++++++---- clang/lib/AST/Decl.cpp | 14 +++++++-- clang/lib/Driver/ToolChains/Clang.cpp | 5 ++-- clang/test/CodeGenCXX/always_destroy.cpp | 8 +++-- .../CodeGenCXX/attr-no-destroy-d54344.cpp | 3 +- clang/test/Driver/cxx-static-destructors.cpp | 9 ++++++ clang/test/SemaCXX/no_destroy.cpp | 30 +++++++------------ 9 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 clang/test/Driver/cxx-static-destructors.cpp diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index d454a7ff2f8cf4..a57da8addb69be 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -465,7 +465,9 @@ LANGOPT(FixedPoint, 1, 0, "fixed point types") LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0, "unsigned fixed point types having one extra padding bit") -LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") +ENUM_LANGOPT(RegisterStaticDestructors, RegisterStaticDestructorsKind, 2, + RegisterStaticDestructorsKind::All, + "Register C++ static destructors") LANGOPT(RegCall4, 1, 0, "Set __regcall4 as a default calling convention to respect __regcall ABI v.4") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 91f1c2f2e6239e..88fbf26e2eb79b 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -441,6 +441,16 @@ class LangOptionsBase { CX_None }; + /// Controls which variables have static destructors registered. + enum class RegisterStaticDestructorsKind { + /// Register static destructors for all variables. + All, + /// Register static destructors only for thread-local variables. + ThreadLocal, + /// Don't register static destructors for any variables. + None, + }; + // Define simple language options (with no accessors). #define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits; #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c66e035a259b3f..0d8cb1d18fb24d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2300,11 +2300,18 @@ defm fixed_point : BoolFOption<"fixed-point", PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">, NegFlag<SetFalse, [], [ClangOption], "Disable">, BothFlags<[], [ClangOption], " fixed point types">>; -defm cxx_static_destructors : BoolFOption<"c++-static-destructors", - LangOpts<"RegisterStaticDestructors">, DefaultTrue, - NegFlag<SetFalse, [], [ClangOption, CC1Option], - "Disable C++ static destructor registration">, - PosFlag<SetTrue>>; +def cxx_static_destructors_EQ : Joined<["-"], "fc++-static-destructors=">, Group<f_Group>, + HelpText<"Controls which variables C++ static destructors are registered for">, + Values<"all,thread-local,none">, + NormalizedValues<["All", "ThreadLocal", "None"]>, + NormalizedValuesScope<"LangOptions::RegisterStaticDestructorsKind">, + MarshallingInfoEnum<LangOpts<"RegisterStaticDestructors">, "All">, + Visibility<[ClangOption, CC1Option]>; +def cxx_static_destructors : Flag<["-"], "fc++-static-destructors">, Group<f_Group>, + Alias<cxx_static_destructors_EQ>, AliasArgs<["all"]>; +def no_cxx_static_destructors : Flag<["-"], "fno-c++-static-destructors">, Group<f_Group>, + Alias<cxx_static_destructors_EQ>, AliasArgs<["none"]>, + HelpText<"Disable C++ static destructor registration">; def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>, MarshallingInfoString<CodeGenOpts<"SymbolPartition">>; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 90caf81757ac96..1a07125815832e 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2799,9 +2799,17 @@ bool VarDecl::isKnownToBeDefined() const { } bool VarDecl::isNoDestroy(const ASTContext &Ctx) const { - return hasGlobalStorage() && (hasAttr<NoDestroyAttr>() || - (!Ctx.getLangOpts().RegisterStaticDestructors && - !hasAttr<AlwaysDestroyAttr>())); + if (!hasGlobalStorage()) + return false; + if (hasAttr<NoDestroyAttr>()) + return true; + if (hasAttr<AlwaysDestroyAttr>()) + return false; + + using RSDKind = LangOptions::RegisterStaticDestructorsKind; + RSDKind K = Ctx.getLangOpts().getRegisterStaticDestructors(); + return K == RSDKind::None || + (K == RSDKind::ThreadLocal && getTLSKind() == TLS_None); } QualType::DestructionKind diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a5a87db97e96b4..68ac374e036b1f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7967,8 +7967,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_keep_persistent_storage_variables); Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers, options::OPT_fno_complete_member_pointers); - Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors, - options::OPT_fno_cxx_static_destructors); + if (Arg *A = Args.getLastArg(options::OPT_cxx_static_destructors_EQ)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-fc++-static-destructors=") + A->getValue())); addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false); diff --git a/clang/test/CodeGenCXX/always_destroy.cpp b/clang/test/CodeGenCXX/always_destroy.cpp index e84c4cf02c52f5..ca8a8e0cabacb3 100644 --- a/clang/test/CodeGenCXX/always_destroy.cpp +++ b/clang/test/CodeGenCXX/always_destroy.cpp @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 %s -fno-c++-static-destructors -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -fc++-static-destructors=none -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | \ +// RUN: FileCheck --check-prefixes=CHECK,NO-DTORS %s +// RUN: %clang_cc1 %s -fc++-static-destructors=thread-local -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | \ +// RUN: FileCheck --check-prefixes=CHECK,THREAD-LOCAL-DTORS %s struct NonTrivial { ~NonTrivial(); @@ -6,7 +9,8 @@ struct NonTrivial { // CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev NonTrivial nt1; -// CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +// NO-DTORS-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +// THREAD-LOCAL-DTORS: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev thread_local NonTrivial nt2; struct NonTrivial2 { diff --git a/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp b/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp index b03791e5135df5..053043adb61c17 100644 --- a/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp +++ b/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu -DNOATTR %s -o - | FileCheck %s // RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefix=CHECK-ATTR -// RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu -DNOATTR -fno-c++-static-destructors %s -o - | FileCheck %s --check-prefix=CHECK-FLAG +// RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu -DNOATTR -fc++-static-destructors=none %s -o - | FileCheck %s --check-prefix=CHECK-FLAG +// RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu -DNOATTR -fc++-static-destructors=thread-local %s -o - | FileCheck %s --check-prefix=CHECK-FLAG // Regression test for D54344. Class with no user-defined destructor // that has an inherited member that has a non-trivial destructor diff --git a/clang/test/Driver/cxx-static-destructors.cpp b/clang/test/Driver/cxx-static-destructors.cpp new file mode 100644 index 00000000000000..71da4d28c25142 --- /dev/null +++ b/clang/test/Driver/cxx-static-destructors.cpp @@ -0,0 +1,9 @@ +// RUN: %clang -### -c -fc++-static-destructors=all %s 2>&1 | FileCheck --check-prefix ALL %s +// RUN: %clang -### -c -fc++-static-destructors %s 2>&1 | FileCheck --check-prefix ALL %s +// RUN: %clang -### -c -fc++-static-destructors=none %s 2>&1 | FileCheck --check-prefix NONE %s +// RUN: %clang -### -c -fno-c++-static-destructors %s 2>&1 | FileCheck --check-prefix NONE %s +// RUN: %clang -### -c -fc++-static-destructors=thread-local %s 2>&1 | FileCheck --check-prefix THREAD-LOCAL %s + +// ALL: -fc++-static-destructors=all +// NONE: -fc++-static-destructors=none +// THREAD-LOCAL: -fc++-static-destructors=thread-local diff --git a/clang/test/SemaCXX/no_destroy.cpp b/clang/test/SemaCXX/no_destroy.cpp index 5872bcf4b439e2..d39bcaeff860a1 100644 --- a/clang/test/SemaCXX/no_destroy.cpp +++ b/clang/test/SemaCXX/no_destroy.cpp @@ -1,31 +1,21 @@ -// RUN: %clang_cc1 -DNO_DTORS -DNO_EXCEPTIONS -fno-c++-static-destructors -verify %s -// RUN: %clang_cc1 -DNO_EXCEPTIONS -verify %s -// RUN: %clang_cc1 -DNO_DTORS -fexceptions -fno-c++-static-destructors -verify %s -// RUN: %clang_cc1 -fexceptions -verify %s +// RUN: %clang_cc1 -fc++-static-destructors=none -verify %s +// RUN: %clang_cc1 -fc++-static-destructors=thread-local -verify=expected,thread-local-dtors %s +// RUN: %clang_cc1 -verify=expected,thread-local-dtors,all-dtors %s +// RUN: %clang_cc1 -fexceptions -fc++-static-destructors=none -verify %s +// RUN: %clang_cc1 -fexceptions -fc++-static-destructors=thread-local -verify=expected,thread-local-dtors %s +// RUN: %clang_cc1 -fexceptions -verify=expected,thread-local-dtors,all-dtors %s struct SecretDestructor { -#ifndef NO_DTORS - // expected-note@+2 4 {{private}} -#endif private: ~SecretDestructor(); // expected-note + {{private}} }; -SecretDestructor sd1; -thread_local SecretDestructor sd2; +SecretDestructor sd1; // all-dtors-error{{private}} +thread_local SecretDestructor sd2; // thread-local-dtors-error{{private}} void locals() { - static SecretDestructor sd3; - thread_local SecretDestructor sd4; + static SecretDestructor sd3; // all-dtors-error{{private}} + thread_local SecretDestructor sd4; // thread-local-dtors-error{{private}} } -#ifndef NO_DTORS -// SecretDestructor sd1; // expected-error@-8 {{private}} -// thread_local SecretDestructor sd2; // expected-error@-8 {{private}} -// void locals() { -// static SecretDestructor sd3; // expected-error@-8 {{private}} -// thread_local SecretDestructor sd4; // expected-error@-8 {{private}} -// } -#endif - [[clang::always_destroy]] SecretDestructor sd6; // expected-error{{private}} [[clang::always_destroy]] thread_local SecretDestructor sd7; // expected-error{{private}} >From 76d4eb283b3c20e9fe11dcb075e442a87d4492bb Mon Sep 17 00:00:00 2001 From: Shoaib Meenai <smee...@fb.com> Date: Tue, 20 Aug 2024 11:02:42 -0700 Subject: [PATCH 2/2] Address comments and add release note --- clang/docs/ReleaseNotes.rst | 7 +++++++ clang/lib/Driver/ToolChains/Clang.cpp | 3 +-- clang/test/Driver/cxx-static-destructors.cpp | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 249249971dec7c..4dbf2fde5786da 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -168,6 +168,13 @@ Non-comprehensive list of changes in this release New Compiler Flags ------------------ +- The ``-fc++-static-destructors={all,thread-local,none}`` flag was + added to control which C++ variables have static destructors + registered: all (the default) does so for all variables, thread-local + only for thread-local variables, and none (which corresponds to the + existing ``-fno-c++-static-destructors`` flag) skips all static + destructors registration. + Deprecated Compiler Flags ------------------------- diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 68ac374e036b1f..9714a0d86b675b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7968,8 +7968,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers, options::OPT_fno_complete_member_pointers); if (Arg *A = Args.getLastArg(options::OPT_cxx_static_destructors_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("-fc++-static-destructors=") + A->getValue())); + A->render(Args, CmdArgs); addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false); diff --git a/clang/test/Driver/cxx-static-destructors.cpp b/clang/test/Driver/cxx-static-destructors.cpp index 71da4d28c25142..a12a292a387bda 100644 --- a/clang/test/Driver/cxx-static-destructors.cpp +++ b/clang/test/Driver/cxx-static-destructors.cpp @@ -1,7 +1,9 @@ // RUN: %clang -### -c -fc++-static-destructors=all %s 2>&1 | FileCheck --check-prefix ALL %s // RUN: %clang -### -c -fc++-static-destructors %s 2>&1 | FileCheck --check-prefix ALL %s +// RUN: %clang -### -c -fno-c++-static-destructors -fc++-static-destructors %s 2>&1 | FileCheck --check-prefix ALL %s // RUN: %clang -### -c -fc++-static-destructors=none %s 2>&1 | FileCheck --check-prefix NONE %s // RUN: %clang -### -c -fno-c++-static-destructors %s 2>&1 | FileCheck --check-prefix NONE %s +// RUN: %clang -### -c -fc++-static-destructors -fno-c++-static-destructors %s 2>&1 | FileCheck --check-prefix NONE %s // RUN: %clang -### -c -fc++-static-destructors=thread-local %s 2>&1 | FileCheck --check-prefix THREAD-LOCAL %s // ALL: -fc++-static-destructors=all _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits