summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Decl.cpp13
-rw-r--r--clang/lib/AST/DeclBase.cpp33
-rw-r--r--clang/lib/Sema/IdentifierResolver.h7
-rw-r--r--clang/lib/Sema/SemaDecl.cpp206
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp30
-rw-r--r--clang/lib/Sema/SemaOverload.cpp32
6 files changed, 145 insertions, 176 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 3edf8a02efb..bfe0272038f 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -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
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 87ebf85b41d..c6b3c53cc42 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -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;
}
}
diff --git a/clang/lib/Sema/IdentifierResolver.h b/clang/lib/Sema/IdentifierResolver.h
index bc9da6126d0..30846dcd174 100644
--- a/clang/lib/Sema/IdentifierResolver.h
+++ b/clang/lib/Sema/IdentifierResolver.h
@@ -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
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 270de5546bc..d84d6adad01 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index eb2e647f013..9ffa6ae82fb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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);
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index b2130e42f88..f829efb71bf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -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);
}
}
}
OpenPOWER on IntegriCloud