r340306 - Add a new flag and attributes to control static destructor registration

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 21 10:24:06 PDT 2018


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 at +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 at -8 {{private}}
+// thread_local SecretDestructor sd2;     // expected-error at -8 {{private}}
+// void locals() {
+//   static SecretDestructor sd3;         // expected-error at -8 {{private}}
+//   thread_local SecretDestructor sd4;   // expected-error at -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
+}




More information about the cfe-commits mailing list