virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool InBaseClass) = 0;
};
+
+/// \brief A class for storing results from argument-dependent lookup.
+class ADLResult {
+private:
+ /// A map from canonical decls to the 'most recent' decl.
+ llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
+
+public:
+ /// Adds a new ADL candidate to this map.
+ void insert(NamedDecl *D);
+
+ /// Removes any data associated with a given decl.
+ void erase(NamedDecl *D) {
+ Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
+ }
+
+ class iterator {
+ typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
+ inner_iterator iter;
+
+ friend class ADLResult;
+ iterator(const inner_iterator &iter) : iter(iter) {}
+ public:
+ iterator() {}
+
+ iterator &operator++() { ++iter; return *this; }
+ iterator operator++(int) { return iterator(iter++); }
+
+ NamedDecl *operator*() const { return iter->second; }
+
+ bool operator==(const iterator &other) const { return iter == other.iter; }
+ bool operator!=(const iterator &other) const { return iter != other.iter; }
+ };
+
+ iterator begin() { return iterator(Decls.begin()); }
+ iterator end() { return iterator(Decls.end()); }
+};
+
}
#endif
class InitializationSequence;
class VisibleDeclConsumer;
class TargetAttributesSema;
+ class ADLResult;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
// TODO: make this is a typesafe union.
typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
- // Members have to be a function or function template.
- typedef llvm::SmallPtrSet<NamedDecl*, 16> ADLFunctionSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
void AddOverloadCandidate(NamedDecl *Function,
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- ADLFunctionSet &Functions);
+ ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer);
}
}
+void ADLResult::insert(NamedDecl *New) {
+ NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())];
+
+ // If we haven't yet seen a decl for this key, or the last decl
+ // was exactly this one, we're done.
+ if (Old == 0 || Old == New) {
+ Old = New;
+ return;
+ }
+
+ // Otherwise, decide which is a more recent redeclaration.
+ FunctionDecl *OldFD, *NewFD;
+ if (isa<FunctionTemplateDecl>(New)) {
+ OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl();
+ NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl();
+ } else {
+ OldFD = cast<FunctionDecl>(Old);
+ NewFD = cast<FunctionDecl>(New);
+ }
+
+ FunctionDecl *Cursor = NewFD;
+ while (true) {
+ Cursor = Cursor->getPreviousDeclaration();
+
+ // If we got to the end without finding OldFD, OldFD is the newer
+ // declaration; leave things as they are.
+ if (!Cursor) return;
+
+ // If we do find OldFD, then NewFD is newer.
+ if (Cursor == OldFD) break;
+
+ // Otherwise, keep looking.
+ }
+
+ Old = New;
+}
+
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- ADLFunctionSet &Functions) {
+ ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- // FIXME: canonical decls.
- // See comment in AddArgumentDependentLookupCandidates().
-
if (isa<FunctionDecl>(D)) {
if (Operator &&
!IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
T1, T2, Context))
continue;
- Functions.insert(D);
- } else if (isa<FunctionTemplateDecl>(D))
- Functions.insert(D);
+ } else if (!isa<FunctionTemplateDecl>(D))
+ continue;
+
+ Result.insert(D);
}
}
}
const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
- ADLFunctionSet Functions;
+ ADLResult Fns;
// FIXME: This approach for uniquing ADL results (and removing
// redundant candidates from the set) relies on pointer-equality,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Args, NumArgs, Functions);
+ ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
CandEnd = CandidateSet.end();
Cand != CandEnd; ++Cand)
if (Cand->Function) {
- Functions.erase(Cand->Function);
+ Fns.erase(Cand->Function);
if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
- Functions.erase(FunTmpl);
+ Fns.erase(FunTmpl);
}
// For each of the ADL candidates we found, add it to the overload
// set.
- for (ADLFunctionSet::iterator I = Functions.begin(),
- E = Functions.end(); I != E; ++I) {
+ for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
if (ExplicitTemplateArgs)
continue;
foo(*p); // expected-error {{no matching function for call to 'foo'}}
}
}
+
+// Redeclarations!
+namespace test1 {
+ namespace ns0 { struct Foo {}; }
+ namespace A { void foo(ns0::Foo *p, int y, int z); }
+ namespace ns2 { using A::foo; }
+ namespace ns1 { struct Bar : ns0::Foo {}; }
+ namespace A { void foo(ns0::Foo *p, int y, int z = 0); } // expected-note {{candidate}}
+ namespace ns1 { using A::foo; }
+ namespace ns2 { struct Baz : ns1::Bar {}; }
+ namespace A { void foo(ns0::Foo *p, int y = 0, int z); }
+
+ void test(ns2::Baz *p) {
+ foo(p, 0, 0); // okay!
+ foo(p, 0); // should be fine!
+ foo(p); // expected-error {{no matching function}}
+ }
+}