diff options
Diffstat (limited to 'lib/AST/DeclBase.cpp')
-rw-r--r-- | lib/AST/DeclBase.cpp | 195 |
1 files changed, 137 insertions, 58 deletions
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 084a432..121c5a6 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const { return false; } +void Decl::markUsed(ASTContext &C) { + if (Used) + return; + + if (C.getASTMutationListener()) + C.getASTMutationListener()->DeclarationMarkedUsed(this); + + Used = true; +} + bool Decl::isReferenced() const { if (Referenced) return true; @@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: + case VarTemplate: return IDNS_Ordinary; case ClassTemplate: @@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: + case VarTemplateSpecialization: + case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: @@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const { return getASTContext().getDeclAttrs(this); } -void Decl::swapAttrs(Decl *RHS) { - bool HasLHSAttr = this->HasAttrs; - bool HasRHSAttr = RHS->HasAttrs; - - // Usually, neither decl has attrs, nothing to do. - if (!HasLHSAttr && !HasRHSAttr) return; - - // If 'this' has no attrs, swap the other way. - if (!HasLHSAttr) - return RHS->swapAttrs(this); - - ASTContext &Context = getASTContext(); - - // Handle the case when both decls have attrs. - if (HasRHSAttr) { - std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); - return; - } - - // Otherwise, LHS has an attr and RHS doesn't. - Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); - Context.eraseDeclAttrs(this); - this->HasAttrs = false; - RHS->HasAttrs = true; -} - Decl *Decl::castFromDeclContext (const DeclContext *D) { Decl::Kind DK = D->getDeclKind(); switch(DK) { @@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const { return false; } +static bool isLinkageSpecContext(const DeclContext *DC, + LinkageSpecDecl::LanguageIDs ID) { + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; + DC = DC->getParent(); + } + return false; +} + +bool DeclContext::isExternCContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); +} + +bool DeclContext::isExternCXXContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); +} + bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() { NeedToReconcileExternalVisibleStorage = false; StoredDeclsMap &Map = *LookupPtr.getPointer(); - ExternalASTSource *Source = getParentASTContext().getExternalSource(); - for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) { - I->second.removeExternalDecls(); - Source->FindExternalVisibleDeclsByName(this, I->first); - } + for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) + I->second.setHasExternalDecls(); } /// \brief Load the declarations within this lexical storage from an @@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, if (!(Map = DC->LookupPtr.getPointer())) Map = DC->CreateStoredDeclsMap(Context); - // Add an entry to the map for this name, if it's not already present. - (*Map)[Name]; + (*Map)[Name].removeExternalDecls(); return DeclContext::lookup_result(); } @@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, Map = DC->CreateStoredDeclsMap(Context); StoredDeclsList &List = (*Map)[Name]; - for (ArrayRef<NamedDecl*>::iterator - I = Decls.begin(), E = Decls.end(); I != E; ++I) { - if (List.isNull()) - List.setOnlyValue(*I); - else - // FIXME: Need declarationReplaces handling for redeclarations in modules. - List.AddSubsequentDecl(*I); + + // Clear out any old external visible declarations, to avoid quadratic + // performance in the redeclaration checks below. + List.removeExternalDecls(); + + if (!List.isNull()) { + // We have both existing declarations and new declarations for this name. + // Some of the declarations may simply replace existing ones. Handle those + // first. + llvm::SmallVector<unsigned, 8> Skip; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) + if (List.HandleRedeclaration(Decls[I])) + Skip.push_back(I); + Skip.push_back(Decls.size()); + + // Add in any new declarations. + unsigned SkipPos = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (I == Skip[SkipPos]) + ++SkipPos; + else + List.AddSubsequentDecl(Decls[I]); + } + } else { + // Convert the array to a StoredDeclsList. + for (ArrayRef<NamedDecl*>::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + if (List.isNull()) + List.setOnlyValue(*I); + else + List.AddSubsequentDecl(*I); + } } return List.getLookupResult(); @@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() { SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl(Contexts[I]); + buildLookupImpl<&DeclContext::decls_begin, + &DeclContext::decls_end>(Contexts[I]); // We no longer have any lazy decls. LookupPtr.setInt(false); @@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() { /// 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) { - for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end(); + for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)(); I != E; ++I) { Decl *D = *I; // 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. + // + // If it's from an AST file, don't add it now. It'll get handled by + // FindExternalVisibleDeclsByName if needed. Exception: if we're not + // in C++, we do not track external visible decls for the TU, so in + // that case we need to collect them all here. if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND)) + if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) && + (!ND->isFromASTFile() || + (isTranslationUnit() && + !getParentASTContext().getLangOpts().CPlusPlus))) makeDeclVisibleInContextImpl(ND, false); // If this declaration is itself a transparent declaration context @@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) { // context (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookupImpl(InnerCtx); + buildLookupImpl<Begin, End>(InnerCtx); } } @@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) { if (!Map) Map = CreateStoredDeclsMap(getParentASTContext()); - // If a PCH/module has a result for this name, and we have a local - // declaration, we will have imported the PCH/module result when adding the - // local declaration or when reconciling the module. + // If we have a lookup result with no external decls, we are done. std::pair<StoredDeclsMap::iterator, bool> R = Map->insert(std::make_pair(Name, StoredDeclsList())); - if (!R.second) + if (!R.second && !R.first->second.hasExternalDecls()) return R.first->second.getLookupResult(); ExternalASTSource *Source = getParentASTContext().getExternalSource(); - if (Source->FindExternalVisibleDeclsByName(this, Name)) { + if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) { if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) @@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) { return I->second.getLookupResult(); } +DeclContext::lookup_result +DeclContext::noload_lookup(DeclarationName Name) { + assert(DeclKind != Decl::LinkageSpec && + "Should not perform lookups into linkage specs!"); + if (!hasExternalVisibleStorage()) + return lookup(Name); + + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) + return PrimaryContext->noload_lookup(Name); + + StoredDeclsMap *Map = LookupPtr.getPointer(); + if (LookupPtr.getInt()) { + // Carefully build the lookup map, without deserializing anything. + 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]); + + // 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(); + } + + if (!Map) + return lookup_result(lookup_iterator(0), lookup_iterator(0)); + + StoredDeclsMap::iterator I = Map->find(Name); + return I != Map->end() + ? I->second.getLookupResult() + : lookup_result(lookup_iterator(0), lookup_iterator(0)); +} + void DeclContext::localUncachedLookup(DeclarationName Name, SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); @@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, assert(this == getPrimaryContext() && "expected a primary DC"); // Skip declarations within functions. - // FIXME: We shouldn't need to build lookup tables for function declarations - // ever, and we can't do so correctly because we can't model the nesting of - // scopes which occurs within functions. We use "qualified" lookup into - // function declarations when handling friend declarations inside nested - // classes, and consequently accept the following invalid code: - // - // void f() { void g(); { int g; struct S { friend void g(); }; } } - if (isFunctionOrMethod() && !isa<FunctionDecl>(D)) + if (isFunctionOrMethod()) return; // Skip declarations which should be invisible to name lookup. @@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Insert this declaration into the map. StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()]; - if (DeclNameEntries.isNull()) { + + if (Internal) { + // If this is being added as part of loading an external declaration, + // this may not be the only external declaration with this name. + // In this case, we never try to replace an existing declaration; we'll + // handle that when we finalize the list of declarations for this name. + DeclNameEntries.setHasExternalDecls(); + DeclNameEntries.AddSubsequentDecl(D); + return; + } + + else if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; } |