From bcb70eee1a38a6676ef9f9aa60575df2cec23219 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 2 Jul 2014 23:51:09 +0000 Subject: [PATCH] Enable clang to continue to parse libstdc++4.6 and stlport after r210091. r210091 made initialization checking more strict in c++11 mode. LWG2193 is about changing standard libraries to still be valid under these new rules, but older libstdc++ (e.g. libstdc++4.6 in -D_GLIBCXX_DEBUG=1 mode, or stlport) do not implement that yet. So fall back to the C++03 semantics for container classes in system headers below the std namespace. llvm-svn: 212238 --- .../clang/Basic/DiagnosticSemaKinds.td | 4 ++ clang/lib/Sema/SemaInit.cpp | 55 ++++++++++++++++++- ...lizer-stdinitializerlist-system-header.cpp | 23 ++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ac97e083fa07..418e2cd78dfa 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2128,6 +2128,10 @@ def err_attribute_dllimport_static_field_definition : Error< def warn_attribute_dllimport_static_field_definition : Warning< "definition of dllimport static field">, InGroup>; +def warn_invalid_initializer_from_system_header : Warning< + "invalid constructor form class in system header, should not be explicit">, + InGroup>; +def note_used_in_initialization_here : Note<"used in initialization here">; def err_attribute_dll_member_of_dll_class : Error< "attribute %q0 cannot be applied to member of %q1 class">; def warn_attribute_dll_instantiated_base_class : Warning< diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 606108c127ea..9feb9e060a43 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -353,8 +353,9 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, // If there are fewer initializer-clauses in the list than there are // members in the aggregate, then each member not explicitly initialized // ... - if (SemaRef.getLangOpts().CPlusPlus11 && - Entity.getType()->getBaseElementTypeUnsafe()->isRecordType()) { + bool EmptyInitList = SemaRef.getLangOpts().CPlusPlus11 && + Entity.getType()->getBaseElementTypeUnsafe()->isRecordType(); + if (EmptyInitList) { // C++1y / DR1070: // shall be initialized [...] from an empty initializer list. // @@ -376,6 +377,56 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, } InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit); + // libstdc++4.6 marks the vector default constructor as explicit in + // _GLIBCXX_DEBUG mode, so recover using the C++03 logic in that case. + // stlport does so too. Look for std::__debug for libstdc++, and for + // std:: for stlport. This is effectively a compiler-side implementation of + // LWG2193. + if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() == + InitializationSequence::FK_ExplicitConstructor) { + OverloadCandidateSet::iterator Best; + OverloadingResult O = + InitSeq.getFailedCandidateSet() + .BestViableFunction(SemaRef, Kind.getLocation(), Best); + (void)O; + assert(O == OR_Success && "Inconsistent overload resolution"); + CXXConstructorDecl *CtorDecl = cast(Best->Function); + CXXRecordDecl *R = CtorDecl->getParent(); + + 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->getLexicalParent())) { + if (SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND)) + IsInStd = true; + } + + if (IsInStd && llvm::StringSwitch(R->getName()) + .Cases("basic_string", "deque", "forward_list", true) + .Cases("list", "map", "multimap", "multiset", true) + .Cases("priority_queue", "queue", "set", "stack", true) + .Cases("unordered_map", "unordered_set", "vector", true) + .Default(false)) { + InitSeq.InitializeFrom( + SemaRef, Entity, + InitializationKind::CreateValue(Loc, Loc, Loc, true), + MultiExprArg(), /*TopLevelOfInitList=*/false); + // Emit a warning for this. System header warnings aren't shown + // by default, but people working on system headers should see it. + if (!VerifyOnly) { + SemaRef.Diag(CtorDecl->getLocation(), + diag::warn_invalid_initializer_from_system_header); + SemaRef.Diag(Entity.getDecl()->getLocation(), + diag::note_used_in_initialization_here); + } + } + } + } if (!InitSeq) { if (!VerifyOnly) { InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit); diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp new file mode 100644 index 000000000000..774745777c17 --- /dev/null +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wsystem-headers %s + +// libstdc++4.6 in debug mode has explicit default constructors. +// stlport has this for all containers. +#ifdef BE_THE_HEADER +#pragma clang system_header +namespace std { +namespace __debug { +template +class vector { +public: + explicit vector() {} // expected-warning{{should not be explicit}} +}; +} +} +#else + +#define BE_THE_HEADER +#include __FILE__ + +struct { int a, b; std::__debug::vector c; } e[] = { {1, 1} }; // expected-note{{used in initialization here}} + +#endif