On Thu, Feb 18, 2016 at 5:52 PM, Nico Weber via cfe-commits <cfe-commits@lists.llvm.org> wrote: > Author: nico > Date: Thu Feb 18 19:52:46 2016 > New Revision: 261297 > > URL: http://llvm.org/viewvc/llvm-project?rev=261297&view=rev > Log: > Implement the likely resolution of core issue 253. > > C++11 requires const objects to have a user-provided constructor, even for > classes without any fields. DR 253 relaxes this to say "If the implicit > default > constructor initializes all subobjects, no initializer should be required." > > clang is currently the only compiler that implements this C++11 rule, and e.g. > libstdc++ relies on something like DR 253 to compile in newer versions. This > change makes it possible to build code that says `const vector<int> v;' again > when using libstdc++5.2 and _GLIBCXX_DEBUG > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60284). > > Fixes PR23381. > > http://reviews.llvm.org/D16552 > > Modified: > cfe/trunk/include/clang/AST/DeclCXX.h > cfe/trunk/lib/AST/ASTImporter.cpp > cfe/trunk/lib/AST/DeclCXX.cpp > cfe/trunk/lib/Sema/SemaInit.cpp > cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > cfe/trunk/lib/Serialization/ASTWriter.cpp > cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp > cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp > cfe/trunk/test/CXX/drs/dr4xx.cpp > cfe/trunk/test/SemaCXX/attr-selectany.cpp > cfe/trunk/test/SemaCXX/constexpr-value-init.cpp > cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp > cfe/trunk/test/SemaCXX/illegal-member-initialization.cpp > cfe/trunk/www/cxx_dr_status.html > > Modified: cfe/trunk/include/clang/AST/DeclCXX.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/DeclCXX.h (original) > +++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Feb 18 19:52:46 2016 > @@ -378,6 +378,10 @@ class CXXRecordDecl : public RecordDecl > /// even if the class has a trivial default constructor. > bool HasUninitializedReferenceMember : 1; > > + /// \brief True if any non-mutable field whose type doesn't have a user- > + /// provided default ctor also doesn't have an in-class initializer. > + bool HasUninitializedFields : 1; > + > /// \brief These flags are \c true if a defaulted corresponding special > /// member can't be fully analyzed without performing overload > resolution. > /// @{ > @@ -1270,6 +1274,13 @@ public: > return !(data().HasTrivialSpecialMembers & SMF_Destructor); > } > > + /// \brief Determine whether declaring a const variable with this type is > ok > + /// per core issue 253. > + bool allowConstDefaultInit() const { > + return !data().HasUninitializedFields || > + hasUserProvidedDefaultConstructor();
hasUserProvidedDefaultConstructor() here is subtly incorrect. We shouldn't care whether there's a user-provided default constructor, we instead care whether the constructor that would have been chosen for initialization is defaulted (or equivalently, whether there *is* a defaulted default constructor, since if there is one, then either the initialization is ambiguous or it is chosen). This causes a regression for a testcase such as: struct X { template<typename ...T> X(T...); int n; }; const X x; // formerly OK, now bogus error > + } > + > /// \brief Determine whether this class has a destructor which has no > /// semantic effect. > /// > > Modified: cfe/trunk/lib/AST/ASTImporter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ASTImporter.cpp (original) > +++ cfe/trunk/lib/AST/ASTImporter.cpp Thu Feb 18 19:52:46 2016 > @@ -2024,6 +2024,7 @@ bool ASTNodeImporter::ImportDefinition(R > ToData.HasInClassInitializer = FromData.HasInClassInitializer; > ToData.HasUninitializedReferenceMember > = FromData.HasUninitializedReferenceMember; > + ToData.HasUninitializedFields = FromData.HasUninitializedFields; > ToData.NeedOverloadResolutionForMoveConstructor > = FromData.NeedOverloadResolutionForMoveConstructor; > ToData.NeedOverloadResolutionForMoveAssignment > > Modified: cfe/trunk/lib/AST/DeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/DeclCXX.cpp (original) > +++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Feb 18 19:52:46 2016 > @@ -46,34 +46,31 @@ void LazyASTUnresolvedSet::getFromExtern > } > > CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) > - : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), > - Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), > - Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), > - HasPrivateFields(false), HasProtectedFields(false), > HasPublicFields(false), > - HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true), > - HasInClassInitializer(false), HasUninitializedReferenceMember(false), > - NeedOverloadResolutionForMoveConstructor(false), > - NeedOverloadResolutionForMoveAssignment(false), > - NeedOverloadResolutionForDestructor(false), > - DefaultedMoveConstructorIsDeleted(false), > - DefaultedMoveAssignmentIsDeleted(false), > - DefaultedDestructorIsDeleted(false), > - HasTrivialSpecialMembers(SMF_All), > - DeclaredNonTrivialSpecialMembers(0), > - HasIrrelevantDestructor(true), > - HasConstexprNonCopyMoveConstructor(false), > - DefaultedDefaultConstructorIsConstexpr(true), > - HasConstexprDefaultConstructor(false), > - HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), > - UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), > - ImplicitCopyConstructorHasConstParam(true), > - ImplicitCopyAssignmentHasConstParam(true), > - HasDeclaredCopyConstructorWithConstParam(false), > - HasDeclaredCopyAssignmentWithConstParam(false), > - IsLambda(false), IsParsingBaseSpecifiers(false), NumBases(0), > NumVBases(0), > - Bases(), VBases(), > - Definition(D), FirstFriend() { > -} > + : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), > + Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), > + Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), > + HasPrivateFields(false), HasProtectedFields(false), > + HasPublicFields(false), HasMutableFields(false), > HasVariantMembers(false), > + HasOnlyCMembers(true), HasInClassInitializer(false), > + HasUninitializedReferenceMember(false), HasUninitializedFields(false), > + NeedOverloadResolutionForMoveConstructor(false), > + NeedOverloadResolutionForMoveAssignment(false), > + NeedOverloadResolutionForDestructor(false), > + DefaultedMoveConstructorIsDeleted(false), > + DefaultedMoveAssignmentIsDeleted(false), > + DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), > + DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), > + HasConstexprNonCopyMoveConstructor(false), > + DefaultedDefaultConstructorIsConstexpr(true), > + HasConstexprDefaultConstructor(false), > + HasNonLiteralTypeFieldsOrBases(false), > ComputedVisibleConversions(false), > + UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), > + ImplicitCopyConstructorHasConstParam(true), > + ImplicitCopyAssignmentHasConstParam(true), > + HasDeclaredCopyConstructorWithConstParam(false), > + HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false), > + IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(), > + VBases(), Definition(D), FirstFriend() {} > > CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { > return Bases.get(Definition->getASTContext().getExternalSource()); > @@ -332,6 +329,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier > if (BaseClassDecl->hasUninitializedReferenceMember()) > data().HasUninitializedReferenceMember = true; > > + if (!BaseClassDecl->allowConstDefaultInit()) > + data().HasUninitializedFields = true; > + > addedClassSubobject(BaseClassDecl); > } > > @@ -702,6 +702,15 @@ void CXXRecordDecl::addedMember(Decl *D) > data().IsStandardLayout = false; > } > > + if (!Field->hasInClassInitializer() && !Field->isMutable()) { > + if (CXXRecordDecl *FieldType = Field->getType()->getAsCXXRecordDecl()) > { > + if (!FieldType->allowConstDefaultInit()) > + data().HasUninitializedFields = true; > + } else { > + data().HasUninitializedFields = true; > + } > + } > + > // Record if this field is the first non-literal or volatile field or > base. > if (!T->isLiteralType(Context) || T.isVolatileQualified()) > data().HasNonLiteralTypeFieldsOrBases = true; > > Modified: cfe/trunk/lib/Sema/SemaInit.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaInit.cpp (original) > +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Feb 18 19:52:46 2016 > @@ -3515,18 +3515,23 @@ static void TryConstructorInitialization > // If a program calls for the default initialization of an object > // of a const-qualified type T, T shall be a class type with a > // user-provided default constructor. > + // C++ core issue 253 proposal: > + // If the implicit default constructor initializes all subobjects, no > + // initializer should be required. > + // The 253 proposal is for example needed to process libstdc++ headers in > 5.x. > + CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function); > if (Kind.getKind() == InitializationKind::IK_Default && > - Entity.getType().isConstQualified() && > - !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) { > - if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) > - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); > - return; > + Entity.getType().isConstQualified()) { > + if (!CtorDecl->getParent()->allowConstDefaultInit()) { > + if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) > + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); > + return; > + } > } > > // C++11 [over.match.list]p1: > // In copy-list-initialization, if an explicit constructor is chosen, the > // initializer is ill-formed. > - CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function); > if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) { > Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor); > return; > > Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Feb 18 19:52:46 2016 > @@ -1412,6 +1412,7 @@ void ASTDeclReader::ReadCXXDefinitionDat > Data.HasOnlyCMembers = Record[Idx++]; > Data.HasInClassInitializer = Record[Idx++]; > Data.HasUninitializedReferenceMember = Record[Idx++]; > + Data.HasUninitializedFields = Record[Idx++]; > Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++]; > Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++]; > Data.NeedOverloadResolutionForDestructor = Record[Idx++]; > @@ -1536,6 +1537,7 @@ void ASTDeclReader::MergeDefinitionData( > MATCH_FIELD(HasOnlyCMembers) > MATCH_FIELD(HasInClassInitializer) > MATCH_FIELD(HasUninitializedReferenceMember) > + MATCH_FIELD(HasUninitializedFields) > MATCH_FIELD(NeedOverloadResolutionForMoveConstructor) > MATCH_FIELD(NeedOverloadResolutionForMoveAssignment) > MATCH_FIELD(NeedOverloadResolutionForDestructor) > > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Feb 18 19:52:46 2016 > @@ -5547,6 +5547,7 @@ void ASTWriter::AddCXXDefinitionData(con > Record.push_back(Data.HasOnlyCMembers); > Record.push_back(Data.HasInClassInitializer); > Record.push_back(Data.HasUninitializedReferenceMember); > + Record.push_back(Data.HasUninitializedFields); > Record.push_back(Data.NeedOverloadResolutionForMoveConstructor); > Record.push_back(Data.NeedOverloadResolutionForMoveAssignment); > Record.push_back(Data.NeedOverloadResolutionForDestructor); > > Modified: cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp > (original) > +++ cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp Thu > Feb 18 19:52:46 2016 > @@ -116,6 +116,7 @@ static_assert(!noexcept(e5 = e5), ""); > namespace PR13492 { > struct B { > B() = default; > + int field; > }; > > void f() { > > Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp (original) > +++ cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp Thu Feb 18 19:52:46 2016 > @@ -4,9 +4,9 @@ > > // If a program calls for the default initialization of an object of a > // const-qualified type T, T shall be a class type with a > -// user-provided default constructor. > +// user-provided default constructor, except if T has no uninitialized > fields. > struct MakeNonPOD { MakeNonPOD(); }; > -struct NoUserDefault : public MakeNonPOD { }; > +struct NoUserDefault : public MakeNonPOD { int field; }; > struct HasUserDefault { HasUserDefault(); }; > > void test_const_default_init() { > @@ -16,7 +16,7 @@ void test_const_default_init() { > } > > // rdar://8501008 > -struct s0 {}; > +struct s0 { int field; }; > struct s1 { static const s0 foo; }; > const struct s0 s1::foo; // expected-error{{default initialization of an > object of const type 'const struct s0' without a user-provided default > constructor}} > > > Modified: cfe/trunk/test/CXX/drs/dr4xx.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr4xx.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/CXX/drs/dr4xx.cpp (original) > +++ cfe/trunk/test/CXX/drs/dr4xx.cpp Thu Feb 18 19:52:46 2016 > @@ -1197,12 +1197,12 @@ namespace dr496 { // dr496: no > int check6[ __is_trivially_assignable(B, const B&) ? 1 : -1]; > } > > -namespace dr497 { // dr497: yes > +namespace dr497 { // dr497: sup 253 > void before() { > struct S { > mutable int i; > }; > - const S cs; // expected-error {{default initialization}} > + const S cs; > int S::*pm = &S::i; > cs.*pm = 88; // expected-error {{not assignable}} > } > > Modified: cfe/trunk/test/SemaCXX/attr-selectany.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-selectany.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/attr-selectany.cpp (original) > +++ cfe/trunk/test/SemaCXX/attr-selectany.cpp Thu Feb 18 19:52:46 2016 > @@ -39,7 +39,9 @@ __declspec(selectany) auto x8 = Internal > // The D3D11 headers do something like this. MSVC doesn't error on this at > // all, even without the __declspec(selectany), in violation of the standard. > // We fall back to a warning for selectany to accept headers. > -struct SomeStruct {}; > +struct SomeStruct { > + int foo; > +}; > extern const __declspec(selectany) SomeStruct some_struct; // > expected-warning {{default initialization of an object of const type 'const > SomeStruct' without a user-provided default constructor is a Microsoft > extension}} > > // It should be possible to redeclare variables that were defined > > Modified: cfe/trunk/test/SemaCXX/constexpr-value-init.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-value-init.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/constexpr-value-init.cpp (original) > +++ cfe/trunk/test/SemaCXX/constexpr-value-init.cpp Thu Feb 18 19:52:46 2016 > @@ -14,7 +14,7 @@ void f() { > constexpr A a; // expected-error {{constant expression}} expected-note > {{in call to 'A()'}} > } > > -constexpr B b1; // expected-error {{without a user-provided default > constructor}} > +constexpr B b1; // ok > constexpr B b2 = B(); // ok > static_assert(b2.a.a == 1, ""); > static_assert(b2.a.b == 2, ""); > > Modified: cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp (original) > +++ cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp Thu Feb 18 > 19:52:46 2016 > @@ -11,6 +11,7 @@ struct non_const_copy { > non_const_copy& operator = (non_const_copy&) &; > non_const_copy& operator = (non_const_copy&) &&; > non_const_copy() = default; // expected-note {{not viable}} > + int uninit_field; > }; > non_const_copy::non_const_copy(non_const_copy&) = default; // expected-note > {{not viable}} > non_const_copy& non_const_copy::operator = (non_const_copy&) & = default; // > expected-note {{not viable}} > @@ -30,6 +31,65 @@ void fn1 () { > ncc = cncc; // expected-error {{no viable overloaded}} > }; > > +struct no_fields { }; > +struct all_init { > + int a = 0; > + int b = 0; > +}; > +struct some_init { > + int a = 0; > + int b; > + int c = 0; > +}; > +struct some_init_mutable { > + int a = 0; > + mutable int b; > + int c = 0; > +}; > +struct some_init_def { > + some_init_def() = default; > + int a = 0; > + int b; > + int c = 0; > +}; > +struct some_init_ctor { > + some_init_ctor(); > + int a = 0; > + int b; > + int c = 0; > +}; > +struct sub_some_init : public some_init_def { }; > +struct sub_some_init_ctor : public some_init_def { > + sub_some_init_ctor(); > +}; > +struct sub_some_init_ctor2 : public some_init_ctor { > +}; > +struct some_init_container { > + some_init_def sid; > +}; > +struct some_init_container_ctor { > + some_init_container_ctor(); > + some_init_def sid; > +}; > +struct no_fields_container { > + no_fields nf; > +}; > + > +void constobjs() { > + const no_fields nf; // ok > + const all_init ai; // ok > + const some_init si; // expected-error {{default initialization of an > object of const type 'const some_init' without a user-provided default > constructor}} > + const some_init_mutable sim; // ok > + const some_init_def sid; // expected-error {{default initialization of an > object of const type 'const some_init_def' without a user-provided default > constructor}} > + const some_init_ctor sic; // ok > + const sub_some_init ssi; // expected-error {{default initialization of an > object of const type 'const sub_some_init' without a user-provided default > constructor}} > + const sub_some_init_ctor ssic; // ok > + const sub_some_init_ctor2 ssic2; // ok > + 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 > +} > + > struct non_const_derived : non_const_copy { > non_const_derived(const non_const_derived&) = default; // expected-error > {{requires it to be non-const}} > non_const_derived& operator =(non_const_derived&) = default; > > Modified: cfe/trunk/test/SemaCXX/illegal-member-initialization.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/illegal-member-initialization.cpp?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/illegal-member-initialization.cpp (original) > +++ cfe/trunk/test/SemaCXX/illegal-member-initialization.cpp Thu Feb 18 > 19:52:46 2016 > @@ -7,6 +7,7 @@ struct A { > }; > > struct B { > + int field; > }; > > struct X { > > Modified: cfe/trunk/www/cxx_dr_status.html > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=261297&r1=261296&r2=261297&view=diff > ============================================================================== > --- cfe/trunk/www/cxx_dr_status.html (original) > +++ cfe/trunk/www/cxx_dr_status.html Thu Feb 18 19:52:46 2016 > @@ -3023,7 +3023,7 @@ of class templates</td> > <td><a > href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#497">497</a></td> > <td>CD1</td> > <td>Missing required initialization in example</td> > - <td class="full" align="center">Yes</td> > + <td class="none" align="center">Superseded by <a href="#253">253</a></td> > </tr> > <tr class="open" id="498"> > <td><a > href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#498">498</a></td> > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits