Skip to content

Commit 7945435

Browse files
authored
[clang] Add support for omitting only global destructors (#104899)
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.
1 parent e1cf849 commit 7945435

File tree

10 files changed

+74
-34
lines changed

10 files changed

+74
-34
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ Non-comprehensive list of changes in this release
173173
New Compiler Flags
174174
------------------
175175

176+
- The ``-fc++-static-destructors={all,thread-local,none}`` flag was
177+
added to control which C++ variables have static destructors
178+
registered: all (the default) does so for all variables, thread-local
179+
only for thread-local variables, and none (which corresponds to the
180+
existing ``-fno-c++-static-destructors`` flag) skips all static
181+
destructors registration.
182+
176183
Deprecated Compiler Flags
177184
-------------------------
178185

clang/include/clang/Basic/LangOptions.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,9 @@ LANGOPT(FixedPoint, 1, 0, "fixed point types")
464464
LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
465465
"unsigned fixed point types having one extra padding bit")
466466

467-
LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
467+
ENUM_LANGOPT(RegisterStaticDestructors, RegisterStaticDestructorsKind, 2,
468+
RegisterStaticDestructorsKind::All,
469+
"Register C++ static destructors")
468470

469471
LANGOPT(RegCall4, 1, 0, "Set __regcall4 as a default calling convention to respect __regcall ABI v.4")
470472

clang/include/clang/Basic/LangOptions.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,16 @@ class LangOptionsBase {
458458
CX_None
459459
};
460460

461+
/// Controls which variables have static destructors registered.
462+
enum class RegisterStaticDestructorsKind {
463+
/// Register static destructors for all variables.
464+
All,
465+
/// Register static destructors only for thread-local variables.
466+
ThreadLocal,
467+
/// Don't register static destructors for any variables.
468+
None,
469+
};
470+
461471
// Define simple language options (with no accessors).
462472
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
463473
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)

clang/include/clang/Driver/Options.td

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,11 +2302,18 @@ defm fixed_point : BoolFOption<"fixed-point",
23022302
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
23032303
NegFlag<SetFalse, [], [ClangOption], "Disable">,
23042304
BothFlags<[], [ClangOption], " fixed point types">>;
2305-
defm cxx_static_destructors : BoolFOption<"c++-static-destructors",
2306-
LangOpts<"RegisterStaticDestructors">, DefaultTrue,
2307-
NegFlag<SetFalse, [], [ClangOption, CC1Option],
2308-
"Disable C++ static destructor registration">,
2309-
PosFlag<SetTrue>>;
2305+
def cxx_static_destructors_EQ : Joined<["-"], "fc++-static-destructors=">, Group<f_Group>,
2306+
HelpText<"Controls which variables C++ static destructors are registered for">,
2307+
Values<"all,thread-local,none">,
2308+
NormalizedValues<["All", "ThreadLocal", "None"]>,
2309+
NormalizedValuesScope<"LangOptions::RegisterStaticDestructorsKind">,
2310+
MarshallingInfoEnum<LangOpts<"RegisterStaticDestructors">, "All">,
2311+
Visibility<[ClangOption, CC1Option]>;
2312+
def cxx_static_destructors : Flag<["-"], "fc++-static-destructors">, Group<f_Group>,
2313+
Alias<cxx_static_destructors_EQ>, AliasArgs<["all"]>;
2314+
def no_cxx_static_destructors : Flag<["-"], "fno-c++-static-destructors">, Group<f_Group>,
2315+
Alias<cxx_static_destructors_EQ>, AliasArgs<["none"]>,
2316+
HelpText<"Disable C++ static destructor registration">;
23102317
def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>,
23112318
Visibility<[ClangOption, CC1Option]>,
23122319
MarshallingInfoString<CodeGenOpts<"SymbolPartition">>;

clang/lib/AST/Decl.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,9 +2799,17 @@ bool VarDecl::isKnownToBeDefined() const {
27992799
}
28002800

28012801
bool VarDecl::isNoDestroy(const ASTContext &Ctx) const {
2802-
return hasGlobalStorage() && (hasAttr<NoDestroyAttr>() ||
2803-
(!Ctx.getLangOpts().RegisterStaticDestructors &&
2804-
!hasAttr<AlwaysDestroyAttr>()));
2802+
if (!hasGlobalStorage())
2803+
return false;
2804+
if (hasAttr<NoDestroyAttr>())
2805+
return true;
2806+
if (hasAttr<AlwaysDestroyAttr>())
2807+
return false;
2808+
2809+
using RSDKind = LangOptions::RegisterStaticDestructorsKind;
2810+
RSDKind K = Ctx.getLangOpts().getRegisterStaticDestructors();
2811+
return K == RSDKind::None ||
2812+
(K == RSDKind::ThreadLocal && getTLSKind() == TLS_None);
28052813
}
28062814

28072815
QualType::DestructionKind

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7972,8 +7972,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
79727972
options::OPT_fno_keep_persistent_storage_variables);
79737973
Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers,
79747974
options::OPT_fno_complete_member_pointers);
7975-
Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors,
7976-
options::OPT_fno_cxx_static_destructors);
7975+
if (Arg *A = Args.getLastArg(options::OPT_cxx_static_destructors_EQ))
7976+
A->render(Args, CmdArgs);
79777977

