Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -1818,6 +1818,17 @@ return FlexArrayDiag != diag::ext_flexible_array_init; } +static bool checkElementDestructor(CXXRecordDecl *CXXRD, QualType RecType, + SourceLocation Loc, Sema &SemaRef) { + CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD); + SemaRef.CheckDestructorAccess( + Loc, Destructor, SemaRef.PDiag(diag::err_access_dtor_temp) << RecType); + SemaRef.MarkFunctionReferenced(Loc, Destructor); + if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc)) + return false; + return true; +} + void InitListChecker::CheckStructUnionTypes( const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field, @@ -1835,6 +1846,32 @@ return; } + // Check if destructors of base classes and members are accessible. + // + // The destructor for each element of class type is potentially invoked + // (15.4 [class.dtor]) from the context where the aggregate + // initialization occurs. + if (!VerifyOnly) + if (auto *CXXRD = DeclType->getAsCXXRecordDecl()) { + SourceLocation Loc = IList->getBeginLoc(); + for (auto &Base : Bases) + if (auto *CXXRDMember = Base.getType()->getAsCXXRecordDecl()) + if (!checkElementDestructor(CXXRDMember, Base.getType(), Loc, + SemaRef)) { + hadError = true; + return; + } + + for (FieldDecl *FD : CXXRD->fields()) { + QualType ET = SemaRef.Context.getBaseElementType(FD->getType()); + if (auto *CXXRDMember = ET->getAsCXXRecordDecl()) + if (!checkElementDestructor(CXXRDMember, ET, Loc, SemaRef)) { + hadError = true; + return; + } + } + } + if (DeclType->isUnionType() && IList->getNumInits() == 0) { RecordDecl *RD = DeclType->getAs()->getDecl(); Index: test/CodeGenObjCXX/arc-list-init-destruct.mm =================================================================== --- /dev/null +++ test/CodeGenObjCXX/arc-list-init-destruct.mm @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -std=c++1z -fobjc-arc -fobjc-exceptions -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s + +// CHECK: %[[V0:.*]] = type opaque +// CHECK: %[[STRUCT_CLASS1:.*]] = type { %[[V0]]* } + +@interface Class0; +@end + +struct Class1 { + Class0 *f; +}; + +struct Container { + Class1 a; + bool b; +}; + +bool getBool() { + return false; +} + +Class0 *g; + +// CHECK: define {{.*}} @_Z4testv() +// CHECK: invoke zeroext i1 @_Z7getBoolv() +// CHECK: landingpad { i8*, i32 } +// CHECK: call void @_ZN6Class1D1Ev(%[[STRUCT_CLASS1]]* %{{.*}}) +// CHECK: br label + +// CHECK: define linkonce_odr void @_ZN6Class1D1Ev( + +Container test() { + return {{g}, getBool()}; +} Index: test/SemaCXX/aggregate-initialization.cpp =================================================================== --- test/SemaCXX/aggregate-initialization.cpp +++ test/SemaCXX/aggregate-initialization.cpp @@ -186,3 +186,51 @@ // amount of time. struct A { int n; int arr[1000 * 1000 * 1000]; } a = {1, {2}}; } + +namespace ElementDestructor { + // The destructor for each element of class type is potentially invoked + // (15.4 [class.dtor]) from the context where the aggregate initialization + // occurs. Produce a diagnostic if an element's destructor isn't accessible. + + class X { int f; ~X(); }; // expected-note {{implicitly declared private here}} + struct Y { X x; }; + + void test0() { + auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}} + } + + struct S0 { int f; ~S0() = delete; }; // expected-note 3 {{'~S0' has been explicitly marked deleted here}} + struct S1 { S0 s0; int f; }; + + S1 test1() { + auto *t = new S1 { .f = 1 }; // expected-error {{attempt to use a deleted function}} + return {2}; // expected-error {{attempt to use a deleted function}} + } + + // Check if the type of an array element has a destructor. + struct S2 { S0 a[4]; }; + + void test2() { + auto *t = new S2 {1,2,3,4}; // expected-error {{attempt to use a deleted function}} + } + +#if __cplusplus >= 201703L + namespace BaseDestructor { + struct S0 { int f; ~S0() = delete; }; // expected-note {{'~S0' has been explicitly marked deleted here}} + + // Check destructor of base class. + struct S3 : S0 {}; + + void test3() { + S3 s3 = {1}; // expected-error {{attempt to use a deleted function}} + } + } +#endif + + // A's destructor doesn't have to be accessible from the context of C's + // initialization. + struct A { friend struct B; private: ~A(); }; + struct B { B(); A a; }; + struct C { B b; }; + C c = { B() }; +}