diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/DeclBase.h | 45 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 23 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 99 | ||||
-rw-r--r-- | clang/lib/Sema/IdentifierResolver.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 77 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 48 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/update-exception-spec/a.h | 2 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/update-exception-spec/b.h | 3 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/update-exception-spec/c.h | 3 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/update-exception-spec/module.modulemap | 3 | ||||
-rw-r--r-- | clang/test/Modules/cxx-templates.cpp | 10 | ||||
-rw-r--r-- | clang/test/Modules/linkage-merge.cpp | 5 | ||||
-rw-r--r-- | clang/test/Modules/odr.cpp | 8 | ||||
-rw-r--r-- | clang/test/Modules/redecl-add-after-load.cpp | 4 | ||||
-rw-r--r-- | clang/test/Modules/update-exception-spec.cpp | 6 |
19 files changed, 257 insertions, 169 deletions
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 121bd005353..7088e4a8d15 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1096,14 +1096,21 @@ class DeclContext { /// another lookup. mutable bool NeedToReconcileExternalVisibleStorage : 1; + /// \brief If \c true, this context may have local lexical declarations + /// that are missing from the lookup table. + mutable bool HasLazyLocalLexicalLookups : 1; + + /// \brief If \c true, the external source may have lexical declarations + /// that are missing from the lookup table. + mutable bool HasLazyExternalLexicalLookups : 1; + /// \brief Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a - /// dependent context), and a bool indicating whether we have lazily - /// omitted any declarations from the map. We maintain the invariant - /// that, if the map contains an entry for a DeclarationName (and we - /// haven't lazily omitted anything), then it contains all relevant - /// entries for that name. - mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr; + /// dependent context). We maintain the invariant that, if the map + /// contains an entry for a DeclarationName (and we haven't lazily + /// omitted anything), then it contains all relevant entries for that + /// name (modulo the hasExternalDecls() flag). + mutable StoredDeclsMap *LookupPtr; protected: /// FirstDecl - The first declaration stored within this declaration @@ -1129,8 +1136,9 @@ protected: DeclContext(Decl::Kind K) : DeclKind(K), ExternalLexicalStorage(false), ExternalVisibleStorage(false), - NeedToReconcileExternalVisibleStorage(false), LookupPtr(nullptr, false), - FirstDecl(nullptr), LastDecl(nullptr) {} + NeedToReconcileExternalVisibleStorage(false), + HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false), + LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {} public: ~DeclContext(); @@ -1656,17 +1664,22 @@ public: inline ddiag_range ddiags() const; // Low-level accessors - - /// \brief Mark the lookup table as needing to be built. This should be - /// used only if setHasExternalLexicalStorage() has been called on any - /// decl context for which this is the primary context. + + /// \brief Mark that there are external lexical declarations that we need + /// to include in our lookup table (and that are not available as external + /// visible lookups). These extra lookup results will be found by walking + /// the lexical declarations of this context. This should be used only if + /// setHasExternalLexicalStorage() has been called on any decl context for + /// which this is the primary context. void setMustBuildLookupTable() { - LookupPtr.setInt(true); + assert(this == getPrimaryContext() && + "should only be called on primary context"); + HasLazyExternalLexicalLookups = true; } /// \brief Retrieve the internal representation of the lookup structure. /// This may omit some names if we are lazily building the structure. - StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); } + StoredDeclsMap *getLookupPtr() const { return LookupPtr; } /// \brief Ensure the lookup structure is fully-built and return it. StoredDeclsMap *buildLookup(); @@ -1689,7 +1702,7 @@ public: /// declarations visible in this context. void setHasExternalVisibleStorage(bool ES = true) { ExternalVisibleStorage = ES; - if (ES && LookupPtr.getPointer()) + if (ES && LookupPtr) NeedToReconcileExternalVisibleStorage = true; } @@ -1722,8 +1735,6 @@ private: friend class DependentDiagnostic; StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; - template<decl_iterator (DeclContext::*Begin)() const, - decl_iterator (DeclContext::*End)() const> void buildLookupImpl(DeclContext *DCtx, bool Internal); void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Rediscoverable); diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 55fe0ef5971..c6310595190 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -446,6 +446,12 @@ private: /// that we needed but hadn't loaded yet. llvm::DenseMap<void *, PendingFakeDefinitionKind> PendingFakeDefinitionData; + /// \brief Exception specification updates that have been loaded but not yet + /// propagated across the relevant redeclaration chain. The map key is the + /// canonical declaration (used only for deduplication) and the value is a + /// declaration that has an exception specification. + llvm::SmallMapVector<Decl *, FunctionDecl *, 4> PendingExceptionSpecUpdates; + struct ReplacedDeclInfo { ModuleFile *Mod; uint64_t Offset; @@ -948,6 +954,11 @@ private: llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> > PendingIdentifierInfos; + /// \brief The set of lookup results that we have faked in order to support + /// merging of partially deserialized decls but that we have not yet removed. + llvm::SmallMapVector<IdentifierInfo *, SmallVector<NamedDecl*, 2>, 16> + PendingFakeLookupResults; + /// \brief The generation number of each identifier, which keeps track of /// the last time we loaded information about this identifier. llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration; @@ -1174,6 +1185,18 @@ private: /// merged into its redecl chain. Decl *getMostRecentExistingDecl(Decl *D); + template <typename Fn> + void forEachFormerlyCanonicalImportedDecl(const Decl *D, Fn Visit) { + D = D->getCanonicalDecl(); + if (D->isFromASTFile()) + Visit(D); + + auto It = MergedDecls.find(const_cast<Decl*>(D)); + if (It != MergedDecls.end()) + for (auto ID : It->second) + Visit(GetExistingDecl(ID)); + } + RecordLocation DeclCursorForID(serialization::DeclID ID, unsigned &RawLocation); void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 89e1d52c643..57621a7b1f6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -7946,7 +7946,7 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, while (LexicalContext && !isa<FunctionDecl>(LexicalContext)) LexicalContext = LexicalContext->getLexicalParent(); - // Let the static local variable inherit it's linkage from the nearest + // Let the static local variable inherit its linkage from the nearest // enclosing function. if (LexicalContext) StaticLocalLinkage = diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index a8e151cc937..1f08a64d3ab 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1011,10 +1011,10 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls, /// built a lookup map. For every name in the map, pull in the new names from /// the external storage. void DeclContext::reconcileExternalVisibleStorage() const { - assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer()); + assert(NeedToReconcileExternalVisibleStorage && LookupPtr); NeedToReconcileExternalVisibleStorage = false; - for (auto &Lookup : *LookupPtr.getPointer()) + for (auto &Lookup : *LookupPtr) Lookup.second.setHasExternalDecls(); } @@ -1027,10 +1027,13 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { // Notify that we have a DeclContext that is initializing. ExternalASTSource::Deserializing ADeclContext(Source); - + + ExternalLexicalStorage = false; + bool HadLazyExternalLexicalLookups = HasLazyExternalLexicalLookups; + HasLazyExternalLexicalLookups = false; + // Load the external declarations, if any. SmallVector<Decl*, 64> Decls; - ExternalLexicalStorage = false; switch (Source->FindExternalLexicalDecls(this, Decls)) { case ELR_Success: break; @@ -1043,6 +1046,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { if (Decls.empty()) return; + if (HadLazyExternalLexicalLookups) + HasLazyLocalLexicalLookups = true; + // We may have already loaded just the fields of this record, in which case // we need to ignore them. bool FieldsAlreadyLoaded = false; @@ -1065,7 +1071,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; - if (!(Map = DC->LookupPtr.getPointer())) + if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); @@ -1081,7 +1087,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, ArrayRef<NamedDecl*> Decls) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; - if (!(Map = DC->LookupPtr.getPointer())) + if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); @@ -1175,7 +1181,7 @@ void DeclContext::removeDecl(Decl *D) { // Remove only decls that have a name if (!ND->getDeclName()) return; - StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer(); + StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; if (!Map) return; StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); @@ -1263,32 +1269,28 @@ static bool shouldBeHidden(NamedDecl *D) { StoredDeclsMap *DeclContext::buildLookup() { assert(this == getPrimaryContext() && "buildLookup called on non-primary DC"); - // FIXME: Should we keep going if hasExternalVisibleStorage? - if (!LookupPtr.getInt()) - return LookupPtr.getPointer(); + if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) + return LookupPtr; + + if (HasLazyExternalLexicalLookups) + LoadLexicalDeclsFromExternalStorage(); SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl<&DeclContext::decls_begin, - &DeclContext::decls_end>(Contexts[I], false); + buildLookupImpl(Contexts[I], hasExternalVisibleStorage()); // We no longer have any lazy decls. - LookupPtr.setInt(false); - return LookupPtr.getPointer(); + HasLazyLocalLexicalLookups = false; + return LookupPtr; } /// buildLookupImpl - Build part of the lookup data structure for the /// declarations contained within DCtx, which will either be this /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. -template<DeclContext::decl_iterator (DeclContext::*Begin)() const, - DeclContext::decl_iterator (DeclContext::*End)() const> void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { - for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)(); - I != E; ++I) { - Decl *D = *I; - + for (Decl *D : DCtx->noload_decls()) { // Insert this declaration into the lookup structure, but only if // it's semantically within its decl context. Any other decls which // should be found in this context are added eagerly. @@ -1309,7 +1311,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { // context (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookupImpl<Begin, End>(InnerCtx, Internal); + buildLookupImpl(InnerCtx, Internal); } } @@ -1337,9 +1339,9 @@ DeclContext::lookup(DeclarationName Name) const { if (NeedToReconcileExternalVisibleStorage) reconcileExternalVisibleStorage(); - StoredDeclsMap *Map = LookupPtr.getPointer(); + StoredDeclsMap *Map = LookupPtr; - if (LookupPtr.getInt()) + if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) // FIXME: Make buildLookup const? Map = const_cast<DeclContext*>(this)->buildLookup(); @@ -1353,7 +1355,7 @@ DeclContext::lookup(DeclarationName Name) const { return R.first->second.getLookupResult(); if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) { - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) return I->second.getLookupResult(); @@ -1363,8 +1365,8 @@ DeclContext::lookup(DeclarationName Name) const { return lookup_result(); } - StoredDeclsMap *Map = LookupPtr.getPointer(); - if (LookupPtr.getInt()) + StoredDeclsMap *Map = LookupPtr; + if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) Map = const_cast<DeclContext*>(this)->buildLookup(); if (!Map) @@ -1388,26 +1390,18 @@ DeclContext::noload_lookup(DeclarationName Name) { if (PrimaryContext != this) return PrimaryContext->noload_lookup(Name); - StoredDeclsMap *Map = LookupPtr.getPointer(); - if (LookupPtr.getInt()) { - // Carefully build the lookup map, without deserializing anything. + // If we have any lazy lexical declarations not in our lookup map, add them + // now. Don't import any external declarations, not even if we know we have + // some missing from the external visible lookups. + if (HasLazyLocalLexicalLookups) { SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl<&DeclContext::noload_decls_begin, - &DeclContext::noload_decls_end>(Contexts[I], true); - - // We no longer have any lazy decls. - LookupPtr.setInt(false); - - // There may now be names for which we have local decls but are - // missing the external decls. FIXME: Just set the hasExternalDecls - // flag on those names that have external decls. - NeedToReconcileExternalVisibleStorage = true; - - Map = LookupPtr.getPointer(); + buildLookupImpl(Contexts[I], hasExternalVisibleStorage()); + HasLazyLocalLexicalLookups = false; } + StoredDeclsMap *Map = LookupPtr; if (!Map) return lookup_result(); @@ -1429,8 +1423,9 @@ void DeclContext::localUncachedLookup(DeclarationName Name, } // If we have a lookup table, check there first. Maybe we'll get lucky. - if (Name && !LookupPtr.getInt()) { - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + // FIXME: Should we be checking these flags on the primary context? + if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) { + if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator Pos = Map->find(Name); if (Pos != Map->end()) { Results.insert(Results.end(), @@ -1443,6 +1438,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name, // Slow case: grovel through the declarations in our chain looking for // matches. + // FIXME: If we have lazy external declarations, this will not find them! + // FIXME: Should we CollectAllContexts and walk them all here? for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (ND->getDeclName() == Name) @@ -1523,7 +1520,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, // FIXME: As a performance hack, don't add such decls into the translation // unit unless we're in C++, since qualified lookup into the TU is never // performed. - if (LookupPtr.getPointer() || hasExternalVisibleStorage() || + if (LookupPtr || hasExternalVisibleStorage() || ((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) && (getParentASTContext().getLangOpts().CPlusPlus || !isTranslationUnit()))) { @@ -1533,7 +1530,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, buildLookup(); makeDeclVisibleInContextImpl(D, Internal); } else { - LookupPtr.setInt(true); + HasLazyLocalLexicalLookups = true; } // If we are a transparent context or inline namespace, insert into our @@ -1551,7 +1548,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Find or create the stored declaration map. - StoredDeclsMap *Map = LookupPtr.getPointer(); + StoredDeclsMap *Map = LookupPtr; if (!Map) { ASTContext *C = &getParentASTContext(); Map = CreateStoredDeclsMap(*C); @@ -1613,7 +1610,7 @@ DeclContext::udir_range DeclContext::using_directives() const { //===----------------------------------------------------------------------===// StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { - assert(!LookupPtr.getPointer() && "context already has a decls map"); + assert(!LookupPtr && "context already has a decls map"); assert(getPrimaryContext() == this && "creating decls map on non-primary context"); @@ -1625,7 +1622,7 @@ StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { M = new StoredDeclsMap(); M->Previous = C.LastSDM; C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent); - LookupPtr.setPointer(M); + LookupPtr = M; return M; } @@ -1657,11 +1654,11 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, assert(Parent->isDependentContext() && "cannot iterate dependent diagnostics of non-dependent context"); Parent = Parent->getPrimaryContext(); - if (!Parent->LookupPtr.getPointer()) + if (!Parent->LookupPtr) Parent->CreateStoredDeclsMap(C); - DependentStoredDeclsMap *Map - = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer()); + DependentStoredDeclsMap *Map = + static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr); // Allocate the copy of the PartialDiagnostic via the ASTContext's // BumpPtrAllocator, rather than the ASTContext itself. diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index a6efe96573a..53263bac546 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -98,7 +98,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) const { Ctx = Ctx->getRedeclContext(); - if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) { + if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) { // Ignore the scopes associated within transparent declaration contexts. while (S->getEntity() && S->getEntity()->isTransparentContext()) S = S->getParent(); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 41abd49627b..51d6acebada 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -167,13 +167,13 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { void Sema::UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI) { - for (auto *Redecl : FD->redecls()) - Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); - // If we've fully resolved the exception specification, notify listeners. if (!isUnresolvedExceptionSpec(ESI.Type)) if (auto *Listener = getASTMutationListener()) Listener->ResolvedExceptionSpec(FD); + + for (auto *Redecl : FD->redecls()) + Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); } /// Determine whether a function has an implicitly-generated exception diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e15e532be19..0b406184058 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3021,17 +3021,45 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (Visited.visitedContext(Ctx->getPrimaryContext())) return; + // Outside C++, lookup results for the TU live on identifiers. + if (isa<TranslationUnitDecl>(Ctx) && + !Result.getSema().getLangOpts().CPlusPlus) { + auto &S = Result.getSema(); + auto &Idents = S.Context.Idents; + + // Ensure all external identifiers are in the identifier table. + if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { + std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); + for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) + Idents.get(Name); + } + + // Walk all lookup results in the TU for each identifier. + for (const auto &Ident : Idents) { + for (auto I = S.IdResolver.begin(Ident.getValue()), + E = S.IdResolver.end(); + I != E; ++I) { + if (S.IdResolver.isDeclInScope(*I, Ctx)) { + if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); + } + } + } + } + + return; + } + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. for (const auto &R : Ctx->lookups()) { - for (auto *I : R) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) { - if ((ND = Result.getAcceptableDecl(ND))) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } + for (auto *D : R) { + if (auto *ND = Result.getAcceptableDecl(D)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); } } } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f4b4c4b9879..a26f251cbdb 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1,4 +1,4 @@ -//===--- ASTReader.cpp - AST File Reader ----------------------------------===// +//===-- ASTReader.cpp - AST File Reader ----------------------------------===// // // The LLVM Compiler Infrastructure // @@ -2835,6 +2835,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case EAGERLY_DESERIALIZED_DECLS: + // FIXME: Skip reading this record if our ASTConsumer doesn't care + // about "interesting" decls (for instance, if we're building a module). for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; @@ -6832,6 +6834,12 @@ void ASTReader::PassInterestingDeclsToConsumer() { SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer, true); + // Ensure that we've loaded all potentially-interesting declarations + // that need to be eagerly loaded. + for (auto ID : EagerlyDeserializedDecls) + GetDecl(ID); + EagerlyDeserializedDecls.clear(); + while (!InterestingDecls.empty()) { Decl *D = InterestingDecls.front(); InterestingDecls.pop_front(); @@ -6850,17 +6858,8 @@ void ASTReader::PassInterestingDeclToConsumer(Decl *D) { void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { this->Consumer = Consumer; - if (!Consumer) - return; - - for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) { - // Force deserialization of this decl, which will cause it to be queued for - // passing to the consumer. - GetDecl(EagerlyDeserializedDecls[I]); - } - EagerlyDeserializedDecls.clear(); - - PassInterestingDeclsToConsumer(); + if (Consumer) + PassInterestingDeclsToConsumer(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); @@ -8618,6 +8617,13 @@ void ASTReader::FinishedDeserializing() { --NumCurrentElementsDeserializing; if (NumCurrentElementsDeserializing == 0) { + // Propagate exception specification updates along redeclaration chains. + for (auto Update : PendingExceptionSpecUpdates) { + auto *FPT = Update.second->getType()->castAs<FunctionProtoType>(); + SemaObj->UpdateExceptionSpec(Update.second, + FPT->getExtProtoInfo().ExceptionSpec); + } + diagnoseOdrViolations(); // We are not in recursive loading, so it's safe to pass the "interesting" @@ -8628,7 +8634,15 @@ void ASTReader::FinishedDeserializing() { } void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { - D = D->getMostRecentDecl(); + if (IdentifierInfo *II = Name.getAsIdentifierInfo()) { + // Remove any fake results before adding any real ones. + auto It = PendingFakeLookupResults.find(II); + if (It != PendingFakeLookupResults.end()) { + for (auto *ND : PendingFakeLookupResults[II]) + SemaObj->IdResolver.RemoveDecl(ND); + PendingFakeLookupResults.erase(It); + } + } if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { SemaObj->TUScope->AddDecl(D); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 83882a83693..5c6820f4834 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -228,9 +228,11 @@ namespace clang { template <typename DeclT> static void attachPreviousDeclImpl(ASTReader &Reader, - Redeclarable<DeclT> *D, Decl *Previous); + Redeclarable<DeclT> *D, Decl *Previous, + Decl *Canon); static void attachPreviousDeclImpl(ASTReader &Reader, ...); - static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous); + static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous, + Decl *Canon); template <typename DeclT> static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest); @@ -2621,8 +2623,11 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() { if (needsAnonymousDeclarationNumber(New)) { setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(), AnonymousDeclNumber, New); - } else if (DC->isTranslationUnit() && Reader.SemaObj) { - Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name); + } else if (DC->isTranslationUnit() && Reader.SemaObj && + !Reader.getContext().getLangOpts().CPlusPlus) { + if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name)) + Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()] + .push_back(New); } else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) { // Add the declaration to its redeclaration context so later merging // lookups will find it. @@ -2727,7 +2732,8 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { if (isSameEntity(Existing, D)) return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber, TypedefNameForLinkage); - } else if (DC->isTranslationUnit() && Reader.SemaObj) { + } else if (DC->isTranslationUnit() && Reader.SemaObj && + !Reader.getContext().getLangOpts().CPlusPlus) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; // Temporarily consider the identifier to be up-to-date. We don't want to @@ -2816,14 +2822,14 @@ Decl *ASTReader::getMostRecentExistingDecl(Decl *D) { template<typename DeclT> void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, Redeclarable<DeclT> *D, - Decl *Previous) { + Decl *Previous, Decl *Canon) { D->RedeclLink.setPrevious(cast<DeclT>(Previous)); } namespace clang { template<> void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, Redeclarable<FunctionDecl> *D, - Decl *Previous) { + Decl *Previous, Decl *Canon) { FunctionDecl *FD = static_cast<FunctionDecl*>(D); FunctionDecl *PrevFD = cast<FunctionDecl>(Previous); @@ -2850,25 +2856,17 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, FD->IsInline = true; } - // If this declaration has an unresolved exception specification but the - // previous declaration had a resolved one, resolve the exception - // specification now. If this declaration has a resolved exception - // specification but the previous declarations did not, apply our exception - // specification to all prior ones now. + // If we need to propagate an exception specification along the redecl + // chain, make a note of that so that we can do so later. auto *FPT = FD->getType()->getAs<FunctionProtoType>(); auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>(); if (FPT && PrevFPT) { - bool WasUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType()); - bool IsUnresolved = isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType()); - if (WasUnresolved && !IsUnresolved) { - Reader.Context.adjustExceptionSpec( - FD, PrevFPT->getExtProtoInfo().ExceptionSpec); - } else if (!WasUnresolved && IsUnresolved) { - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - for (FunctionDecl *PrevFDToUpdate = PrevFD; PrevFDToUpdate; - PrevFDToUpdate = PrevFDToUpdate->getPreviousDecl()) - Reader.Context.adjustExceptionSpec(PrevFDToUpdate, EPI.ExceptionSpec); - } + bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType()); + bool WasUnresolved = + isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType()); + if (IsUnresolved != WasUnresolved) + Reader.PendingExceptionSpecUpdates.insert( + std::make_pair(Canon, IsUnresolved ? PrevFD : FD)); } } } @@ -2877,14 +2875,14 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) { } void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D, - Decl *Previous) { + Decl *Previous, Decl *Canon) { assert(D && Previous); switch (D->getKind()) { #define ABSTRACT_DECL(TYPE) -#define DECL(TYPE, BASE) \ - case Decl::TYPE: \ - attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous); \ +#define DECL(TYPE, BASE) \ + case Decl::TYPE: \ + attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous, Canon); \ break; #include "clang/AST/DeclNodes.inc" } @@ -3388,7 +3386,7 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) { if (Chain[I] == CanonDecl) continue; - ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent); + ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl); MostRecent = Chain[I]; } ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent); @@ -3732,23 +3730,24 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, } case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { - // FIXME: This doesn't send the right notifications if there are - // ASTMutationListeners other than an ASTWriter. FunctionProtoType::ExceptionSpecInfo ESI; SmallVector<QualType, 8> ExceptionStorage; Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx); - for (auto *Redecl : merged_redecls(D)) { - auto *FD = cast<FunctionDecl>(Redecl); - auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { - // AST invariant: if any exception spec in the redecl chain is - // resolved, all are resolved. We don't need to go any further. - // FIXME: If the exception spec is resolved, check that it matches. - break; - } + + // Update this declaration's exception specification, if needed. + auto *FD = cast<FunctionDecl>(D); + auto *FPT = FD->getType()->castAs<FunctionProtoType>(); + // FIXME: If the exception specification is already present, check that it + // matches. + if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { FD->setType(Reader.Context.getFunctionType( FPT->getReturnType(), FPT->getParamTypes(), FPT->getExtProtoInfo().withExceptionSpec(ESI))); + + // When we get to the end of deserializing, see if there are other decls + // that we need to propagate this exception specification onto. + Reader.PendingExceptionSpecUpdates.insert( + std::make_pair(FD->getCanonicalDecl(), FD)); } break; } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a8e92b8151c..e992685a83d 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3731,7 +3731,9 @@ void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) { uint32_t ASTWriter::GenerateNameLookupTable(const DeclContext *DC, llvm::SmallVectorImpl<char> &LookupTable) { - assert(!DC->LookupPtr.getInt() && "must call buildLookups first"); + assert(!DC->HasLazyLocalLexicalLookups && + !DC->HasLazyExternalLexicalLookups && + "must call buildLookups first"); llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator; @@ -5804,37 +5806,36 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, } void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { - assert(!WritingAST && "Already writing the AST!"); - FD = FD->getCanonicalDecl(); - if (!FD->isFromASTFile()) - return; // Not a function declared in PCH and defined outside. - - DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC); + assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); + if (!Chain) return; + Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + // If we don't already know the exception specification for this redecl + // chain, add an update record for it. + if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D) + ->getType() + ->castAs<FunctionProtoType>() + ->getExceptionSpecType())) + DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC); + }); } void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { assert(!WritingAST && "Already writing the AST!"); - FD = FD->getCanonicalDecl(); - if (!FD->isFromASTFile()) - return; // Not a function declared in PCH and defined outside. - - DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); + if (!Chain) return; + Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) { + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); + }); } void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, const FunctionDecl *Delete) { assert(!WritingAST && "Already writing the AST!"); assert(Delete && "Not given an operator delete"); - for (auto *D : DD->redecls()) { - if (D->isFromASTFile()) { - // We added an operator delete that some imported destructor didn't - // know about. Add an update record to let importers of us and that - // declaration know about it. - DeclUpdates[DD].push_back( - DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); - return; - } - } + if (!Chain) return; + Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) { + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); + }); } void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { @@ -5851,8 +5852,7 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (!D->isFromASTFile()) return; - DeclUpdates[D].push_back( - DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); + DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { diff --git a/clang/test/Modules/Inputs/update-exception-spec/a.h b/clang/test/Modules/Inputs/update-exception-spec/a.h new file mode 100644 index 00000000000..078ebf9aecf --- /dev/null +++ b/clang/test/Modules/Inputs/update-exception-spec/a.h @@ -0,0 +1,2 @@ +struct A { ~A() throw(int); }; +struct B { A a; }; diff --git a/clang/test/Modules/Inputs/update-exception-spec/b.h b/clang/test/Modules/Inputs/update-exception-spec/b.h new file mode 100644 index 00000000000..f75b559bee4 --- /dev/null +++ b/clang/test/Modules/Inputs/update-exception-spec/b.h @@ -0,0 +1,3 @@ +struct A { ~A() throw(int); }; +struct B { A a; }; +inline void f(B *p) { p->~B(); } diff --git a/clang/test/Modules/Inputs/update-exception-spec/c.h b/clang/test/Modules/Inputs/update-exception-spec/c.h new file mode 100644 index 00000000000..067dbb65055 --- /dev/null +++ b/clang/test/Modules/Inputs/update-exception-spec/c.h @@ -0,0 +1,3 @@ +#include "a.h" +#include "b.h" +inline void g(B *p) { p->~B(); } diff --git a/clang/test/Modules/Inputs/update-exception-spec/module.modulemap b/clang/test/Modules/Inputs/update-exception-spec/module.modulemap new file mode 100644 index 00000000000..880ae38b97a --- /dev/null +++ b/clang/test/Modules/Inputs/update-exception-spec/module.modulemap @@ -0,0 +1,3 @@ +module a { header "a.h" } +module b { header "b.h" } +module c { header "c.h" } diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index 46c2f33ef15..41b0f2cd92d 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N -// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP +// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP // RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 // RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT @@ -125,9 +125,10 @@ void g() { static_assert(Outer<int>::Inner<int>::f() == 1, ""); static_assert(Outer<int>::Inner<int>::g() == 2, ""); -#ifndef EARLY_IMPORT -// FIXME: The textual inclusion above shouldn't cause this to fail! -static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); +// FIXME: We're too lazy in merging class definitions to find the definition +// of this function. +static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); // expected-error {{constant expression}} expected-note {{undefined}} +// expected-note@cxx-templates-c.h:10 {{here}} static_assert(MergeTemplateDefinitions<int>::g() == 2, ""); RedeclaredAsFriend<int> raf1; @@ -140,7 +141,6 @@ MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1; MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2; MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2; MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2; -#endif MergeAnonUnionMember<> maum_main; typedef DontWalkPreviousDeclAfterMerging<int> dwpdam_typedef_2; diff --git a/clang/test/Modules/linkage-merge.cpp b/clang/test/Modules/linkage-merge.cpp index 99917897fcc..3ac8053761b 100644 --- a/clang/test/Modules/linkage-merge.cpp +++ b/clang/test/Modules/linkage-merge.cpp @@ -11,6 +11,5 @@ static void g(int); // happen to find lookup results for 'g'; LookupResult::resolveKind needs to // be taught to prefer a visible result over a non-visible one. // -// FIXME-error@-1 {{functions that differ only in their return type cannot be overloaded}} -// FIXME-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}} -// expected-no-diagnostics +// expected-error@9 {{functions that differ only in their return type cannot be overloaded}} +// expected-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}} diff --git a/clang/test/Modules/odr.cpp b/clang/test/Modules/odr.cpp index 120ca20e0a8..4ac257cd03a 100644 --- a/clang/test/Modules/odr.cpp +++ b/clang/test/Modules/odr.cpp @@ -15,9 +15,9 @@ bool b = F<int>{0} == F<int>{1}; int x = f() + g(); // expected-note@a.h:5 {{definition has no member 'e2'}} -// expected-note@a.h:3 {{declaration of 'f' does not match}} -// expected-note@a.h:1 {{definition has no member 'm'}} +// expected-note@b.h:3 {{declaration of 'f' does not match}} +// expected-note@b.h:1 {{definition has no member 'n'}} // expected-error@b.h:5 {{'E::e2' from module 'b' is not present in definition of 'E' in module 'a'}} -// expected-error@b.h:3 {{'Y::f' from module 'b' is not present in definition of 'Y' in module 'a'}} -// expected-error@b.h:2 {{'Y::m' from module 'b' is not present in definition of 'Y' in module 'a'}} +// expected-error@a.h:3 {{'Y::f' from module 'a' is not present in definition of 'Y' in module 'b'}} +// expected-error@a.h:2 {{'Y::n' from module 'a' is not present in definition of 'Y' in module 'b'}} diff --git a/clang/test/Modules/redecl-add-after-load.cpp b/clang/test/Modules/redecl-add-after-load.cpp index 68deaf8b4ef..53e54c84cc3 100644 --- a/clang/test/Modules/redecl-add-after-load.cpp +++ b/clang/test/Modules/redecl-add-after-load.cpp @@ -29,7 +29,7 @@ struct D { static constexpr int function(); // expected-note {{here}} }; typedef D::A DB; -constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{subexpression}} expected-note {{undefined}} +constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{undefined}} #endif @import redecl_add_after_load; @@ -54,6 +54,6 @@ constexpr int merged_struct_variable_test = D_test(true); constexpr int merged_struct_function_test = D_test(false); #ifndef IMPORT_DECLS // expected-error@-4 {{incomplete}} -// expected-error@-4 {{constant}} expected-note@-4 {{in call to}} +// @-4: definition of D::variable must be emitted, so it gets imported eagerly // expected-error@-4 {{constant}} expected-note@-4 {{in call to}} #endif diff --git a/clang/test/Modules/update-exception-spec.cpp b/clang/test/Modules/update-exception-spec.cpp new file mode 100644 index 00000000000..bccdddc9c09 --- /dev/null +++ b/clang/test/Modules/update-exception-spec.cpp @@ -0,0 +1,6 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fmodules -fmodules-cache-path=%t -I%S/Inputs/update-exception-spec -emit-llvm-only %s +#include "a.h" +void use(B *p); +#include "c.h" +void use(B *p) { g(p); } |