]> granicus.if.org Git - clang/commitdiff
Teach Sema::isDeclInScope to handle overload sets constructed from
authorDouglas Gregor <dgregor@apple.com>
Mon, 28 Sep 2009 00:47:05 +0000 (00:47 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 28 Sep 2009 00:47:05 +0000 (00:47 +0000)
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 <iostream>, 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

lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/SemaCXX/using-decl-1.cpp

index a992fb16a25bfb4a18a356160043352e75b4fb0b..be5e551579f01eee48d17592611fc461d326890d 100644 (file)
@@ -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.
index f8751fb9c9b0b955df0300b2fd1b9cb1591602ce..d0463c658ea3fad0643162995ba08325f6bbc832 100644 (file)
@@ -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<OverloadedFunctionDecl>(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<TypedefDecl>(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)
index 2459f251deb2575f0d9321101c0b6ca98667a3e2..37e101e221ea3cc30a7ab5467042e01a7b3d92dc 100644 (file)
@@ -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}}
+}