Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -13108,11 +13108,16 @@ if (ClassDecl->hasIrrelevantDestructor()) return; if (ClassDecl->isDependentContext()) return; - if (VD->isNoDestroy(getASTContext())) + bool IsNoDestroy = VD->isNoDestroy(getASTContext()); + if (IsNoDestroy && !VD->getType()->isArrayType()) return; CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); MarkFunctionReferenced(VD->getLocation(), Destructor); + + if (IsNoDestroy) + return; + CheckDestructorAccess(VD->getLocation(), Destructor, PDiag(diag::err_access_dtor_var) << VD->getDeclName() Index: clang/test/CodeGenCXX/no_destroy.cpp =================================================================== --- clang/test/CodeGenCXX/no_destroy.cpp +++ clang/test/CodeGenCXX/no_destroy.cpp @@ -1,11 +1,14 @@ // RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s +// RUN: %clang_cc1 -fexceptions %s -emit-llvm -triple x86_64-apple-macosx10.13.0 -o - | FileCheck %s --check-prefixes=CHECK,EXCEPTIONS struct NonTrivial { ~NonTrivial(); }; +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::no_destroy]] NonTrivial nt1; +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::no_destroy]] thread_local NonTrivial nt2; @@ -13,11 +16,14 @@ ~NonTrivial2(); }; +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev NonTrivial2 nt21; +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev thread_local NonTrivial2 nt22; +// CHECK-LABEL: define void @_Z1fv void f() { // CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev static NonTrivial2 nt21; @@ -25,7 +31,21 @@ thread_local NonTrivial2 nt22; } +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::always_destroy]] NonTrivial nt3; +// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::always_destroy]] thread_local NonTrivial nt4; + + +struct NonTrivial3 { + NonTrivial3(); + ~NonTrivial3(); +}; +[[clang::no_destroy]] NonTrivial3 arr[10]; + +// CHECK-LABEL: define internal void @__cxx_global_var_init +// CHECK: {{invoke|call}} void @_ZN11NonTrivial3C1Ev +// EXCEPTIONS: call void @_ZN11NonTrivial3D1Ev +// CHECK-NOT: call i32 @__cxa_atexit Index: clang/test/SemaCXX/no_destroy.cpp =================================================================== --- clang/test/SemaCXX/no_destroy.cpp +++ clang/test/SemaCXX/no_destroy.cpp @@ -6,6 +6,9 @@ // expected-note@+2 4 {{private}} #endif private: ~SecretDestructor(); // expected-note 2 {{private}} +#ifndef NO_DTORS + // expected-note@-2 3 {{private}} +#endif }; SecretDestructor sd1; @@ -44,3 +47,32 @@ [[clang::no_destroy(0)]] int no_args; // expected-error{{'no_destroy' attribute takes no arguments}} [[clang::always_destroy(0)]] int no_args2; // expected-error{{'always_destroy' attribute takes no arguments}} + +SecretDestructor arr[10]; +#ifndef NO_DTORS +// expected-error@-2 {{variable of type 'SecretDestructor [10]' has private destructor}} +#endif + +void local_arrays() { + static SecretDestructor arr2[10]; +#ifndef NO_DTORS + // expected-error@-2 {{variable of type 'SecretDestructor [10]' has private destructor}} +#endif + thread_local SecretDestructor arr3[10]; +#ifndef NO_DTORS + // expected-error@-2 {{variable of type 'SecretDestructor [10]' has private destructor}} +#endif +} + +struct Base { + ~Base(); +}; +struct Derived1 { + Derived1(int); + Base b; +}; +struct Derived2 { + Derived1 b; +}; + +[[clang::no_destroy]] Derived2 d2[] = {0, 0};