From: Nico Weber Date: Wed, 24 Feb 2016 20:58:14 +0000 (+0000) Subject: Fix rejects-valid caused by r261297. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2f89cf41352f6e87f68f12ff25466970482729e3;p=clang Fix rejects-valid caused by r261297. r261297 called hasUserProvidedDefaultConstructor() to check if defining a const object is ok. This is incorrect for this example: struct X { template 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 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index dde0270ce3..d5cdc09fc4 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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 diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 1ea44fe600..d6b9424fb4 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -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 diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index e84b91388f..65bfc49dae 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index bf60ba9478..5ef31c31bf 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 1d1c99874b..a88ab5fb5f 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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); diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp index f671bd190e..17215fedf0 100644 --- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -74,6 +74,33 @@ struct some_init_container_ctor { struct no_fields_container { no_fields nf; }; +struct param_pack_ctor { + template + param_pack_ctor(T...); + int n; +}; +struct param_pack_ctor_field { + param_pack_ctor ndc; +}; +struct multi_param_pack_ctor { + template + multi_param_pack_ctor(T..., U..., int f = 0); + int n; +}; +struct ignored_template_ctor_and_def { + template ignored_template_ctor_and_def(T* f = nullptr); + ignored_template_ctor_and_def() = default; + int field; +}; +template struct enable_if {}; +template struct enable_if { typedef T type; }; +struct multi_param_pack_and_defaulted { + template ::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 {