Author: epilk Date: Tue Aug 21 10:24:06 2018 New Revision: 340306 URL: http://llvm.org/viewvc/llvm-project?rev=340306&view=rev Log: Add a new flag and attributes to control static destructor registration
This commit adds the flag -fno-c++-static-destructors and the attributes [[clang::no_destroy]] and [[clang::always_destroy]]. no_destroy specifies that a specific static or thread duration variable shouldn't have it's destructor registered, and is the default in -fno-c++-static-destructors mode. always_destroy is the opposite, and is the default in -fc++-static-destructors mode. A variable whose destructor is disabled (either because of -fno-c++-static-destructors or [[clang::no_destroy]]) doesn't count as a use of the destructor, so we don't do any access checking or mark it referenced. We also don't emit -Wexit-time-destructors for these variables. rdar://21734598 Differential revision: https://reviews.llvm.org/D50994 Added: cfe/trunk/test/CodeGenCXX/always_destroy.cpp cfe/trunk/test/CodeGenCXX/no_destroy.cpp cfe/trunk/test/SemaCXX/no_destroy.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/Basic/Attr.td cfe/trunk/include/clang/Basic/AttrDocs.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/LangOptions.def cfe/trunk/include/clang/Driver/Options.td cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp cfe/trunk/lib/Driver/ToolChains/Clang.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test cfe/trunk/test/SemaCXX/warn-exit-time-destructors.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Tue Aug 21 10:24:06 2018 @@ -1469,6 +1469,9 @@ public: // has no definition within this source file. bool isKnownToBeDefined() const; + /// Do we need to emit an exit-time destructor for this variable? + bool isNoDestroy(const ASTContext &) const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Tue Aug 21 10:24:06 2018 @@ -3009,3 +3009,15 @@ def Reinitializes : InheritableAttr { let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>; let Documentation = [ReinitializesDocs]; } + +def NoDestroy : InheritableAttr { + let Spellings = [Clang<"no_destroy", 0>]; + let Subjects = SubjectList<[Var]>; + let Documentation = [NoDestroyDocs]; +} + +def AlwaysDestroy : InheritableAttr { + let Spellings = [Clang<"always_destroy", 0>]; + let Subjects = SubjectList<[Var]>; + let Documentation = [AlwaysDestroyDocs]; +} Modified: cfe/trunk/include/clang/Basic/AttrDocs.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td (original) +++ cfe/trunk/include/clang/Basic/AttrDocs.td Tue Aug 21 10:24:06 2018 @@ -3486,3 +3486,22 @@ a container class: }; }]; } + +def AlwaysDestroyDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``always_destroy`` attribute specifies that a variable with static or thread +storage duration should have its exit-time destructor run. This attribute is the +default unless clang was invoked with -fno-c++-static-destructors. + }]; +} + +def NoDestroyDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``no_destroy`` attribute specifies that a variable with static or thread +storage duration shouldn't have its exit-time destructor run. Annotating every +static and thread duration variable with this attribute is equivalent to +invoking clang with -fno-c++-static-destructors. + }]; +} Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug 21 10:24:06 2018 @@ -1809,6 +1809,10 @@ def err_destructor_expr_type_mismatch : def note_destructor_type_here : Note< "type %0 is declared here">; +def err_destroy_attr_on_non_static_var : Error< + "%select{no_destroy|always_destroy}0 attribute can only be applied to a" + " variable with static or thread storage duration">; + def err_destructor_template : Error< "destructor cannot be declared as a template">; Modified: cfe/trunk/include/clang/Basic/LangOptions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.def (original) +++ cfe/trunk/include/clang/Basic/LangOptions.def Tue Aug 21 10:24:06 2018 @@ -308,6 +308,8 @@ LANGOPT(FixedPoint, 1, 0, "fixed point t LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0, "unsigned fixed point types having one extra padding bit") +LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT Modified: cfe/trunk/include/clang/Driver/Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/Options.td (original) +++ cfe/trunk/include/clang/Driver/Options.td Tue Aug 21 10:24:06 2018 @@ -898,6 +898,13 @@ def ffixed_point : Flag<["-"], "ffixed-p Flags<[CC1Option]>, HelpText<"Enable fixed point types">; def fno_fixed_point : Flag<["-"], "fno-fixed-point">, Group<f_Group>, HelpText<"Disable fixed point types">; +def fcxx_static_destructors : Flag<["-"], "fc++-static-destructors">, + Group<f_Group>, + HelpText<"Enable C++ static destructor registration (the default)">; +def fno_cxx_static_destructors : Flag<["-"], "fno-c++-static-destructors">, + Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Disable C++ static destructor registration">; // Begin sanitizer flags. These should all be core options exposed in all driver // modes. Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Tue Aug 21 10:24:06 2018 @@ -2449,6 +2449,12 @@ bool VarDecl::isKnownToBeDefined() const return hasDefinition(); } +bool VarDecl::isNoDestroy(const ASTContext &Ctx) const { + return hasGlobalStorage() && (hasAttr<NoDestroyAttr>() || + (!Ctx.getLangOpts().RegisterStaticDestructors && + !hasAttr<AlwaysDestroyAttr>())); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { if (isStaticDataMember()) // FIXME: Remove ? Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Aug 21 10:24:06 2018 @@ -2342,6 +2342,9 @@ void ItaniumCXXABI::registerGlobalDtor(C const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { + if (D.isNoDestroy(CGM.getContext())) + return; + // Use __cxa_atexit if available. if (CGM.getCodeGenOpts().CXAAtExit) return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind()); Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Aug 21 10:24:06 2018 @@ -2240,6 +2240,9 @@ static void emitGlobalDtorWithTLRegDtor( void MicrosoftCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, llvm::Constant *Dtor, llvm::Constant *Addr) { + if (D.isNoDestroy(CGM.getContext())) + return; + if (D.getTLSKind()) return emitGlobalDtorWithTLRegDtor(CGF, D, Dtor, Addr); Modified: cfe/trunk/lib/Driver/ToolChains/Clang.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/Clang.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/Driver/ToolChains/Clang.cpp (original) +++ cfe/trunk/lib/Driver/ToolChains/Clang.cpp Tue Aug 21 10:24:06 2018 @@ -4832,6 +4832,10 @@ void Clang::ConstructJob(Compilation &C, options::OPT_fno_complete_member_pointers, false)) CmdArgs.push_back("-fcomplete-member-pointers"); + if (!Args.hasFlag(options::OPT_fcxx_static_destructors, + options::OPT_fno_cxx_static_destructors, true)) + CmdArgs.push_back("-fno-c++-static-destructors"); + if (Arg *A = Args.getLastArg(options::OPT_moutline, options::OPT_mno_outline)) { if (A->getOption().matches(options::OPT_moutline)) { Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Aug 21 10:24:06 2018 @@ -2772,6 +2772,8 @@ static void ParseLangArgs(LangOptions &O // -fallow-editor-placeholders Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); + Opts.RegisterStaticDestructors = !Args.hasArg(OPT_fno_cxx_static_destructors); + if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { Opts.setClangABICompat(LangOptions::ClangABI::Latest); Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Aug 21 10:24:06 2018 @@ -5917,6 +5917,20 @@ static void handleOpenCLAccessAttr(Sema AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } +static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { + if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->hasGlobalStorage()) { + S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var) + << (A.getKind() == ParsedAttr::AT_AlwaysDestroy); + return; + } + + if (A.getKind() == ParsedAttr::AT_AlwaysDestroy) { + handleSimpleAttributeWithExclusions<AlwaysDestroyAttr, NoDestroyAttr>(S, D, A); + } else { + handleSimpleAttributeWithExclusions<NoDestroyAttr, AlwaysDestroyAttr>(S, D, A); + } +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6587,6 +6601,11 @@ static void ProcessDeclAttribute(Sema &S case ParsedAttr::AT_Reinitializes: handleSimpleAttribute<ReinitializesAttr>(S, D, AL); break; + + case ParsedAttr::AT_AlwaysDestroy: + case ParsedAttr::AT_NoDestroy: + handleDestroyAttr(S, D, AL); + break; } } Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 21 10:24:06 2018 @@ -12910,6 +12910,9 @@ void Sema::FinalizeVarWithDestructor(Var if (ClassDecl->hasIrrelevantDestructor()) return; if (ClassDecl->isDependentContext()) return; + if (VD->isNoDestroy(getASTContext())) + return; + CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); MarkFunctionReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, Added: cfe/trunk/test/CodeGenCXX/always_destroy.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/always_destroy.cpp?rev=340306&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/always_destroy.cpp (added) +++ cfe/trunk/test/CodeGenCXX/always_destroy.cpp Tue Aug 21 10:24:06 2018 @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 %s -fno-c++-static-destructors -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s + +struct NonTrivial { + ~NonTrivial(); +}; + +// CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev +NonTrivial nt1; +// CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +thread_local NonTrivial nt2; + +struct NonTrivial2 { + ~NonTrivial2(); +}; + +// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev +[[clang::always_destroy]] NonTrivial2 nt21; +// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev +[[clang::always_destroy]] thread_local NonTrivial2 nt22; + +void f() { + // CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev + [[clang::always_destroy]] static NonTrivial2 nt21; + // CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev + [[clang::always_destroy]] thread_local NonTrivial2 nt22; +} + +// CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::no_destroy]] NonTrivial nt3; +// CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::no_destroy]] thread_local NonTrivial nt4; Added: cfe/trunk/test/CodeGenCXX/no_destroy.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/no_destroy.cpp?rev=340306&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/no_destroy.cpp (added) +++ cfe/trunk/test/CodeGenCXX/no_destroy.cpp Tue Aug 21 10:24:06 2018 @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s + +struct NonTrivial { + ~NonTrivial(); +}; + +// CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::no_destroy]] NonTrivial nt1; +// CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::no_destroy]] thread_local NonTrivial nt2; + +struct NonTrivial2 { + ~NonTrivial2(); +}; + +// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev +NonTrivial2 nt21; +// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev +thread_local NonTrivial2 nt22; + +void f() { + // CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev + static NonTrivial2 nt21; + // CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev + thread_local NonTrivial2 nt22; +} + +// CHECK: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::always_destroy]] NonTrivial nt3; +// CHECK: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev +[[clang::always_destroy]] thread_local NonTrivial nt4; Modified: cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test (original) +++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test Tue Aug 21 10:24:06 2018 @@ -2,7 +2,7 @@ // The number of supported attributes should never go down! -// CHECK: #pragma clang attribute supports 72 attributes: +// CHECK: #pragma clang attribute supports 74 attributes: // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function) @@ -11,6 +11,7 @@ // CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace) // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias) // CHECK-NEXT: AllocSize (SubjectMatchRule_function) +// CHECK-NEXT: AlwaysDestroy (SubjectMatchRule_variable) // CHECK-NEXT: Annotate () // CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function) @@ -38,6 +39,7 @@ // CHECK-NEXT: MipsLongCall (SubjectMatchRule_function) // CHECK-NEXT: MipsShortCall (SubjectMatchRule_function) // CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter) +// CHECK-NEXT: NoDestroy (SubjectMatchRule_variable) // CHECK-NEXT: NoDuplicate (SubjectMatchRule_function) // CHECK-NEXT: NoEscape (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: NoMicroMips (SubjectMatchRule_function) Added: cfe/trunk/test/SemaCXX/no_destroy.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/no_destroy.cpp?rev=340306&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/no_destroy.cpp (added) +++ cfe/trunk/test/SemaCXX/no_destroy.cpp Tue Aug 21 10:24:06 2018 @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -DNO_DTORS -fno-c++-static-destructors -verify %s +// RUN: %clang_cc1 -verify %s + +struct SecretDestructor { +#ifndef NO_DTORS + // expected-note@+2 4 {{private}} +#endif +private: ~SecretDestructor(); // expected-note 2 {{private}} +}; + +SecretDestructor sd1; +thread_local SecretDestructor sd2; +void locals() { + static SecretDestructor sd3; + thread_local SecretDestructor sd4; +} + +#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}} + +[[clang::no_destroy]] SecretDestructor sd8; + +int main() { + [[clang::no_destroy]] int p; // expected-error{{no_destroy attribute can only be applied to a variable with static or thread storage duration}} + [[clang::always_destroy]] int p2; // expected-error{{always_destroy attribute can only be applied to a variable with static or thread storage duration}} + [[clang::no_destroy]] static int p3; + [[clang::always_destroy]] static int p4; +} + +[[clang::always_destroy]] [[clang::no_destroy]] int p; // expected-error{{'no_destroy' and 'always_destroy' attributes are not compatible}} // expected-note{{here}} +[[clang::no_destroy]] [[clang::always_destroy]] int p2; // expected-error{{'always_destroy' and 'no_destroy' attributes are not compatible}} // expected-note{{here}} Modified: cfe/trunk/test/SemaCXX/warn-exit-time-destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-exit-time-destructors.cpp?rev=340306&r1=340305&r2=340306&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-exit-time-destructors.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-exit-time-destructors.cpp Tue Aug 21 10:24:06 2018 @@ -43,3 +43,8 @@ namespace test3 { }; E e; } + +namespace test4 { +struct A { ~A(); }; +[[clang::no_destroy]] A a; // no warning +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits