Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -363,6 +363,15 @@ InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } }; +bool IsContainedInNamespaceStd(Sema& S, CXXRecordDecl *R) { + for (NamespaceDecl *ND = dyn_cast(R->getDeclContext()); ND; + ND = dyn_cast(ND->getParent())) { + if (S.getStdNamespace()->InEnclosingNamespaceSetOf(ND)) + return true; + } + return false; +} + } // end anonymous namespace ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, @@ -422,14 +431,8 @@ if (CtorDecl->getMinRequiredArguments() == 0 && CtorDecl->isExplicit() && R->getDeclName() && SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) { - bool IsInStd = false; - for (NamespaceDecl *ND = dyn_cast(R->getDeclContext()); - ND && !IsInStd; ND = dyn_cast(ND->getParent())) { - if (SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND)) - IsInStd = true; - } - - if (IsInStd && llvm::StringSwitch(R->getName()) + if (IsContainedInNamespaceStd(SemaRef, R) && + llvm::StringSwitch(R->getName()) .Cases("basic_string", "deque", "forward_list", true) .Cases("list", "map", "multimap", "multiset", true) .Cases("priority_queue", "queue", "set", "stack", true) @@ -3418,6 +3421,36 @@ return CandidateSet.BestViableFunction(S, DeclLoc, Best); } +static bool HasUninitializedFields(const CXXRecordDecl* R) { + for (const auto *F : R->fields()) { + if (F->hasInClassInitializer() || F->isUnnamedBitfield()) + continue; + if (CXXRecordDecl *FieldType = F->getType()->getAsCXXRecordDecl()) { + if (FieldType->hasUserProvidedDefaultConstructor()) + continue; + if (HasUninitializedFields(FieldType)) { + return true; + } else { + // Has class type but class has no user-provided default ctor. Only + // a problem if that class has uninitialized fields. + if (!HasUninitializedFields(FieldType)) + continue; + } + } + // field has no intializer + return true; + } + for (const auto& BI : R->bases()) { + const RecordType *RT = BI.getType()->getAs(); + CXXRecordDecl *Base = cast(RT->getDecl()); + if (!Base->hasUserProvidedDefaultConstructor() && + HasUninitializedFields(Base)) { + return true; + } + } + return false; +} + /// \brief Attempt initialization by constructor (C++ [dcl.init]), which /// enumerates the constructors of the initialized entity and performs overload /// resolution to select the best. @@ -3515,18 +3548,24 @@ // 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. + CXXConstructorDecl *CtorDecl = cast(Best->Function); if (Kind.getKind() == InitializationKind::IK_Default && - Entity.getType().isConstQualified() && - !cast(Best->Function)->isUserProvided()) { - if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); - return; + Entity.getType().isConstQualified() && !CtorDecl->isUserProvided()) { + // Some libstdc++ types use `MyType() = default;` which technically isn't + // a user-provided default constructor. For types that don't have + // uninitialized fields, suppress the error. See also core issue 253. + CXXRecordDecl *R = CtorDecl->getParent(); + bool AllowConstDefaultInit = !HasUninitializedFields(R); + if (!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(Best->Function); if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) { Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor); return; Index: test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp =================================================================== --- test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp +++ test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp @@ -116,6 +116,7 @@ namespace PR13492 { struct B { B() = default; + int field; }; void f() { Index: test/CXX/dcl.decl/dcl.init/p6.cpp =================================================================== --- test/CXX/dcl.decl/dcl.init/p6.cpp +++ test/CXX/dcl.decl/dcl.init/p6.cpp @@ -4,8 +4,8 @@ // 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. -struct MakeNonPOD { MakeNonPOD(); }; +// user-provided default constructor, except if T has no uninitialized fields. +struct MakeNonPOD { MakeNonPOD(); int field; }; struct NoUserDefault : public MakeNonPOD { }; struct HasUserDefault { HasUserDefault(); }; @@ -16,7 +16,7 @@ } // 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}} Index: test/SemaCXX/attr-selectany.cpp =================================================================== --- test/SemaCXX/attr-selectany.cpp +++ test/SemaCXX/attr-selectany.cpp @@ -39,7 +39,9 @@ // 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 Index: test/SemaCXX/constexpr-value-init.cpp =================================================================== --- test/SemaCXX/constexpr-value-init.cpp +++ test/SemaCXX/constexpr-value-init.cpp @@ -14,7 +14,7 @@ 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, ""); Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp =================================================================== --- test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -11,6 +11,7 @@ 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,59 @@ 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_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_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; Index: test/SemaCXX/illegal-member-initialization.cpp =================================================================== --- test/SemaCXX/illegal-member-initialization.cpp +++ test/SemaCXX/illegal-member-initialization.cpp @@ -7,6 +7,7 @@ }; struct B { + int field; }; struct X {