]> granicus.if.org Git - clang/commitdiff
Don't push OverloadedFunctionDecls onto the chain of declarations
authorDouglas Gregor <dgregor@apple.com>
Tue, 23 Dec 2008 21:05:05 +0000 (21:05 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 23 Dec 2008 21:05:05 +0000 (21:05 +0000)
attached to an identifier. Instead, all overloaded functions will be
pushed into scope, and we'll synthesize an OverloadedFunctionDecl on
the fly when we need it.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61386 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/AST/DeclBase.cpp
lib/Sema/IdentifierResolver.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp

index aaae0921929b4d73c5c368b80928459fc2d8c191..8ff8aefaaff93e9b0365c3ae267007f4e79c71a0 100644 (file)
@@ -200,6 +200,15 @@ public:
       return true;
   }
 
+  /// declarationReplaces - Determine whether this declaration, if
+  /// known to be well-formed within its context, will replace the
+  /// declaration OldD if introduced into scope. A declaration will
+  /// replace another declaration if, for example, it is a
+  /// redeclaration of the same variable or function, but not if it is
+  /// a declaration of a different kind (function vs. class) or an
+  /// overloaded function.
+  bool declarationReplaces(NamedDecl *OldD) const;
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
     return D->getKind() >= ScopedFirst && D->getKind() <= ScopedLast;
index 3edf8a02efb77001512aa1028747adb0705316ad..bfe0272038f5c0598be14206ed66a08c005733a6 100644 (file)
@@ -174,6 +174,19 @@ ScopedDecl::~ScopedDecl() {
     delete getMultipleDC();
 }
 
+bool ScopedDecl::declarationReplaces(NamedDecl *OldD) const {
+  assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
+
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
+    // For function declarations, we keep track of redeclarations.
+    return FD->getPreviousDeclaration() == OldD;
+
+  // For non-function declarations, if the declarations are of the
+  // same kind then this must be a redeclaration, or semantic analysis
+  // would not have given us the new declaration.
+  return this->getKind() == OldD->getKind();
+}
+
 //===----------------------------------------------------------------------===//
 // VarDecl Implementation
 //===----------------------------------------------------------------------===//
index 87ebf85b41d3079bb398acb83b3ea9558a07c9ce..c6b3c53cc42b2b99bc013d728728daad1c1110e4 100644 (file)
@@ -17,6 +17,8 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
+#include <algorithm>
+#include <functional>
 #include <vector>
 using namespace clang;
 
@@ -543,19 +545,6 @@ void DeclContext::insert(ASTContext &Context, ScopedDecl *D) {
     insertImpl(D);
 }
 
