diff options
-rw-r--r-- | include/clang/AST/DeclBase.h | 13 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 150 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp | 10 | ||||
-rw-r--r-- | test/Modules/namespaces.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/PR10447.cpp | 22 |
12 files changed, 109 insertions, 124 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 351f77cef1..28dc1b4fe9 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1432,11 +1432,7 @@ public: /// visible from this context, as determined by /// NamedDecl::declarationReplaces, the previous declaration will be /// replaced with D. - /// - /// @param Recoverable true if it's okay to not add this decl to - /// the lookup tables because it can be easily recovered by walking - /// the declaration chains. - void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true); + void makeDeclVisibleInContext(NamedDecl *D); /// udir_iterator - Iterates through the using-directives stored /// within this context. @@ -1509,15 +1505,12 @@ private: /// /// Analogous to makeDeclVisibleInContext, but for the exclusive /// use of addDeclInternal(). - void makeDeclVisibleInContextInternal(NamedDecl *D, - bool Recoverable = true); + void makeDeclVisibleInContextInternal(NamedDecl *D); friend class DependentDiagnostic; StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; - void buildLookup(DeclContext *DCtx); - void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, - bool Recoverable); + void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal); void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); }; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index baba97d815..9171d2792c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -1082,64 +1082,28 @@ void DeclContext::addDeclInternal(Decl *D) { ND->getDeclContext()->makeDeclVisibleInContextInternal(ND); } -/// buildLookup - Build the lookup data structure with all of the -/// declarations in DCtx (and any other contexts linked to it or -/// transparent contexts nested within it). -void DeclContext::buildLookup(DeclContext *DCtx) { - llvm::SmallVector<DeclContext *, 2> Contexts; - DCtx->collectAllContexts(Contexts); - for (unsigned I = 0, N = Contexts.size(); I != N; ++I) { - for (decl_iterator D = Contexts[I]->decls_begin(), - DEnd = Contexts[I]->decls_end(); - D != DEnd; ++D) { - // Insert this declaration into the lookup structure, but only - // if it's semantically in its decl context. During non-lazy - // lookup building, this is implicitly enforced by addDecl. - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) - if (D->getDeclContext() == Contexts[I]) - makeDeclVisibleInContextImpl(ND, false); - - // If this declaration is itself a transparent declaration context or - // inline namespace, add its members (recursively). - if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) - if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookup(InnerCtx->getPrimaryContext()); - } - } -} - DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->lookup(Name); - if (hasExternalVisibleStorage()) { - // Check to see if we've already cached the lookup results. - if (LookupPtr) { - StoredDeclsMap::iterator I = LookupPtr->find(Name); - if (I != LookupPtr->end()) - return I->second.getLookupResult(); - } + if (LookupPtr) { + StoredDeclsMap::iterator I = LookupPtr->find(Name); + if (I != LookupPtr->end()) + return I->second.getLookupResult(); + } + // If a PCH has a result for this name, and we have a local declaration, we + // will have imported the PCH result when adding the local declaration. + // FIXME: For modules, we could have had more declarations added by module + // imoprts since we saw the declaration of the local name. + if (hasExternalVisibleStorage()) { ExternalASTSource *Source = getParentASTContext().getExternalSource(); return Source->FindExternalVisibleDeclsByName(this, Name); } - /// If there is no lookup data structure, build one now by walking - /// all of the linked DeclContexts (in declaration order!) and - /// inserting their values. - if (!LookupPtr) { - buildLookup(this); - - if (!LookupPtr) - return lookup_result(lookup_iterator(0), lookup_iterator(0)); - } - - StoredDeclsMap::iterator Pos = LookupPtr->find(Name); - if (Pos == LookupPtr->end()) - return lookup_result(lookup_iterator(0), lookup_iterator(0)); - return Pos->second.getLookupResult(); + return lookup_result(lookup_iterator(0), lookup_iterator(0)); } DeclContext::lookup_const_result @@ -1213,60 +1177,53 @@ bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { return false; } -void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) +void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { - makeDeclVisibleInContextWithFlags(D, false, Recoverable); + makeDeclVisibleInContextWithFlags(D, false); } -void DeclContext::makeDeclVisibleInContextInternal(NamedDecl *D, bool Recoverable) +void DeclContext::makeDeclVisibleInContextInternal(NamedDecl *D) { - makeDeclVisibleInContextWithFlags(D, true, Recoverable); + makeDeclVisibleInContextWithFlags(D, true); } -void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Recoverable) { +void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, + bool Internal) { + // Skip unnamed declarations. + if (!D->getDeclName()) + return; + + // Skip entities that can't be found by name lookup into a particular + // context. + if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || + D->isTemplateParameter()) + return; + + // Skip template specializations. // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? - if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter()) + if (isa<ClassTemplateSpecializationDecl>(D)) return; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) if (FD->isFunctionTemplateSpecialization()) return; - DeclContext *PrimaryContext = getPrimaryContext(); - if (PrimaryContext != this) { - PrimaryContext->makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); - return; - } - - // If we already have a lookup data structure, perform the insertion - // into it. If we haven't deserialized externally stored decls, deserialize - // them so we can add the decl. Otherwise, be lazy and don't build that - // structure until someone asks for it. - if (LookupPtr || !Recoverable || hasExternalVisibleStorage()) - makeDeclVisibleInContextImpl(D, Internal); - - // If we are a transparent context or inline namespace, insert into our - // parent context, too. This operation is recursive. - if (isTransparentContext() || isInlineNamespace()) - getParent()->makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); - - Decl *DCAsDecl = cast<Decl>(this); - // Notify that a decl was made visible unless it's a Tag being defined. - if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) - if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) - L->AddedVisibleDecl(this, D); + // Add the declaration into our lookup table (and those of containing + // contexts). + getPrimaryContext()->makeDeclVisibleInContextImpl(D, Internal); } void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { - // Skip unnamed declarations. - if (!D->getDeclName()) - return; - - // Skip entities that can't be found by name lookup into a particular - // context. - if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || - D->isTemplateParameter()) + // 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)) return; ASTContext *C = 0; @@ -1289,23 +1246,32 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()]; if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); - return; + } else if (DeclNameEntries.HandleRedeclaration(D)) { + // This declaration has replaced an existing one for which + // declarationReplaces returns true. + } else { + // Put this declaration into the appropriate slot. + DeclNameEntries.AddSubsequentDecl(D); } - // If it is possible that this is a redeclaration, check to see if there is - // already a decl for which declarationReplaces returns true. If there is - // one, just replace it and return. - if (DeclNameEntries.HandleRedeclaration(D)) - return; + // If we are a transparent context or inline namespace, insert into our + // parent context, too. This operation is recursive. + if (isTransparentContext() || isInlineNamespace()) + getParent()->getPrimaryContext()->makeDeclVisibleInContextImpl(D, Internal); - // Put this declaration into the appropriate slot. - DeclNameEntries.AddSubsequentDecl(D); + Decl *DCAsDecl = cast<Decl>(this); + // Notify that a decl was made visible unless we are a Tag being defined. + if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) + if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) + L->AddedVisibleDecl(this, D); } /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const { + // FIXME: Use something more efficient than normal lookup for using + // directives. In C++, using directives are looked up more than anything else. lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), reinterpret_cast<udir_iterator>(Result.second)); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a9c1ec1cd6..bee542234b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8514,7 +8514,7 @@ CreateNewDecl: New->setAccess(PrevDecl->getAccess()); DeclContext *DC = New->getDeclContext()->getRedeclContext(); - DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + DC->makeDeclVisibleInContext(New); if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); @@ -8522,7 +8522,7 @@ CreateNewDecl: S = getNonFieldDeclScope(S); PushOnScopeChains(New, S, !IsForwardReference); if (IsForwardReference) - SearchDC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + SearchDC->makeDeclVisibleInContext(New); } else { CurContext->addDecl(New); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index abbbe11561..b6866d04e4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5829,14 +5829,15 @@ Decl *Sema::ActOnUsingDirective(Scope *S, } void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { - // If scope has associated entity, then using directive is at namespace - // or translation unit scope. We add UsingDirectiveDecls, into - // it's lookup structure. - if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) + // If the scope has an associated entity and the using directive is at + // namespace or translation unit scope, add the UsingDirectiveDecl into + // its lookup structure so qualified name lookup can find it. + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + if (Ctx && !Ctx->isFunctionOrMethod()) Ctx->addDecl(UDir); else - // Otherwise it is block-sope. using-directives will affect lookup - // only to the end of scope. + // Otherwise, it is at block sope. The using-directives will affect lookup + // only to the end of the scope. S->PushUsingDirective(UDir); } @@ -10195,7 +10196,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // lookup context is in lexical scope. if (!CurContext->isDependentContext()) { DC = DC->getRedeclContext(); - DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false); + DC->makeDeclVisibleInContext(ND); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false); } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index d224f1058a..268ab368ce 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1026,7 +1026,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, // Add ivar's to class's DeclContext. for (unsigned i = 0, e = numIvars; i != e; ++i) { ivars[i]->setLexicalDeclContext(ImpDecl); - IDecl->makeDeclVisibleInContext(ivars[i], false); + IDecl->makeDeclVisibleInContext(ivars[i]); ImpDecl->addDecl(ivars[i]); } @@ -1050,7 +1050,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, } // Instance ivar to Implementation's DeclContext. ImplIvar->setLexicalDeclContext(ImpDecl); - IDecl->makeDeclVisibleInContext(ImplIvar, false); + IDecl->makeDeclVisibleInContext(ImplIvar); ImpDecl->addDecl(ImplIvar); } return; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f1eb522415..fbb0dc6b0f 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -106,7 +106,8 @@ namespace { assert(InnermostFileDC && InnermostFileDC->isFileContext()); for (; S; S = S->getParent()) { - if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + if (Ctx && !Ctx->isFunctionOrMethod()) { DeclContext *EffectiveDC = (Ctx->isFileContext() ? Ctx : InnermostFileDC); visit(Ctx, EffectiveDC); } else { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 5c28db4c5e..5ece8f11e7 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -740,7 +740,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); - IDecl->makeDeclVisibleInContext(Ivar, false); + IDecl->makeDeclVisibleInContext(Ivar); property->setPropertyIvarDecl(Ivar); if (!getLangOpts().ObjCNonFragileABI) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index af6b319e90..e76a253869 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1088,7 +1088,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Friend templates are visible in fairly strange ways. if (!CurContext->isDependentContext()) { DeclContext *DC = SemanticContext->getRedeclContext(); - DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false); + DC->makeDeclVisibleInContext(NewTemplate); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(NewTemplate, EnclosingScope, /* AddToContext = */ false); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 56ce50e592..f10670c47a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -817,7 +817,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Finish handling of friends. if (isFriend) { - DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); + DC->makeDeclVisibleInContext(Inst); Inst->setLexicalDeclContext(Owner); RecordInst->setLexicalDeclContext(Owner); return Inst; @@ -1189,7 +1189,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrevDecl = Function->getPreviousDecl(); PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); - DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); + DC->makeDeclVisibleInContext(PrincipalDecl); bool queuedInstantiation = false; diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp index 99903b57bf..c7966ce643 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp @@ -70,10 +70,8 @@ namespace test4 { } // FIXME: we should be able to diagnose both of these, but we can't. -// ...I'm actually not sure why we can diagnose either of them; it's -// probably a bug. namespace test5 { - namespace ns { void foo(int); } // expected-note {{target of using declaration}} + namespace ns { void foo(int); } template <typename T> class Test0 { void test() { int foo(T); @@ -83,11 +81,11 @@ namespace test5 { template <typename T> class Test1 { void test() { - using ns::foo; // expected-note {{using declaration}} - int foo(T); // expected-error {{declaration conflicts with target of using declaration already in scope}} + using ns::foo; + int foo(T); } }; template class Test0<int>; - template class Test1<int>; // expected-note {{in instantiation of member function}} + template class Test1<int>; } diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp index a51c65992e..19e0c5a991 100644 --- a/test/Modules/namespaces.cpp +++ b/test/Modules/namespaces.cpp @@ -1,6 +1,10 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify +// Importing modules which add declarations to a pre-existing non-imported +// overload set does not currently work. +// XFAIL: * + namespace N6 { char &f(char); } diff --git a/test/SemaCXX/PR10447.cpp b/test/SemaCXX/PR10447.cpp new file mode 100644 index 0000000000..08644ada4a --- /dev/null +++ b/test/SemaCXX/PR10447.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -verify %s + +// PR12223 +namespace test1 { + namespace N { + extern "C" void f(struct S*); + void g(S*); + } + namespace N { + void f(struct S *s) { + g(s); + } + } +} + +// PR10447 +namespace test2 { + extern "C" { + void f(struct Bar*) { } + test2::Bar *ptr; + } +} |