Skip to content

[clang] Add support for omitting only global destructors #104899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------------------------

Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 12 additions & 5 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">>;
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7967,8 +7967,8 @@ 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))
A->render(Args, CmdArgs);

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

Expand Down
8 changes: 6 additions & 2 deletions clang/test/CodeGenCXX/always_destroy.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// 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();
};

// 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 {
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 11 additions & 0 deletions clang/test/Driver/cxx-static-destructors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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
// NONE: -fc++-static-destructors=none
// THREAD-LOCAL: -fc++-static-destructors=thread-local
30 changes: 10 additions & 20 deletions clang/test/SemaCXX/no_destroy.cpp
Original file line number Diff line number Diff line change
@@ -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}}

Expand Down
Loading