-static bool isRedeclarationOf(ScopedDecl *D, ScopedDecl *OldD) {
-  assert(D->getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
-
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
-    // For function declarations, we keep track of redeclarations.
-    return FD->getPreviousDeclaration() == OldD;
-
-  // For non-function declarations, if the declarations are of the
-  // same kind then this must be a redeclaration, or semantic analysis
-  // would not have given us the new declaration.
-  return D->getKind() == OldD->getKind();
-}
-
 void DeclContext::insertImpl(ScopedDecl *D) {
   bool MayBeRedeclaration = true;
 
@@ -591,7 +580,7 @@ void DeclContext::insertImpl(ScopedDecl *D) {
         if (Array[LastMatch]->getDeclName() != D->getDeclName())
           break;
 
-        if (isRedeclarationOf(D, Array[LastMatch])) {
+        if (D->declarationReplaces(Array[LastMatch])) {
           // D is a redeclaration of an existing element in the
           // array. Replace that element with D.
           Array[LastMatch] = D;
@@ -640,15 +629,13 @@ void DeclContext::insertImpl(ScopedDecl *D) {
   if (Pos != Map->end()) {
     if (MayBeRedeclaration) {
       // Determine if this declaration is actually a redeclaration.
-      for (std::vector<ScopedDecl *>::iterator I = Pos->second.begin(),
-                                            IEnd = Pos->second.end();
-           I != IEnd; ++I) {
-        if (isRedeclarationOf(D, *I)) {
-          // D is a redeclaration of *I. Replace *I with D and we're
-          // done.
-          *I = D;
-          return;
-        }
+      std::vector<ScopedDecl *>::iterator Redecl
+        = std::find_if(Pos->second.begin(), Pos->second.end(),
+                     std::bind1st(std::mem_fun(&ScopedDecl::declarationReplaces),
+                                  D));
+      if (Redecl != Pos->second.end()) {
+        *Redecl = D;
+        return;
       }
     }
 
index bc9da6126d0fd5d09fd97b82a443c55c612d89d5..30846dcd1744963fcf026e85e3f7f893a99325bf 100644 (file)
@@ -128,6 +128,13 @@ public:
   /// It will walk or not the parent declaration contexts depending on how
   /// it was instantiated.
   class iterator {
+  public:
+    typedef NamedDecl *             value_type;
+    typedef NamedDecl *             reference;
+    typedef NamedDecl *             pointer;
+    typedef std::input_iterator_tag iterator_category;
+    typedef std::ptrdiff_t          difference_type;
+
     /// Ptr - There are 3 forms that 'Ptr' represents:
     /// 1) A single NamedDecl. (Ptr & 0x1 == 0)
     /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the
index 270de5546bcad6aa76c7e1ac3ba67c05ca2228f9..d84d6adad0120bb1dc3c5c9487a8dac3b8be7d16 100644 (file)
@@ -26,6 +26,8 @@
 #include "clang/Lex/HeaderSearch.h" 
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/STLExtras.h"
+#include <algorithm>
+#include <functional>
 
 using namespace clang;
 
@@ -93,6 +95,12 @@ void Sema::PopDeclContext() {
 void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
   S->AddDecl(D);
 
+  // Add scoped declarations into their context, so that they can be
+  // found later. Declarations without a context won't be inserted
+  // into any context.
+  if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D))
+    CurContext->addDecl(Context, SD);
+
   // C++ [basic.scope]p4:
   //   -- exactly one declaration shall declare a class name or
   //   enumeration name that is not a typedef name and the other
@@ -105,74 +113,56 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
       // We're pushing the tag into the current context, which might
       // require some reshuffling in the identifier resolver.
       IdentifierResolver::iterator
-        I = IdResolver.begin(TD->getIdentifier(), CurContext, 
-                             false/*LookInParentCtx*/);
-      if (I != IdResolver.end()) {
-       // There is already a declaration with the same name in the same
-       // scope. It must be found before we find the new declaration,
-       // so swap the order on the shadowed declaration chain.
-       IdResolver.AddShadowedDecl(TD, *I);
-
-       // Add this declaration to the current context.
-       CurContext->addDecl(Context, TD);
-       
-       return;
+        I = IdResolver.begin(TD->getDeclName(), CurContext, 
+                             false/*LookInParentCtx*/),
+        IEnd = IdResolver.end();
+      if (I != IEnd && isDeclInScope(*I, CurContext, S)) {
+        NamedDecl *PrevDecl = *I;
+        for (; I != IEnd && isDeclInScope(*I, CurContext, S); 
+             PrevDecl = *I, ++I) {
+          if (TD->declarationReplaces(*I)) {
+            // This is a redeclaration. Remove it from the chain and
+            // break out, so that we'll add in the shadowed
+            // declaration.
+            S->RemoveDecl(*I);
+            if (PrevDecl == *I) {
+              IdResolver.RemoveDecl(*I);
+              IdResolver.AddDecl(TD);
+              return;
+            } else {
+              IdResolver.RemoveDecl(*I);
+              break;
+            }
+          }
+        }
+
+        // There is already a declaration with the same name in the same
+        // scope, which is not a tag declaration. It must be found
+        // before we find the new declaration, so insert the new
+        // declaration at the end of the chain.
+        IdResolver.AddShadowedDecl(TD, PrevDecl);
+        
+        return;
       }
     }
   } else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
     // We are pushing the name of a function, which might be an
     // overloaded name.
     FunctionDecl *FD = cast<FunctionDecl>(D);
-    if (CurContext == FD->getDeclContext()) {
-      IdentifierResolver::iterator
-        I = IdResolver.begin(FD->getDeclName(), CurContext, 
-                             false/*LookInParentCtx*/);
-      if (I != IdResolver.end() &&
-          (isa<OverloadedFunctionDecl>(*I) || isa<FunctionDecl>(*I))) {
-        // There is already a declaration with the same name in
-        // the same scope. It must be a function or an overloaded
-        // function.
-        OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(*I);
-        if (!Ovl) {
-          // We haven't yet overloaded this function. Take the existing
-          // FunctionDecl and put it into an OverloadedFunctionDecl.
-          Ovl = OverloadedFunctionDecl::Create(Context, 
-                                               FD->getDeclContext(),
-                                               FD->getDeclName());
-          Ovl->addOverload(cast<FunctionDecl>(*I));
-          
-          IdResolver.RemoveDecl(*I);
-          S->RemoveDecl(*I);
-        
-          // Add the name binding for the OverloadedFunctionDecl.
-          IdResolver.AddDecl(Ovl);
-          
-          S->AddDecl(Ovl);
-        }
-
-        // We added this function declaration to the scope earlier, but
-        // we don't want it there because it is part of the overloaded
-        // function declaration.
-        S->RemoveDecl(FD);
-        
-        // We have an OverloadedFunctionDecl. Add the new FunctionDecl
-        // to its list of overloads.
-        Ovl->addOverload(FD);
-        
-        // Add this new function declaration to the declaration context.
-        CurContext->addDecl(Context, FD);
-        
-        return;      
-      }
+    IdentifierResolver::iterator Redecl
+      = std::find_if(IdResolver.begin(FD->getDeclName(), CurContext, 
+                                      false/*LookInParentCtx*/),
+                     IdResolver.end(),
+                     std::bind1st(std::mem_fun(&ScopedDecl::declarationReplaces),
+                                  FD));
+    if (Redecl != IdResolver.end()) {
+      // There is already a declaration of a function on our
+      // IdResolver chain. Replace it with this declaration.
+      S->RemoveDecl(*Redecl);
+      IdResolver.RemoveDecl(*Redecl);
     }
   }
 
-  // Add scoped declarations into their context, so that they can be
-  // found later. Declarations without a context won't be inserted
-  // into any context.
-  if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D))
-    CurContext->addDecl(Context, SD);
-
   IdResolver.AddDecl(D);
 }
 
@@ -217,10 +207,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
 /// probably be able to return multiple results, to deal with cases of
 /// ambiguity and overloaded functions without needing to create a
 /// Decl node.
+template<typename DeclIterator>
 static Decl *
-MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
-                          DeclContext::lookup_const_iterator I,
-                          DeclContext::lookup_const_iterator IEnd) {
+MaybeConstructOverloadSet(ASTContext &Context, 
+                          DeclIterator I, DeclIterator IEnd) {
   assert(I != IEnd && "Iterator range cannot be empty");
   assert(!isa<OverloadedFunctionDecl>(*I) && 
          "Cannot have an overloaded function");
@@ -228,7 +218,7 @@ MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
   if (isa<FunctionDecl>(*I)) {
     // If we found a function, there might be more functions. If
     // so, collect them into an overload set.
-    DeclContext::lookup_const_iterator Last = I;
+    DeclIterator Last = I;
     OverloadedFunctionDecl *Ovl = 0;
     for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
       if (!Ovl) {
@@ -236,7 +226,7 @@ MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
         // stop building the declarations for these overload sets, so
         // there will be nothing to leak.
         Ovl = OverloadedFunctionDecl::Create(Context, 
-                                             const_cast<DeclContext *>(DC), 
+                                         cast<ScopedDecl>(*I)->getDeclContext(),
                                              (*I)->getDeclName());
         Ovl->addOverload(cast<FunctionDecl>(*I));
       }
@@ -285,7 +275,7 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
     DeclContext::lookup_const_iterator I, E;
     for (llvm::tie(I, E) = LookupCtx->lookup(Context, Name); I != E; ++I)
       if ((*I)->getIdentifierNamespace() & NS)
-        return MaybeConstructOverloadSet(Context, LookupCtx, I, E);
+        return MaybeConstructOverloadSet(Context, I, E);
   } else {
     // Name lookup for ordinary names and tag names in C++ requires
     // looking into scopes that aren't strictly lexical, and
@@ -297,9 +287,21 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
     for (; S; S = S->getParent()) {
       // Check whether the IdResolver has anything in this scope.
       // FIXME: The isDeclScope check could be expensive. Can we do better?
-      for (; I != IEnd && S->isDeclScope(*I); ++I)
-        if ((*I)->getIdentifierNamespace() & NS)
-          return *I;
+      for (; I != IEnd && S->isDeclScope(*I); ++I) {
+        if ((*I)->getIdentifierNamespace() & NS) {
+          // We found something. Look for anything else in our scope
+          // with this same name and in an acceptable identifier
+          // namespace, so that we can construct an overload set if we
+          // need to.
+          IdentifierResolver::iterator LastI = I;
+          for (++LastI; LastI != IEnd; ++LastI) {
+            if (((*LastI)->getIdentifierNamespace() & NS) == 0 ||
+                !S->isDeclScope(*LastI))
+              break;
+          }
+          return MaybeConstructOverloadSet(Context, I, LastI);
+        }
+      }
       
       // If there is an entity associated with this scope, it's a
       // DeclContext. We might need to perform qualified lookup into
@@ -313,7 +315,7 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
         for (llvm::tie(I, E) = Ctx->lookup(Context, Name); I != E; ++I) {
           // FIXME: Cache this result in the IdResolver
           if ((*I)->getIdentifierNamespace() & NS)
-            return MaybeConstructOverloadSet(Context, LookupCtx, I, E);
+            return MaybeConstructOverloadSet(Context, I, E);
         }
         
         Ctx = Ctx->getParent();
@@ -652,6 +654,8 @@ void Sema::CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD) {
   bool VDIsTentative = isTentativeDefinition(VD);
   bool VDIsIncompleteArray = VD->getType()->isIncompleteArrayType();
   
+  // FIXME: I don't this will actually see all of the
+  // redefinitions. Can't we check this property on-the-fly?
   for (IdentifierResolver::iterator
        I = IdResolver.begin(VD->getIdentifier(), 
                             VD->getDeclContext(), false/*LookInParentCtx*/), 
@@ -1132,7 +1136,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
       assert(DC->isCXXRecord() &&
              "Constructors can only be declared in a member context");
 
-      bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
+      InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
 
       // Create the new declaration
       NewFD = CXXConstructorDecl::Create(Context, 
@@ -1141,12 +1145,12 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
                                          isExplicit, isInline,
                                          /*isImplicitlyDeclared=*/false);
 
-      if (isInvalidDecl)
+      if (InvalidDecl)
         NewFD->setInvalidDecl();
     } else if (D.getKind() == Declarator::DK_Destructor) {
       // This is a C++ destructor declaration.
       if (DC->isCXXRecord()) {
-        bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
+        InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
 
         NewFD = CXXDestructorDecl::Create(Context,
                                           cast<CXXRecordDecl>(DC),
@@ -1154,16 +1158,18 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
                                           isInline,
                                           /*isImplicitlyDeclared=*/false);
 
-        if (isInvalidDecl)
+        if (InvalidDecl)
           NewFD->setInvalidDecl();
       } else {
         Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
+
         // Create a FunctionDecl to satisfy the function definition parsing
         // code path.
         NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
                                      Name, R, SC, isInline, LastDeclarator,
                                      // FIXME: Move to DeclGroup...
                                    D.getDeclSpec().getSourceRange().getBegin());
+        InvalidDecl = true;
         NewFD->setInvalidDecl();
       }
     } else if (D.getKind() == Declarator::DK_Conversion) {
@@ -1172,14 +1178,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
              diag::err_conv_function_not_member);
         return 0;
       } else {
-        bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
+        InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
 
         NewFD = CXXConversionDecl::Create(Context, 
                                           cast<CXXRecordDecl>(DC),
                                           D.getIdentifierLoc(), Name, R,
                                           isInline, isExplicit);
         
-        if (isInvalidDecl)
+        if (InvalidDecl)
           NewFD->setInvalidDecl();
       }
     } else if (DC->isCXXRecord()) {
@@ -1316,48 +1322,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
         if (Redeclaration) {
           NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
 
-          if (OldDecl == PrevDecl) {
-            // Remove the name binding for the previous
-            // declaration.
-           if (S->isDeclScope(PrevDecl)) {
-             IdResolver.RemoveDecl(cast<NamedDecl>(PrevDecl));
-             S->RemoveDecl(PrevDecl);
-           }
-
-           // Introduce the new binding for this declaration.
-           IdResolver.AddDecl(NewFD);
-           if (getLangOptions().CPlusPlus && NewFD->getParent())
-             NewFD->getParent()->insert(Context, NewFD);
-
-           // Add the redeclaration to the current scope, since we'll
-           // be skipping PushOnScopeChains.
-           S->AddDecl(NewFD);
-          } else {
-            // We need to update the OverloadedFunctionDecl with the
-            // latest declaration of this function, so that name
-            // lookup will always refer to the latest declaration of
-            // this function.
-            *MatchedDecl = NewFD;
-         }
-           
-          if (getLangOptions().CPlusPlus) {
-            // Add this declaration to the current context.
-            CurContext->addDecl(Context, NewFD, false);
-
-            // Check default arguments now that we have merged decls.
-            CheckCXXDefaultArguments(NewFD);
-
-            // An out-of-line member function declaration must also be a
-            // definition (C++ [dcl.meaning]p1).
-            if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
-                !InvalidDecl) {
-              Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
-                << D.getCXXScopeSpec().getRange();
-              NewFD->setInvalidDecl();
-            }
+          // An out-of-line member function declaration must also be a
+          // definition (C++ [dcl.meaning]p1).
+          if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
+              !InvalidDecl) {
+            Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+              << D.getCXXScopeSpec().getRange();
+            NewFD->setInvalidDecl();
           }
-
-         return NewFD;
         }
       }
 
@@ -1417,7 +1389,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
 
       // An out-of-line member function declaration must also be a
       // definition (C++ [dcl.meaning]p1).
-      if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet()) {
+      if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
         Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
           << D.getCXXScopeSpec().getRange();
         InvalidDecl = true;
index eb2e647f0134bf1a58afcca6a3290484219f6e40..9ffa6ae82fb5124a6ada5d1edbc1dca162aaa113 100644 (file)
@@ -515,26 +515,15 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
   DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
 
   // Check if this function is already declared.
-  IdentifierResolver::iterator I = IdResolver.begin(Name, GlobalCtx,
-                                                    /*CheckParent=*/false);
-
-  if (I != IdResolver.end()) {
-    NamedDecl *Decl = *I;
-    if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(Decl)) {
-      // The return type fits. This is checked when the function is declared.
-      if (Fn->getNumParams() == 1 &&
-          Context.getCanonicalType(Fn->getParamDecl(0)->getType()) == Argument)
+  {
+    DeclContext::decl_iterator Alloc, AllocEnd;
+    for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Context, Name);
+         Alloc != AllocEnd; ++Alloc) {
+      // FIXME: Do we need to check for default arguments here?
+      FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
+      if (Func->getNumParams() == 1 &&
+          Context.getCanonicalType(Func->getParamDecl(0)->getType()) == Argument)
         return;
-    } else if(OverloadedFunctionDecl *Ovl =
-                  dyn_cast<OverloadedFunctionDecl>(Decl)) {
-      for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
-                                                     FEnd = Ovl->function_end();
-               F != FEnd; ++F) {
-        if ((*F)->getNumParams() == 1 &&
-            Context.getCanonicalType((*F)->getParamDecl(0)->getType())
-                == Argument)
-          return;
-      }
     }
   }
 
@@ -548,6 +537,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
                                            0, Argument, VarDecl::None, 0, 0);
   Alloc->setParams(&Param, 1);
 
