[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-09 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

In D45898#1324625 , @orivej wrote:

> I have noticed that this change breaks seemingly valid code:
>
>   class A { protected: ~A(); };
>   struct B : A {};
>   B f() { return B(); }
>   B g() { return {}; }
>
>
> `f` compiles, but `g` fails with `temporary of type 'A' has protected 
> destructor`. (g++ 8.2 compiles this file.)


We talked about this in the analysis for https://reviews.llvm.org/D53860, and 
Richard decided that it is indeed invalid under the standard.

As a language designer I'm not sure that's a good language rule, but it's the 
realm of a standard defect, not a compiler bug.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-09 Thread Orivej Desh via Phabricator via cfe-commits
orivej added a comment.

I have noticed that this change breaks seemingly valid code:

  class A { protected: ~A(); };
  struct B : A {};
  B f() { return B(); }
  B g() { return {}; }

`f` compiles, but `g` fails with `temporary of type 'A' has protected 
destructor`. (g++ 8.2 compiles this file.)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-08 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Yeah, if we weren't exercising the code in our test suite, that would be one 
thing, but I think a language-mode-specific test probably isn't too valuable.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-08 Thread Orivej Desh via Phabricator via cfe-commits
orivej added a comment.

Actually, `arc-list-init-destruct.mm` crashes Clang 7 with the same backtrace 
as this test case, and Clang trunk generates similar assembly (to the the point 
that I could essentially copy the `// CHECK` comments from the .mm test to a 
.cpp test), so I'm not sure if adding a .cpp test is valuable…


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-08 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

Always worth adding more tests.  Mind writing that one up as a commit?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-12-08 Thread Orivej Desh via Phabricator via cfe-commits
orivej added a comment.
Herald added a subscriber: jkorous.

The committed test does not crash Clang 7, but the following test does, yet it 
compiles without any warnings by the current Clang trunk thanks to this fix.

  struct A { ~A(); };
  struct B : A {};
  struct C { C();  B b; };
  struct D { C c, d; };
  D f() { return {}; }


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D45898/new/

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-06 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC341629: [Sema] Check that the destructor for each element of 
class type is (authored by ahatanak, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

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() };
+}
Index: test/CodeGenObjCXX/arc-list-init-destruct.mm
===
--- test/CodeGenObjCXX/arc-list-init-destruct.mm
+++ 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: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1818,6 +1818,30 @@
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
+/// Check if the type of a class element has an accessible destructor.
+///
+/// Aggregate initialization requires a class element's destructor be
+/// accessible per 11.6.1 [dcl.init.aggr]:
+///
+/// The destructor for each element of class type is potentially invoked
+/// (15.4 [class.dtor]) from the context where the aggregate initialization
+/// occurs.
+static bool hasAccessibleDestructor(QualType ElementType, SourceLocation Loc,
+Sema ) {
+  auto *CXXRD = ElementType->getAsCXXRecordDecl();
+  if (!CXXRD)
+return false;
+
+  CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+  SemaRef.CheckDestructorAccess(Loc, Destructor,
+SemaRef.PDiag(diag::err_access_dtor_temp)
+<< ElementType);
+  SemaRef.MarkFunctionReferenced(Loc, Destructor);
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return true;
+  return false;
+}
+
 void InitListChecker::CheckStructUnionTypes(
 const InitializedEntity , InitListExpr *IList, QualType DeclType,
 CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1838,6 +1862,15 @@
   if (DeclType->isUnionType() && IList->getNumInits() == 0) {
 RecordDecl *RD = DeclType->getAs()->getDecl();
 
+if (!VerifyOnly)
+  for (FieldDecl *FD : RD->fields()) {
+QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
+if 

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 163871.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Point the diagnostic at either the relevant init list element or at the close 
brace.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

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() };
+}
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: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -1818,6 +1818,30 @@
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
+/// Check if the type of a class element has an accessible destructor.
+///
+/// Aggregate initialization requires a class element's destructor be
+/// accessible per 11.6.1 [dcl.init.aggr]:
+///
+/// The destructor for each element of class type is potentially invoked
+/// (15.4 [class.dtor]) from the context where the aggregate initialization
+/// occurs.
+static bool hasAccessibleDestructor(QualType ElementType, SourceLocation Loc,
+Sema ) {
+  auto *CXXRD = ElementType->getAsCXXRecordDecl();
+  if (!CXXRD)
+return false;
+
+  CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+  SemaRef.CheckDestructorAccess(Loc, Destructor,
+SemaRef.PDiag(diag::err_access_dtor_temp)
+<< ElementType);
+  SemaRef.MarkFunctionReferenced(Loc, Destructor);
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return true;
+  return false;
+}
+
 void InitListChecker::CheckStructUnionTypes(
 const InitializedEntity , InitListExpr *IList, QualType DeclType,
 CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1838,6 +1862,15 @@
   if (DeclType->isUnionType() && IList->getNumInits() == 0) {
 RecordDecl *RD = DeclType->getAs()->getDecl();
 
+if (!VerifyOnly)
+  for (FieldDecl *FD : RD->fields()) {
+QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
+if (hasAccessibleDestructor(ET, IList->getEndLoc(), SemaRef)) 

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-09-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: lib/Sema/SemaInit.cpp:1827-1829
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return false;
+  return true;

rsmith wrote:
> Usual Clang convention is to return `true` on error.
I also renamed the function to hasAccessibleDestructor to make it clearer what 
the function does.



Comment at: lib/Sema/SemaInit.cpp:1856
+if (auto *CXXRD = DeclType->getAsCXXRecordDecl()) {
+  SourceLocation Loc = IList->getBeginLoc();
+  for (auto  : Bases)

rsmith wrote:
> It's a minor thing, but I think it'd be preferable to point the diagnostic at 
> the relevant init list element, or at the close brace if the initializer was 
> omitted.
The function that checks the destructor (hasAccessibleDestructor) is called in 
five different places now.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-31 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith accepted this revision.
rsmith added inline comments.
This revision is now accepted and ready to land.



Comment at: lib/Sema/SemaInit.cpp:1827-1829
+  if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
+return false;
+  return true;

Usual Clang convention is to return `true` on error.



Comment at: lib/Sema/SemaInit.cpp:1856
+if (auto *CXXRD = DeclType->getAsCXXRecordDecl()) {
+  SourceLocation Loc = IList->getBeginLoc();
+  for (auto  : Bases)

It's a minor thing, but I think it'd be preferable to point the diagnostic at 
the relevant init list element, or at the close brace if the initializer was 
omitted.



Comment at: lib/Sema/SemaInit.cpp:1875
+
   if (DeclType->isUnionType() && IList->getNumInits() == 0) {
 RecordDecl *RD = DeclType->getAs()->getDecl();

Hmm, I don't think we considered this case when working on the relevant DR. It 
doesn't make much sense to check the destructors of the inactive union members. 
I'll take this back to WG21, but let's go with the wording as-is for now.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-31 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 163612.
ahatanak marked 3 inline comments as done.
ahatanak added a comment.

Move the call that checks the element's destructor into 
InitListChecker::CheckStructUnionTypes.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

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() };
+}
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: 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 ) {
+  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 , 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  : 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 

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-30 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/Sema/SemaInit.cpp:830
+
+  for (FieldDecl *FD : CXXRD->fields())
+if (auto *CXXRDMember = FD->getType()->getAsCXXRecordDecl())

rsmith wrote:
> I think this now checks too much: only those subobjects for which we formed 
> an `InitListExpr` should be checked. Testcase:
> 
> ```
> struct A { friend struct B; private: ~A(); };
> struct B { B(); A a; };
> struct C { B b; };
> C c = { B(); };
> ```
> 
> Here, we must not check that `A`'s destructor is accessible from the context 
> of `C`'s initialization.
> 
> I think the best thing to do is probably to move the call to this function 
> into `InitListChecker::CheckStructUnionTypes`, and make it just check one 
> level.
You also need to check base classes (since C++17, aggregates can have base 
classes).



Comment at: lib/Sema/SemaInit.cpp:830-834
+  for (FieldDecl *FD : CXXRD->fields())
+if (auto *CXXRDMember = FD->getType()->getAsCXXRecordDecl())
+  if (!checkMemberDestructor(CXXRDMember, FD->getType(), Loc, true,
+ SemaRef))
+return false;

I think this now checks too much: only those subobjects for which we formed an 
`InitListExpr` should be checked. Testcase:

```
struct A { friend struct B; private: ~A(); };
struct B { B(); A a; };
struct C { B b; };
C c = { B(); };
```

Here, we must not check that `A`'s destructor is accessible from the context of 
`C`'s initialization.

I think the best thing to do is probably to move the call to this function into 
`InitListChecker::CheckStructUnionTypes`, and make it just check one level.



Comment at: lib/Sema/SemaInit.cpp:831
+  for (FieldDecl *FD : CXXRD->fields())
+if (auto *CXXRDMember = FD->getType()->getAsCXXRecordDecl())
+  if (!checkMemberDestructor(CXXRDMember, FD->getType(), Loc, true,

Do we need a `getBaseElementType()` here? (What if the member is of 
array-of-class type?)


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-08-30 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-25 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 157373.
ahatanak added a comment.

Check if destructors are accessible from InitListChecker's constructor. Add 
test cases for designated initializer and brace elision.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp

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}}
+  }
+}
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: 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 ) {
+  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 , const InitializedEntity ,
  InitListExpr *IL, QualType ,
  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;
   }
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-24 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

Does this check destructors of nested aggregate initializations in the case 
where brace elision occurs? I don't think just checking the top level of the 
SK_ListInitialization is enough. Perhaps it would make more sense to mark the 
dtors used from InitListChecker (in non-VerifyOnly mode).


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-18 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-11 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

ping


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-03 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

LGTM, but I'd like Richard to sign off, too.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-07-02 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 153779.
ahatanak added a comment.
Herald added a subscriber: dexonsmith.

Implement the new rule defined here: http://wg21.link/p0968r0#2227. Produce a 
diagnostic if a class is initialized with aggregate initialization and one of 
its element's destructor is not accessible.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm
  test/SemaCXX/aggregate-initialization.cpp


Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,15 @@
   // 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 { ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+  void test() {
+auto *y = new Y {}; // expected-error {{temporary of type 
'ElementDestructor::X' has private destructor}}
+  }
+}
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: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -7083,6 +7083,28 @@
 
   InitListExpr *StructuredInitList =
   PerformInitList.getFullyStructuredList();
