r288565 - [Sema] Don't perform aggregate initialization for types with explicit constructors

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 2 17:26:48 PST 2016


Author: ericwf
Date: Fri Dec  2 19:26:47 2016
New Revision: 288565

URL: http://llvm.org/viewvc/llvm-project?rev=288565&view=rev
Log:
[Sema] Don't perform aggregate initialization for types with explicit constructors

Summary:
The C++17 rules for aggregate initialization changed to disallow types with explicit constructors [dcl.init.aggr]p1. This patch implements that new rule.


Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D25654

Modified:
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/p7.cpp
    cfe/trunk/test/CXX/drs/dr15xx.cpp

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=288565&r1=288564&r2=288565&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Dec  2 19:26:47 2016
@@ -533,6 +533,17 @@ void CXXRecordDecl::addedMember(Decl *D)
       } else if (Constructor->isMoveConstructor())
         SMKind |= SMF_MoveConstructor;
     }
+
+    // C++ [dcl.init.aggr]p1:
+    //   An aggregate is an array or a class with no user-declared
+    //   constructors [...].
+    // C++11 [dcl.init.aggr]p1: DR1518
+    //  An aggregate is an array or a class with no user-provided, explicit, or
+    //  inherited constructors
+    if (getASTContext().getLangOpts().CPlusPlus11
+            ? (Constructor->isUserProvided() || Constructor->isExplicit())
+            : !Constructor->isImplicit())
+      data().Aggregate = false;
   }
 
   // Handle constructors, including those inherited from base classes.
@@ -546,20 +557,6 @@ void CXXRecordDecl::addedMember(Decl *D)
     //   constructor [...]
     if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
       data().HasConstexprNonCopyMoveConstructor = true;
-
-    // C++ [dcl.init.aggr]p1:
-    //   An aggregate is an array or a class with no user-declared
-    //   constructors [...].
-    // C++11 [dcl.init.aggr]p1:
-    //   An aggregate is an array or a class with no user-provided
-    //   constructors [...].
-    // C++11 [dcl.init.aggr]p1:
-    //   An aggregate is an array or a class with no user-provided
-    //   constructors (including those inherited from a base class) [...].
-    if (getASTContext().getLangOpts().CPlusPlus11
-            ? Constructor->isUserProvided()
-            : !Constructor->isImplicit())
-      data().Aggregate = false;
   }
 
   // Handle destructors.
@@ -989,8 +986,12 @@ void CXXRecordDecl::addedMember(Decl *D)
 
   if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) {
     if (Using->getDeclName().getNameKind() ==
-        DeclarationName::CXXConstructorName)
+        DeclarationName::CXXConstructorName) {
       data().HasInheritedConstructor = true;
+      // C++1z [dcl.init.aggr]p1:
+      //  An aggregate is [...] a class [...] with no inherited constructors
+      data().Aggregate = false;
+    }
 
     if (Using->getDeclName().getCXXOverloadedOperator() == OO_Equal)
       data().HasInheritedAssignment = true;

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp?rev=288565&r1=288564&r2=288565&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp Fri Dec  2 19:26:47 2016
@@ -122,3 +122,39 @@ struct DefaultedAggr {
   ~DefaultedAggr() = default;
 };
 DefaultedAggr da = { 42 } ;