79787978
addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);
79797979

clang/test/CodeGenCXX/always_destroy.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
// RUN: %clang_cc1 %s -fno-c++-static-destructors -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s
1+
// RUN: %clang_cc1 %s -fc++-static-destructors=none -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | \
2+
// RUN: FileCheck --check-prefixes=CHECK,NO-DTORS %s
3+
// RUN: %clang_cc1 %s -fc++-static-destructors=thread-local -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | \
4+
// RUN: FileCheck --check-prefixes=CHECK,THREAD-LOCAL-DTORS %s
25

36
struct NonTrivial {
47
~NonTrivial();
58
};
69

710
// CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev
811
NonTrivial nt1;
9-
// CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev
12+
// NO-DTORS-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev
13+
// THREAD-LOCAL-DTORS: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev
1014
thread_local NonTrivial nt2;
1115

1216
struct NonTrivial2 {

clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu -DNOATTR %s -o - | FileCheck %s
22
// RUN: %clang_cc1 -std=c++2a -emit-llvm -O0 -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefix=CHECK-ATTR
3-
// 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
3+
// 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
4+
// 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
45

56
// Regression test for D54344. Class with no user-defined destructor
67
// that has an inherited member that has a non-trivial destructor
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang -### -c -fc++-static-destructors=all %s 2>&1 | FileCheck --check-prefix ALL %s
2+
// RUN: %clang -### -c -fc++-static-destructors %s 2>&1 | FileCheck --check-prefix ALL %s
3+
// RUN: %clang -### -c -fno-c++-static-destructors -fc++-static-destructors %s 2>&1 | FileCheck --check-prefix ALL %s
4+
// RUN: %clang -### -c -fc++-static-destructors=none %s 2>&1 | FileCheck --check-prefix NONE %s
5+
// RUN: %clang -### -c -fno-c++-static-destructors %s 2>&1 | FileCheck --check-prefix NONE %s
6+
// RUN: %clang -### -c -fc++-static-destructors -fno-c++-static-destructors %s 2>&1 | FileCheck --check-prefix NONE %s
7+
// RUN: %clang -### -c -fc++-static-destructors=thread-local %s 2>&1 | FileCheck --check-prefix THREAD-LOCAL %s
8+
9+
// ALL: -fc++-static-destructors=all
10+
// NONE: -fc++-static-destructors=none
11+
// THREAD-LOCAL: -fc++-static-destructors=thread-local

clang/test/SemaCXX/no_destroy.cpp

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,21 @@
1-
// RUN: %clang_cc1 -DNO_DTORS -DNO_EXCEPTIONS -fno-c++-static-destructors -verify %s
2-
// RUN: %clang_cc1 -DNO_EXCEPTIONS -verify %s
3-
// RUN: %clang_cc1 -DNO_DTORS -fexceptions -fno-c++-static-destructors -verify %s
4-
// RUN: %clang_cc1 -fexceptions -verify %s
1+
// RUN: %clang_cc1 -fc++-static-destructors=none -verify %s
2+
// RUN: %clang_cc1 -fc++-static-destructors=thread-local -verify=expected,thread-local-dtors %s
3+
// RUN: %clang_cc1 -verify=expected,thread-local-dtors,all-dtors %s
4+
// RUN: %clang_cc1 -fexceptions -fc++-static-destructors=none -verify %s
5+
// RUN: %clang_cc1 -fexceptions -fc++-static-destructors=thread-local -verify=expected,thread-local-dtors %s
6+
// RUN: %clang_cc1 -fexceptions -verify=expected,thread-local-dtors,all-dtors %s
57

68
struct SecretDestructor {
7-
#ifndef NO_DTORS
8-
// expected-note@+2 4 {{private}}
9-
#endif
109
private: ~SecretDestructor(); // expected-note + {{private}}
1110
};
1211

13-
SecretDestructor sd1;
14-
thread_local SecretDestructor sd2;
12+
SecretDestructor sd1; // all-dtors-error{{private}}
13+
thread_local SecretDestructor sd2; // thread-local-dtors-error{{private}}
1514
void locals() {
16-
static SecretDestructor sd3;
17-
thread_local SecretDestructor sd4;
15+
static SecretDestructor sd3; // all-dtors-error{{private}}
16+
thread_local SecretDestructor sd4; // thread-local-dtors-error{{private}}
1817
}
1918

20-
#ifndef NO_DTORS
21-
// SecretDestructor sd1; // expected-error@-8 {{private}}
22-
// thread_local SecretDestructor sd2; // expected-error@-8 {{private}}
23-
// void locals() {
24-
// static SecretDestructor sd3; // expected-error@-8 {{private}}
25-
// thread_local SecretDestructor sd4; // expected-error@-8 {{private}}
26-
// }
27-
#endif
28-
2919
[[clang::always_destroy]] SecretDestructor sd6; // expected-error{{private}}
3020
[[clang::always_destroy]] thread_local SecretDestructor sd7; // expected-error{{private}}
3121

0 commit comments

Comments
 (0)