+
+  // The destructor for each element of class type is potentially invoked
+  // (15.4 [class.dtor]) from the context where the aggregate
+  // initialization occurs.
+  if (StructuredInitList)
+if (const auto *RD =
+StructuredInitList->getType()->getAsCXXRecordDecl()) {
+  for (const FieldDecl *FD : RD->fields()) {
+QualType FT = FD->getType();
+if (auto *FRD = FT->getAsCXXRecordDecl()) {
+  CXXDestructorDecl *Destructor = S.LookupDestructor(FRD);
+  S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor,
+  S.PDiag(diag::err_access_dtor_temp)
+  << FT);
+  S.MarkFunctionReferenced(CurInit.get()->getLocStart(),
+   Destructor);
+  if (S.DiagnoseUseOfDecl(Destructor, 
CurInit.get()->getLocStart()))
+return ExprError();
+}
+  }
+}
+
   CurInit.get();
   CurInit = shouldBindAsTemporary(InitEntity)
   ? S.MaybeBindToTemporary(StructuredInitList)


Index: test/SemaCXX/aggregate-initialization.cpp
===
--- test/SemaCXX/aggregate-initialization.cpp
+++ test/SemaCXX/aggregate-initialization.cpp
@@ -186,3 +186,15 @@
   // 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 { ~X(); }; // expected-note {{implicitly declared private here}}