+
+struct ExplicitDefaultedAggr {
+  int n;
+  explicit ExplicitDefaultedAggr() = default; // expected-note {{candidate}}
+  ExplicitDefaultedAggr(const ExplicitDefaultedAggr &) = default; // expected-note {{candidate}}
+  ExplicitDefaultedAggr(ExplicitDefaultedAggr &&) = default; // expected-note {{candidate}}
+};
+ExplicitDefaultedAggr eda = { 42 }; // expected-error {{no matching constructor}}
+ExplicitDefaultedAggr eda2{};
+
+struct DefaultedBase {
+  int n;
+  DefaultedBase() = default; // expected-note 0+ {{candidate}}
+  DefaultedBase(DefaultedBase const&) = default; // expected-note 0+ {{candidate}}
+  DefaultedBase(DefaultedBase &&) = default; // expected-note 0+ {{candidate}}
+};
+
+struct InheritingConstructors : DefaultedBase { // expected-note 3 {{candidate}}
+  using DefaultedBase::DefaultedBase; // expected-note 2 {{inherited here}}
+};
+InheritingConstructors ic = { 42 }; // expected-error {{no matching constructor}}
+
+struct NonInheritingConstructors : DefaultedBase {}; // expected-note 0+ {{candidate}}
+NonInheritingConstructors nic = { 42 };
+#if __cplusplus <= 201402L
+// expected-error at -2 {{no matching constructor}}
+#endif
+
+struct NonAggrBase {
+  NonAggrBase(int) {}
+};
+struct HasNonAggrBase : NonAggrBase {}; // expected-note 0+ {{candidate}}
+HasNonAggrBase hnab = {42};
+#if __cplusplus <= 201402L
+// expected-error at -2 {{no matching constructor}}
+#endif

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/p7.cpp?rev=288565&r1=288564&r2=288565&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/p7.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/p7.cpp Fri Dec  2 19:26:47 2016
@@ -12,3 +12,5 @@ struct B : NotAggregateBase {
   explicit B() = default; // expected-note {{here}}
 };
 B b = {}; // expected-error {{chosen constructor is explicit}}
+B b2{};
+B b3;

Modified: cfe/trunk/test/CXX/drs/dr15xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr15xx.cpp?rev=288565&r1=288564&r2=288565&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr15xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr15xx.cpp Fri Dec  2 19:26:47 2016
@@ -135,6 +135,53 @@ namespace dr1512 { // dr1512: 4.0
   }
 }
 
+namespace dr1518 { // dr1518: 4.0
+#if __cplusplus >= 201103L
+struct Z0 { // expected-note 0+ {{candidate}}
+  explicit Z0() = default; // expected-note 0+ {{here}}
+};
+struct Z { // expected-note 0+ {{candidate}}
+  explicit Z(); // expected-note 0+ {{here}}
+  explicit Z(int);
+  explicit Z(int, int); // expected-note 0+ {{here}}
+};
+template <class T> int Eat(T); // expected-note 0+ {{candidate}}
+Z0 a;
+Z0 b{};
+Z0 c = {}; // expected-error {{explicit in copy-initialization}}
+int i = Eat<Z0>({}); // expected-error {{no matching function for call to 'Eat'}}
+
+Z c2 = {}; // expected-error {{explicit in copy-initialization}}
+int i2 = Eat<Z>({}); // expected-error {{no matching function for call to 'Eat'}}
+Z a1 = 1; // expected-error {{no viable conversion}}
+Z a3 = Z(1);
+Z a2(1);
+Z *p = new Z(1);
+Z a4 = (Z)1;
+Z a5 = static_cast<Z>(1);
+Z a6 = {4, 3}; // expected-error {{explicit in copy-initialization}}
+
+struct UserProvidedBaseCtor { // expected-note 0+ {{candidate}}
+  UserProvidedBaseCtor() {}
+};
+struct DoesntInheritCtor : UserProvidedBaseCtor { // expected-note 0+ {{candidate}}
+  int x;
+};
+DoesntInheritCtor I{{}, 42};
+#if __cplusplus <= 201402L
+// expected-error at -2 {{no matching constructor}}
+#endif
+
+struct BaseCtor { BaseCtor() = default; }; // expected-note 0+ {{candidate}}
+struct InheritsCtor : BaseCtor { // expected-note 1+ {{candidate}}
+  using BaseCtor::BaseCtor;      // expected-note 2 {{inherited here}}
+  int x;
+};
+InheritsCtor II = {{}, 42}; // expected-error {{no matching constructor}}
+
+#endif                      // __cplusplus >= 201103L
+}
+
 namespace dr1550 { // dr1550: yes
   int f(bool b, int n) {
     return (b ? (throw 0) : n) + (b ? n : (throw 0));




More information about the cfe-commits mailing list