+  // FIXME: Also add this declaration to the IdentifierResolver, but
+  // make sure it is at the end of the chain to coincide with the
+  // global scope.
   ((DeclContext *)TUScope->getEntity())->addDecl(Context, Alloc);
 }
 
index b2130e42f886ccf565f1da2d3d28db088fb42189..f829efb71bf2719135180ce9763873da7fd87ecc 100644 (file)
@@ -2160,10 +2160,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
   //        of type T2 or “reference to (possibly cv-qualified) T2”,
   //        when T2 is an enumeration type, are candidate functions.
   {
-    NamedDecl *NonMemberOps = 0;
-    for (IdentifierResolver::iterator I 
-           = IdResolver.begin(OpName, CurContext, true/*LookInParentCtx*/);
-         I != IdResolver.end(); ++I) {
+    IdentifierResolver::iterator
+      I = IdResolver.begin(OpName, CurContext, true/*LookInParentCtx*/),
+      IEnd = IdResolver.end();
+    for (; I != IEnd; ++I) {
       // We don't need to check the identifier namespace, because
       // operator names can only be ordinary identifiers.
 
@@ -2174,22 +2174,20 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
       } 
 
       // We found something with this name. We're done.
-      NonMemberOps = *I;
       break;
     }
 
-    if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps)) {
-      if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
-        AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
-                             /*SuppressUserConversions=*/false);
-    } else if (OverloadedFunctionDecl *Ovl
-                 = dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
-      for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
-                                                  FEnd = Ovl->function_end();
-           F != FEnd; ++F) {
-        if (IsAcceptableNonMemberOperatorCandidate(*F, T1, T2, Context)) 
-          AddOverloadCandidate(*F, Args, NumArgs, CandidateSet, 
-                               /*SuppressUserConversions=*/false);
+    if (I != IEnd && isa<ScopedDecl>(*I)) {
+      ScopedDecl *FirstDecl = cast<ScopedDecl>(*I);
+      for (; I != IEnd; ++I) {
+        ScopedDecl *SD = cast<ScopedDecl>(*I);
+        if (FirstDecl->getDeclContext() != SD->getDeclContext())
+          break;
+
+        if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
+          if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
+            AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+                                 /*SuppressUserConversions=*/false);
       }
     }
   }