+  struct Y { X x; };
+  void test() {
+auto *y = new Y {}; // expected-error {{temporary of type 'ElementDestructor::X' has private destructor}}
+  }
+}
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 

[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-22 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

In https://reviews.llvm.org/D45898#1104025, @rsmith wrote:

> As it happens, the C++ committee fixed the language wording hole here very 
> recently. The new rule can be found here: http://wg21.link/p0968r0#2227
>  In summary: we should to consider the destructor for all elements of the 
> aggregate to be potentially-invoked.


It doesn't mean that clang should reject the following code, does it?

  // This should compile fine as long as 'Deleted7d d7d' is commented out.
  struct DeletedDtor { ~DeletedDtor() = delete; };
  struct Deleted7d { DeletedDtor a = {}; }; 
  //Deleted7d d7d;

I tried making a helper function out of the code in SK_UserConversion and using 
it in "case SK_ListInitialization". That doesn't seem to work because 
DiagnoseUseOfDecl rejects the code (with error message "error: attempt to use a 
deleted function") above even though the destructor isn't needed (because 'd7d' 
is commented out), so I guess that check should be done in another place.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-17 Thread John McCall via Phabricator via cfe-commits
rjmccall added a comment.

I agree that the new-expression case doesn't use the destructor, and all the 
other cases of list-initialization presumably use the destructor for the 
initialized type for separate reasons.  Ok.




Comment at: test/CodeGenObjCXX/arc-list-init-destruct.mm:1
+// 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
+

ahatanak wrote:
> rjmccall wrote:
> > Does the corresponding C++ test case (replacing `Class0 *f;` with 
> > `HasExplicitNonTrivialDestructor f;`) not reproduce the problem?
> I wasn't able to reproduce the problem by changing the type of field 'f' to a 
> C++ class with a non-trivial destructor because, if I make that change, 
> Class1's destructor declaration gets added in 
> Sema::AddImplicitlyDeclaredMembersToClass. I don't fully understand the 
> reason behind it, but Class1's destructor declaration is added when the type 
> of one of its subobject has a user-declared destructor.
Interesting, alright.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-17 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

As it happens, the C++ committee fixed the language wording hole here very 
recently. The new rule can be found here: http://wg21.link/p0968r0#2227
In summary: we should to consider the destructor for all elements of the 
aggregate to be potentially-invoked.

@rjmccall Were you suggesting that we should also consider the destructor of 
the aggregate itself to be potentially-invoked, or just the elements? In the 
//new-expression// case at least, I don't think the former is permitted.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-05-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added a comment.

Richard and Doug, do you have any thoughts on John's suggestion?




Comment at: test/CodeGenObjCXX/arc-list-init-destruct.mm:1
+// 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
+

rjmccall wrote:
> Does the corresponding C++ test case (replacing `Class0 *f;` with 
> `HasExplicitNonTrivialDestructor f;`) not reproduce the problem?
I wasn't able to reproduce the problem by changing the type of field 'f' to a 
C++ class with a non-trivial destructor because, if I make that change, 
Class1's destructor declaration gets added in 
Sema::AddImplicitlyDeclaredMembersToClass. I don't fully understand the reason 
behind it, but Class1's destructor declaration is added when the type of one of 
its subobject has a user-declared destructor.


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-04-21 Thread John McCall via Phabricator via cfe-commits
rjmccall added a reviewer: doug.gregor.
rjmccall added inline comments.



Comment at: lib/Sema/SemaInit.cpp:7074
+  if (RD->hasDefinition() && RD->hasNonTrivialDestructor())
+S.MarkFunctionReferenced(E->getExprLoc(), S.LookupDestructor(RD));
+

If we're actually using the destructor, we can't just look it up and mark it 
referenced; we have to call CheckDestructorAccess and DiagnoseUseOfDecl.

Walking the syntactic initializers like this seems wrong:
  - I don't know if we actually promise to rewrite these expressions to the 
actual recursive element initialization expression if the expression requires 
conversion.
  - This is going to miss implicitly-initialized elements, which can happen for 
a variety of reasons including (1) running out of explicit initializers and (2) 
designated initializers skipping a field.
  - We'll end up with redundant diagnostics from 
CheckDestructorAccess/DiagnoseUseOfDecl if the expression is an 
already-materialized temporary.
  - We'll end up with unwanted diagnostics from 
CheckDestructorAccess/DiagnoseUseOfDecl if the expression is a gl-value and 
actually part of a reference-initialization, where we don't actually use the 
destructor.

I think the right solution is probably that list-initialization needs to 
recognize that the initialization of a record needs to be treated as a 
potential use of the destructor even if we aren't supposed to bind it as a 
temporary, because once an object is initialized in the local context, there 
are all sorts of reasons why we might need to call its destructor before the 
initialization completes/transitions.  Basically every call to 
shouldBindAsTemporary in this file is suspect, because they're all places where 
we might need to check the destructor use even if we didn't make a temporary.

We seem to get this right in SK_UserConversion where we call 
shouldDestroyEntity, and the comment there is spot-on — it doesn't make sense 
for this code to be specific to SK_UserConversion at all.  My tentative 
suggestion would be to (1) make a helper function that does that exact "if 
should-bind then bind else if should-destroy then destroy" dance and then (2) 
look at all the should-bind checks and try to use your helper function instead. 
 But I'd really like Richard and/or Doug to weigh in.



Comment at: test/CodeGenObjCXX/arc-list-init-destruct.mm:1
+// 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
+

Does the corresponding C++ test case (replacing `Class0 *f;` with 
`HasExplicitNonTrivialDestructor f;`) not reproduce the problem?


Repository:
  rC Clang

https://reviews.llvm.org/D45898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45898: [SemaCXX] Mark destructor as referenced

2018-04-20 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added reviewers: rsmith, rjmccall.

If an initializer in a braced-init-list is a C++ class that has a non-trivial 
destructor, mark the destructor as referenced. This fixes a crash in 
CodeGenFunction::destroyCXXObject that occurs when it tries to emit a call to 
the destructor on the stack unwinding path but the CXXRecordDecl of the class 
doesn't have a CXXDestructorDecl for the destructor.


Repository:
  rC Clang

https://reviews.llvm.org/D45898

Files:
  lib/Sema/SemaInit.cpp
  test/CodeGenObjCXX/arc-list-init-destruct.mm


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: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -7065,6 +7065,14 @@
 *ResultType = Ty;
   }
 
+  for (Expr *E : InitList->inits())
+// If this initializer's type is a C++ class that has a non-trivial
+// destructor, mark the destructor as referenced. The destructor can be
+// invoked during stack unwinding.
+if (auto *RD = E->getType()->getAsCXXRecordDecl())
+  if (RD->hasDefinition() && RD->hasNonTrivialDestructor())
+S.MarkFunctionReferenced(E->getExprLoc(), S.LookupDestructor(RD));
+
   InitListExpr *StructuredInitList =
   PerformInitList.getFullyStructuredList();
   CurInit.get();


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: lib/Sema/SemaInit.cpp
===
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -7065,6 +7065,14 @@
 *ResultType = Ty;
   }
 
+  for (Expr *E : InitList->inits())
+// If this initializer's type is a C++ class that has a non-trivial
+// destructor, mark the destructor as referenced. The destructor can be
+// invoked during stack unwinding.
+if (auto *RD = E->getType()->getAsCXXRecordDecl())
+  if (RD->hasDefinition() && RD->hasNonTrivialDestructor())
+S.MarkFunctionReferenced(E->getExprLoc(), S.LookupDestructor(RD));
+
   InitListExpr *StructuredInitList =
   PerformInitList.getFullyStructuredList();
   CurInit.get();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits