]> granicus.if.org Git - clang/commitdiff
PR11650: Implement resolution of core issue 1301. Value initialization can't be
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2012 21:14:13 +0000 (21:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2012 21:14:13 +0000 (21:14 +0000)
used to construct an object of union type with a deleted default constructor
(plus fixes for some related value-initialization corner cases).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150502 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaInit.cpp
test/CodeGenCXX/pr11676.cpp
test/SemaCXX/dr1301.cpp [new file with mode: 0644]

index 8376c0d66b42528c8d4059e384cc9753f763cbf9..deedff65025e60cf9e584a710bb22a4ca6bfd73a 100644 (file)
@@ -2699,9 +2699,14 @@ static bool TryListConstructionSpecialCases(Sema &S,
                                             QualType DestType,
                                             InitializationSequence &Sequence) {
   // C++11 [dcl.init.list]p3:
-  //   List-initialization of an object of type T is defined as follows:
-  //   - If the initializer list has no elements and T is a class type with
-  //     a default constructor, the object is value-initialized.
+  //   List-initialization of an object or reference of type T is defined as
+  //   follows:
+  //   - If T is an aggregate, aggregate initialization is performed.
+  if (DestType->isAggregateType())
+    return false;
+
+  //   - Otherwise, if the initializer list has no elements and T is a class
+  //     type with a default constructor, the object is value-initialized.
   if (List->getNumInits() == 0) {
     if (CXXConstructorDecl *DefaultConstructor =
             S.LookupDefaultConstructor(DestRecordDecl)) {
@@ -3549,31 +3554,42 @@ static void TryValueInitialization(Sema &S,
                                    const InitializedEntity &Entity,
                                    const InitializationKind &Kind,
                                    InitializationSequence &Sequence) {
-  // C++ [dcl.init]p5:
+  // C++98 [dcl.init]p5, C++11 [dcl.init]p7:
   //
   //   To value-initialize an object of type T means:
   QualType T = Entity.getType();
 
   //     -- if T is an array type, then each element is value-initialized;
-  while (const ArrayType *AT = S.Context.getAsArrayType(T))
-    T = AT->getElementType();
+  T = S.Context.getBaseElementType(T);
 
   if (const RecordType *RT = T->getAs<RecordType>()) {
     if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+      // C++98:
       // -- if T is a class type (clause 9) with a user-declared
       //    constructor (12.1), then the default constructor for T is
       //    called (and the initialization is ill-formed if T has no
       //    accessible default constructor);
-      //
-      // FIXME: we really want to refer to a single subobject of the array,
-      // but Entity doesn't have a way to capture that (yet).
-      if (ClassDecl->hasUserDeclaredConstructor())
-        return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+      if (!S.getLangOptions().CPlusPlus0x) {
+        if (ClassDecl->hasUserDeclaredConstructor())
+          // FIXME: we really want to refer to a single subobject of the array,
+          // but Entity doesn't have a way to capture that (yet).
+          return TryConstructorInitialization(S, Entity, Kind, 0, 0,
+                                              T, Sequence);
+      } else {
+        // C++11:
+        // -- if T is a class type (clause 9) with either no default constructor
+        //    (12.1 [class.ctor]) or a default constructor that is user-provided
+        //    or deleted, then the object is default-initialized;
+        CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
+        if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
+          return TryConstructorInitialization(S, Entity, Kind, 0, 0,
+                                              T, Sequence);
+      }
 
-      // -- if T is a (possibly cv-qualified) non-union class type
-      //    without a user-provided constructor, then the object is
-      //    zero-initialized and, if T's implicitly-declared default
-      //    constructor is non-trivial, that constructor is called.
+      // -- if T is a (possibly cv-qualified) non-union class type without a
+      //    user-provided or deleted default constructor, then the object is
+      //    zero-initialized and, if T has a non-trivial default constructor,
+      //    default-initialized;
       if ((ClassDecl->getTagKind() == TTK_Class ||
            ClassDecl->getTagKind() == TTK_Struct)) {
         Sequence.AddZeroInitializationStep(Entity.getType());
index 78e7a5fe021c1164bd1239e62e3fc4b39a9dc11e..896751ad6e31b874675725fe9378e4f5195f0056 100644 (file)
@@ -1,8 +1,17 @@
 // RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
 // CHECK that we don't crash.
 
+// PR11676's example is ill-formed:
+/*
 union _XEvent {
 };
 void ProcessEvent() {
   _XEvent pluginEvent = _XEvent();
 }
+*/
+
+// Example from PR11665:
+void f() {
+  union U { int field; } u = U();
+  (void)U().field;
+}
diff --git a/test/SemaCXX/dr1301.cpp b/test/SemaCXX/dr1301.cpp
new file mode 100644 (file)
index 0000000..e3d63be
--- /dev/null
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+struct A { // expected-note 2{{candidate}}
+  A(int); // expected-note {{candidate}}
+  int n;
+};
+int a = A().n; // expected-error {{no matching constructor}}
+
+struct B {
+  B() = delete; // expected-note {{here}}
+  int n;
+};
+int b = B().n; // expected-error {{call to deleted}}
+
+struct C { // expected-note {{here}}
+  B b;
+};
+int c = C().b.n; // expected-error {{call to deleted}}
+
+struct D {
+  D() = default; // expected-note {{here}}
+  B b;
+};
+int d = D().b.n; // expected-error {{call to deleted}}
+
+struct E {
+  E() = default;
+  int n;
+};
+int e = E().n; // ok
+
+struct F {
+  F();
+  int n;
+};
+int f = F().n; // ok
+
+union G { // expected-note {{here}}
+  F f;
+};
+int g = G().f.n; // expected-error {{call to deleted}}
+
+struct H {
+  int n;
+private:
+  H(); // expected-note {{here}}
+};
+int h = H().n; // expected-error {{private constructor}}
+
+struct I { // expected-note {{here}}
+  H h;
+};
+int i = I().h.n; // expected-error {{call to deleted}}
+
+struct J {
+  J();
+  virtual int f();
+  int n;
+};
+int j1 = J().n; // ok
+int j2 = J().f(); // ok
+
+union K { // expected-note 2{{here}}
+  J j;
+  int m;
+};
+int k1 = K().j.n; // expected-error {{call to deleted}}
+int k2 = K().j.f(); // expected-error {{call to deleted}}