]> granicus.if.org Git - clang/commitdiff
PR32044: Fix some cases where we would confuse a transparent init-list expression...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Feb 2017 22:41:47 +0000 (22:41 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Feb 2017 22:41:47 +0000 (22:41 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@296033 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Expr.cpp
lib/Sema/SemaInit.cpp
test/CodeGenCXX/cxx11-initializer-aggregate.cpp
test/CodeGenCXX/reference-init.cpp

index 366e5bf404fc2734ade877e40ebf6a0a159869a7..c22661758c88b0faa5912acbdae381bb6edbe25f 100644 (file)
@@ -1882,6 +1882,11 @@ bool InitListExpr::isTransparent() const {
   if (getNumInits() != 1 || !getInit(0))
     return false;
 
+  // Don't confuse aggregate initialization of a struct X { X &x; }; with a
+  // transparent struct copy.
+  if (!getInit(0)->isRValue() && getType()->isRecordType())
+    return false;
+
   return getType().getCanonicalType() ==
          getInit(0)->getType().getCanonicalType();
 }
index b8fee85516e7e92a7e989759f60cac49a862c582..3970e831c5cd226a2b53e8a2a97b73c2749b77d8 100644 (file)
@@ -623,6 +623,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
   assert((ILE->getType() != SemaRef.Context.VoidTy) &&
          "Should not have void type");
 
+  // A transparent ILE is not performing aggregate initialization and should
+  // not be filled in.
+  if (ILE->isTransparent())
+    return;
+
   if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
     const RecordDecl *RDecl = RType->getDecl();
     if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
index be4fd73e6c21dba772eab446099fa506dfc242a5..8bf35966f5b99e2d9a86b744ffb972f4f6189468 100644 (file)
@@ -2,7 +2,16 @@
 
 struct A { int a, b; int f(); };
 
-// CHECK: define {{.*}}@_Z3fn1i(
+namespace NonAggregateCopyInAggregateInit { // PR32044
+  struct A { constexpr A(int n) : x(n), y() {} int x, y; } extern a;
+  // CHECK-DAG: @_ZN31NonAggregateCopyInAggregateInit1bE = global %{{.*}} { %[[A:.*]]* @_ZN31NonAggregateCopyInAggregateInit1aE }
+  struct B { A &p; } b{{a}};
+  // CHECK-DAG: @_ZGRN31NonAggregateCopyInAggregateInit1cE_ = internal global %[[A]] { i32 1, i32 0 }
+  // CHECK-DAG: @_ZN31NonAggregateCopyInAggregateInit1cE = global %{{.*}} { %{{.*}}* @_ZGRN31NonAggregateCopyInAggregateInit1cE_ }
+  struct C { A &&p; } c{{1}};
+}
+
+// CHECK-LABEL: define {{.*}}@_Z3fn1i(
 int fn1(int x) {
   // CHECK: %[[INITLIST:.*]] = alloca %struct.A
   // CHECK: %[[A:.*]] = getelementptr inbounds %struct.A, %struct.A* %[[INITLIST]], i32 0, i32 0
@@ -15,7 +24,7 @@ int fn1(int x) {
 
 struct B { int &r; int &f() { return r; } };
 
-// CHECK: define {{.*}}@_Z3fn2Ri(
+// CHECK-LABEL: define {{.*}}@_Z3fn2Ri(
 int &fn2(int &v) {
   // CHECK: %[[INITLIST2:.*]] = alloca %struct.B, align 8
   // CHECK: %[[R:.*]] = getelementptr inbounds %struct.B, %struct.B* %[[INITLIST2:.*]], i32 0, i32 0
@@ -24,7 +33,7 @@ int &fn2(int &v) {
   return B{v}.f();
 }
 
-// CHECK: define {{.*}}@__cxx_global_var_init(
+// CHECK-LABEL: define {{.*}}@__cxx_global_var_init(
 //
 // CHECK: call {{.*}}@_ZN14NonTrivialInit1AC1Ev(
 // CHECK: getelementptr inbounds {{.*}}, i64 1
index 3a3eaeee78f6ba6ce53b8690ee2e920fea06d4bc..ba7b282028cf2bdb09be1627ab9b22d318cafc09 100644 (file)
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm-only -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -verify %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++98 | FileCheck %s --check-prefix=CHECK-CXX98
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - -std=c++11 | FileCheck %s --check-prefix=CHECK-CXX11
 // expected-no-diagnostics
 
 struct XPTParamDescriptor {};
@@ -23,3 +25,12 @@ Foo& ignoreSetMutex = *(new Foo);
 // Binding to a bit-field that requires a temporary. 
 struct { int bitfield : 3; } s = { 3 };
 const int &s2 = s.bitfield;
+
+// In C++98, this forms a reference to itself. In C++11 onwards, this performs
+// copy-construction.
+struct SelfReference { SelfReference &r; };
+extern SelfReference self_reference_1;
+SelfReference self_reference_2 = {self_reference_1};
+// CHECK-CXX98: @self_reference_2 = global %[[SELF_REF:.*]] { %[[SELF_REF]]* @self_reference_1 }
+// CHECK-CXX11: @self_reference_2 = global %[[SELF_REF:.*]] zeroinitializer
+// CHECK-CXX11: call {{.*}}memcpy{{.*}} @self_reference_2 {{.*}} @self_reference_1