Add iterators to LookupResult, allowing one to iterate over the

non-ambiguous name lookup results without allocating any memory, e.g.,
for sets of overloaded functions.

llvm-svn: 63549
This commit is contained in:
Douglas Gregor 2009-02-02 21:35:47 +00:00
parent dd5dbca59c
commit 0e8fc3c773
5 changed files with 133 additions and 25 deletions

View File

@ -735,6 +735,55 @@ public:
Decl* getAsDecl() const;
BasePaths *getBasePaths() const;
/// \brief Iterate over the results of name lookup.
///
/// The @c iterator class provides iteration over the results of a
/// non-ambiguous name lookup.
class iterator {
/// The LookupResult structure we're iterating through.
LookupResult *Result;
/// The current position of this iterator within the sequence of
/// results. This value will have the same representation as the
/// @c First field in the LookupResult structure.
mutable uintptr_t Current;
public:
typedef Decl * value_type;
typedef Decl * reference;
typedef Decl * pointer;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
iterator() : Result(0), Current(0) { }
iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { }
reference operator*() const;
pointer operator->() const { return **this; }
iterator &operator++();
iterator operator++(int) {
iterator tmp(*this);
++(*this);
return tmp;
}
friend inline bool operator==(iterator const& x, iterator const& y) {
return x.Current == y.Current;
}
friend inline bool operator!=(iterator const& x, iterator const& y) {
return x.Current != y.Current;
}
};
friend class iterator;
iterator begin();
iterator end();
};
/// Determines whether D is a suitable lookup result according to the

View File

@ -1666,35 +1666,22 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName);
if (!PrevDecl) {
// Nothing to suggest.
} else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(PrevDecl)) {
for (OverloadedFunctionDecl::function_iterator
Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
if (isNearlyMatchingMemberFunction(Context, *Func, NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(PrevDecl)) {
// Suggest this no matter how mismatched it is; it's the only
// thing we have.
unsigned diag;
if (isNearlyMatchingMemberFunction(Context, Method, NewFD))
diag = diag::note_member_def_close_match;
else if (Method->getBody())
diag = diag::note_previous_definition;
else
diag = diag::note_previous_declaration;
Diag(Method->getLocation(), diag);
LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
true);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
if (isa<CXXMethodDecl>(*Func) &&
isNearlyMatchingMemberFunction(Context, cast<FunctionDecl>(*Func),
NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
PrevDecl = 0;
}
}
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);

View File

@ -1342,6 +1342,8 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
// [...] A program that calls for default-initialization or
// value-initialization of an entity of reference type is
// ill-formed. [...]
// FIXME: Once we have code that goes through this path, add an
// actual diagnostic :)
}
return false;

View File

@ -181,6 +181,66 @@ BasePaths *Sema::LookupResult::getBasePaths() const {
return reinterpret_cast<BasePaths *>(First);
}
Sema::LookupResult::iterator::reference
Sema::LookupResult::iterator::operator*() const {
switch (Result->StoredKind) {
case SingleDecl:
return reinterpret_cast<Decl*>(Current);
case OverloadedDeclFromIdResolver:
return *IdentifierResolver::iterator::getFromOpaqueValue(Current);
case OverloadedDeclFromDeclContext:
return *reinterpret_cast<DeclContext::lookup_iterator>(Current);
case AmbiguousLookup:
assert(false && "Cannot look into ambiguous lookup results");
break;
}
return 0;
}
Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
switch (Result->StoredKind) {
case SingleDecl:
Current = reinterpret_cast<uintptr_t>((Decl*)0);
break;
case OverloadedDeclFromIdResolver: {
IdentifierResolver::iterator I
= IdentifierResolver::iterator::getFromOpaqueValue(Current);
++I;
Current = I.getAsOpaqueValue();
break;
}
case OverloadedDeclFromDeclContext: {
DeclContext::lookup_iterator I
= reinterpret_cast<DeclContext::lookup_iterator>(Current);
++I;
Current = reinterpret_cast<uintptr_t>(I);
break;
}
case AmbiguousLookup:
assert(false && "Cannot look into ambiguous lookup results");
break;
}
return *this;
}
Sema::LookupResult::iterator Sema::LookupResult::begin() {
assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result");
return iterator(this, First);
}
Sema::LookupResult::iterator Sema::LookupResult::end() {
assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result");
return iterator(this, Last);
}
// Retrieve the set of identifier namespaces that correspond to a
// specific kind of name lookup.
inline unsigned

View File

@ -96,3 +96,13 @@ struct {
int a;
int z[2];
} y = { .z = {} };
int bbb[10];
struct foo2 {
unsigned a;
};
struct foo2 bar2[] = {
{ (int)bbb }
};