Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -815,6 +815,27 @@ } } +static bool checkMemberDestructor(CXXRecordDecl *CXXRD, QualType RecType, + SourceLocation Loc, bool IsMember, + Sema &SemaRef) { + if (IsMember) { + 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; + } + + for (FieldDecl *FD : CXXRD->fields()) + if (auto *CXXRDMember = FD->getType()->getAsCXXRecordDecl()) + if (!checkMemberDestructor(CXXRDMember, FD->getType(), Loc, true, + SemaRef)) + return false; + + return true; +} + InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, bool VerifyOnly, @@ -838,6 +859,16 @@ if (RequiresSecondPass && !hadError) FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, nullptr, 0); + + // Check if destructors of 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 (auto *CXXRD = T->getAsCXXRecordDecl()) + if (!checkMemberDestructor(CXXRD, T, IL->getLocStart(), + /*IsMember*/ false, S)) + hadError = true; } } 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,24 @@ // 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 2 {{'~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}} + } +}