Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -360,6 +360,15 @@ // semantic analysis and code generation. 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, @@ -419,16 +428,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) @@ -3420,6 +3421,18 @@ return CandidateSet.BestViableFunction(S, DeclLoc, Best); } +static bool HasUninitializedFields(CXXRecordDecl* R) { + for (const auto *F : R->fields()) { + if (F->hasInClassInitializer() || F->isUnnamedBitfield()) + continue; + if (CXXRecordDecl *FieldType = F->getType()->getAsCXXRecordDecl()) + if (FieldType->hasDefaultConstructor()) + continue; + 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. @@ -3517,18 +3530,28 @@ // 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 in system headers that + // are in namespace std and that only have fields that have default + // constructors, look the other way. See also core issue 253. + CXXRecordDecl *R = CtorDecl->getParent(); + bool AllowConstDefaultInit = + S.SourceMgr.isInSystemHeader(CtorDecl->getLocation()) && + CtorDecl->isDefaulted() && IsContainedInNamespaceStd(S, R) && + !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/SemaCXX/cxx0x-const-defaulted-ctor-system-header.cpp =================================================================== --- test/SemaCXX/cxx0x-const-defaulted-ctor-system-header.cpp +++ test/SemaCXX/cxx0x-const-defaulted-ctor-system-header.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// expected-no-diagnostics + +// libstdc++5.3 uses `= default` for its container constructors. +#ifdef BE_THE_HEADER +#pragma clang system_header +namespace std { +template +struct vector { + vector() = default; +}; +} +#else + +#define BE_THE_HEADER +#include __FILE__ +const std::vector empty_vector; // no diagnostic +#endif