]> granicus.if.org Git - clang/commitdiff
Fix rejects-valid caused by r261297.
authorNico Weber <nicolasweber@gmx.de>
Wed, 24 Feb 2016 20:58:14 +0000 (20:58 +0000)
committerNico Weber <nicolasweber@gmx.de>
Wed, 24 Feb 2016 20:58:14 +0000 (20:58 +0000)
r261297 called hasUserProvidedDefaultConstructor() to check if defining a
const object is ok.  This is incorrect for this example:

  struct X { template<typename ...T> X(T...); int n; };
  const X x; // formerly OK, now bogus error

Instead, track if a class has a defaulted default constructor, and disallow
a const object for classes that either have defaulted default constructors or
if they need an implicit constructor.

Bug report and fix approach by Richard Smith, thanks!

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

include/clang/AST/DeclCXX.h
lib/AST/ASTImporter.cpp
lib/AST/DeclCXX.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/SemaCXX/cxx0x-cursory-default-delete.cpp

index dde0270ce3ba1a5f18a60658ecebe07e933e7b9f..d5cdc09fc4aff90e0e8d1ad65d75c134031c2709 100644 (file)
@@ -421,6 +421,10 @@ class CXXRecordDecl : public RecordDecl {
     /// constructor which is neither the copy nor move constructor.
     bool HasConstexprNonCopyMoveConstructor : 1;
 
+    /// \brief True if this class has a (possibly implicit) defaulted default
+    /// constructor.
+    bool HasDefaultedDefaultConstructor : 1;
+
     /// \brief True if a defaulted default constructor for this class would
     /// be constexpr.
     bool DefaultedDefaultConstructorIsConstexpr : 1;
@@ -1278,7 +1282,8 @@ public:
   /// per core issue 253.
   bool allowConstDefaultInit() const {
     return !data().HasUninitializedFields ||
-           hasUserProvidedDefaultConstructor();
+           !(data().HasDefaultedDefaultConstructor ||
+             needsImplicitDefaultConstructor());
   }
 
   /// \brief Determine whether this class has a destructor which has no
index 1ea44fe60062ebb5783ccc4095094d1fa341e1ab..d6b9424fb4da970a6da64751f8fe203d0404c02e 100644 (file)
@@ -2040,6 +2040,8 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
     ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
     ToData.HasConstexprNonCopyMoveConstructor
       = FromData.HasConstexprNonCopyMoveConstructor;
+    ToData.HasDefaultedDefaultConstructor
+      = FromData.HasDefaultedDefaultConstructor;
     ToData.DefaultedDefaultConstructorIsConstexpr
       = FromData.DefaultedDefaultConstructorIsConstexpr;
     ToData.HasConstexprDefaultConstructor
index e84b91388fb780a406d46fc39938e3bda5b8c340..65bfc49daec431fa0f28cc938c61bafeaf72fbba 100644 (file)
@@ -61,6 +61,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
       DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
       DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),
       HasConstexprNonCopyMoveConstructor(false),
+      HasDefaultedDefaultConstructor(false),
       DefaultedDefaultConstructorIsConstexpr(true),
       HasConstexprDefaultConstructor(false),
       HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -497,6 +498,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
         data().UserProvidedDefaultConstructor = true;
       if (Constructor->isConstexpr())
         data().HasConstexprDefaultConstructor = true;
+      if (Constructor->isDefaulted())
+        data().HasDefaultedDefaultConstructor = true;
     }
 
     if (!FunTmpl) {
index bf60ba9478afdaafbb7bbe9fc1aa8e18e6d9cced..5ef31c31bfae4b9de60272ec56de3eaf82ff3570 100644 (file)
@@ -1423,6 +1423,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
   Data.DeclaredNonTrivialSpecialMembers = Record[Idx++];
   Data.HasIrrelevantDestructor = Record[Idx++];
   Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
+  Data.HasDefaultedDefaultConstructor = Record[Idx++];
   Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
   Data.HasConstexprDefaultConstructor = Record[Idx++];
   Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
@@ -1548,6 +1549,7 @@ void ASTDeclReader::MergeDefinitionData(
   OR_FIELD(DeclaredNonTrivialSpecialMembers)
   MATCH_FIELD(HasIrrelevantDestructor)
   OR_FIELD(HasConstexprNonCopyMoveConstructor)
+  OR_FIELD(HasDefaultedDefaultConstructor)
   MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
   OR_FIELD(HasConstexprDefaultConstructor)
   MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
index 1d1c99874b6573878d87b067abfca9cbb50876fc..a88ab5fb5f214a549e6e33def9e23606ad997909 100644 (file)
@@ -5558,6 +5558,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
   Record.push_back(Data.DeclaredNonTrivialSpecialMembers);
   Record.push_back(Data.HasIrrelevantDestructor);
   Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
+  Record.push_back(Data.HasDefaultedDefaultConstructor);
   Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
   Record.push_back(Data.HasConstexprDefaultConstructor);
   Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
index f671bd190ec781c7b7f9733d8c76b9fff5c8c775..17215fedf0abaa6a2a6bf1674e0576dffba82108 100644 (file)
@@ -74,6 +74,33 @@ struct some_init_container_ctor {
 struct no_fields_container {
   no_fields nf;
 };
+struct param_pack_ctor {
+  template <typename... T>
+  param_pack_ctor(T...);
+  int n;
+};
+struct param_pack_ctor_field {
+  param_pack_ctor ndc;
+};
+struct multi_param_pack_ctor {
+  template <typename... T, typename... U>
+  multi_param_pack_ctor(T..., U..., int f = 0);
+  int n;
+};
+struct ignored_template_ctor_and_def {
+  template <class T> ignored_template_ctor_and_def(T* f = nullptr);
+  ignored_template_ctor_and_def() = default;
+  int field;
+};
+template<bool, typename = void> struct enable_if {};
+template<typename T> struct enable_if<true, T> { typedef T type; };
+struct multi_param_pack_and_defaulted {
+  template <typename... T,
+            typename enable_if<sizeof...(T) != 0>::type* = nullptr>
+  multi_param_pack_and_defaulted(T...);
+  multi_param_pack_and_defaulted() = default;
+  int n;
+};
 
 void constobjs() {
   const no_fields nf; // ok
@@ -88,6 +115,12 @@ void constobjs() {
   const some_init_container sicon; // expected-error {{default initialization of an object of const type 'const some_init_container' without a user-provided default constructor}}
   const some_init_container_ctor siconc; // ok
   const no_fields_container nfc; // ok
+  const param_pack_ctor ppc; // ok
+  const param_pack_ctor_field ppcf; // ok
+  const multi_param_pack_ctor mppc; // ok
+  const multi_param_pack_and_defaulted mppad; // expected-error {{default initialization of an object of const type 'const multi_param_pack_and_defaulted' without a user-provided default constructor}}
+  const ignored_template_ctor_and_def itcad; // expected-error {{default initialization of an object of const type 'const ignored_template_ctor_and_def' without a user-provided default constructor}}
+
 }
 
 struct non_const_derived : non_const_copy {