From: Douglas Gregor Date: Mon, 28 Sep 2009 00:47:05 +0000 (+0000) Subject: Teach Sema::isDeclInScope to handle overload sets constructed from X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2531c2d2f1e8ce35f2ce8e9539738ddf8dccb7cc;p=clang Teach Sema::isDeclInScope to handle overload sets constructed from functions that occur in multiple declaration contexts, e.g., because some were found via using declarations. Now, isDeclInScope will build a new overload set (when needed) containing only those declarations that are actually in scope. This eliminates a problem found with libstdc++'s , where the presence of using In the longer term, I'd like to eliminate Sema::isDeclInScope in favor of better handling of the RedeclarationOnly flag in the name-lookup routines. That way, name lookup only returns the entities that matter, rather than taking the current two-pass approach of producing too many results and then filtering our the wrong results. It's not efficient, and I'm sure that we aren't filtering everywhere we should be. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82954 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a992fb16a2..be5e551579 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -528,7 +528,7 @@ public: void DiagnoseFunctionSpecifiers(Declarator& D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - Decl* PrevDecl, bool &Redeclaration); + NamedDecl* PrevDecl, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, NamedDecl* PrevDecl, @@ -725,9 +725,7 @@ public: /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { - return IdResolver.isDeclInScope(D, Ctx, Context, S); - } + bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0); /// Finds the scope corresponding to the given decl context, if it /// happens to be an enclosing scope. Otherwise return NULL. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f8751fb9c9..d0463c658e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -311,9 +311,10 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { IdentifierResolver::iterator I = IdResolver.begin(TD->getDeclName()), IEnd = IdResolver.end(); - if (I != IEnd && isDeclInScope(*I, CurContext, S)) { + NamedDecl *ID = *I; + if (I != IEnd && isDeclInScope(ID, CurContext, S)) { NamedDecl *PrevDecl = *I; - for (; I != IEnd && isDeclInScope(*I, CurContext, S); + for (; I != IEnd && isDeclInScope(ID, CurContext, S); PrevDecl = *I, ++I) { if (TD->declarationReplaces(*I)) { // This is a redeclaration. Remove it from the chain and @@ -374,6 +375,41 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { IdResolver.AddDecl(D); } +bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { + if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { + // Look inside the overload set to determine if any of the declarations + // are in scope. (Possibly) build a new overload set containing only + // those declarations that are in scope. + OverloadedFunctionDecl *NewOvl = 0; + bool FoundInScope = false; + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + NamedDecl *FD = F->get(); + if (!isDeclInScope(FD, Ctx, S)) { + if (!NewOvl && F != Ovl->function_begin()) { + NewOvl = OverloadedFunctionDecl::Create(Context, + F->get()->getDeclContext(), + F->get()->getDeclName()); + D = NewOvl; + for (OverloadedFunctionDecl::function_iterator + First = Ovl->function_begin(); + First != F; ++First) + NewOvl->addOverload(*First); + } + } else { + FoundInScope = true; + if (NewOvl) + NewOvl->addOverload(*F); + } + } + + return FoundInScope; + } + + return IdResolver.isDeclInScope(D, Ctx, Context, S); +} + void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && @@ -1971,7 +2007,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - Decl* PrevDecl, bool &Redeclaration) { + NamedDecl* PrevDecl, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) @@ -4411,7 +4447,8 @@ CreateNewDecl: if (Lookup.getKind() == LookupResult::Found) PrevTypedef = dyn_cast(Lookup.getAsDecl()); - if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) && + NamedDecl *PrevTypedefNamed = PrevTypedef; + if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != Context.getCanonicalType(Context.getTypeDeclType(New))) { Diag(Loc, diag::err_tag_definition_of_typedef) diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp index 2459f251de..37e101e221 100644 --- a/test/SemaCXX/using-decl-1.cpp +++ b/test/SemaCXX/using-decl-1.cpp @@ -6,3 +6,14 @@ namespace std { using ::f; inline void f() { return f(true); } } + +namespace M { + void f(float); +} + +namespace N { + using M::f; + void f(int) { } // expected-note{{previous}} + + void f(int) { } // expected-error{{redefinition}} +}