Initial implementation of member name lookup

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62247 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-01-15 00:26:24 +00:00
Родитель 89db21fec8
Коммит 7176fff961
7 изменённых файлов: 464 добавлений и 105 удалений

Просмотреть файл

@ -1519,7 +1519,7 @@ DIAG(err_anonymous_record_bad_member, ERROR,
DIAG(err_anonymous_record_nonpublic_member, ERROR,
"anonymous %select{struct|union}0 cannot contain a %select{private|protected}1 data member")
// Derived classes.
// C++ derived classes
DIAG(err_dup_virtual, ERROR,
"duplicate 'virtual' in base specifier")
DIAG(err_base_clause_on_union, ERROR,
@ -1536,6 +1536,12 @@ DIAG(err_duplicate_base_class, ERROR,
DIAG(err_ambiguous_derived_to_base_conv, ERROR,
"ambiguous conversion from derived class %0 to base class %1:%2")
// C++ member name lookup
DIAG(err_ambiguous_member_multiple_subobjects, ERROR,
"non-static member %0 found in multiple base-class subobjects of type %1")
DIAG(err_ambiguous_member_multiple_subobject_types, ERROR,
"member %0 found in multiple base classes of different types")
// C++ operator overloading
DIAG(err_operator_overload_needs_class_or_enum, ERROR,
"overloaded %0 must have at least one parameter of class "

Просмотреть файл

@ -71,6 +71,7 @@ namespace clang {
class ObjCContainerDecl;
struct BlockSemaInfo;
class BasePaths;
class MemberLookupCriteria;
/// PragmaPackStack - Simple class to wrap the stack used by #pragma
/// pack.
@ -596,6 +597,10 @@ public:
/// field is determined by the kind of name we're searching for.
unsigned IDNS;
LookupCriteria()
: Kind(Ordinary), AllowLazyBuiltinCreation(true),
RedeclarationOnly(false), IDNS(Decl::IDNS_Ordinary) { }
LookupCriteria(NameKind K, bool RedeclarationOnly, bool CPlusPlus);
bool isLookupResult(Decl *D) const;
@ -620,13 +625,19 @@ public:
mutable enum {
/// First is a single declaration (a Decl*), which may be NULL.
SingleDecl,
/// [First, Last) is an iterator range represented as opaque
/// pointers used to reconstruct IdentifierResolver::iterators.
OverloadedDeclFromIdResolver,
/// [First, Last) is an iterator range represented as opaque
/// pointers used to reconstruct DeclContext::lookup_iterators.
OverloadedDeclFromDeclContext,
/// FIXME: Cope with ambiguous name lookup.
/// First is a pointer to a BasePaths structure, which is owned
/// by the LookupResult. Last is non-zero to indicate that the
/// ambiguity is caused by two names found in base class
/// subobjects of different types.
AmbiguousLookup
} StoredKind;
@ -634,15 +645,16 @@ public:
/// lookup result. This may be a Decl* (if StoredKind ==
/// SingleDecl), the opaque pointer from an
/// IdentifierResolver::iterator (if StoredKind ==
/// OverloadedDeclFromIdResolver), or a
/// DeclContext::lookup_iterator (if StoredKind ==
/// OverloadedDeclFromDeclContext).
/// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator
/// (if StoredKind == OverloadedDeclFromDeclContext), or a
/// BasePaths pointer (if StoredKind == AmbiguousLookup).
mutable uintptr_t First;
/// The last lookup result, whose contents depend on the kind of
/// lookup result. This may be unused (if StoredKind ==
/// SingleDecl) or it may have the same type as First (for
/// overloaded function declarations).
/// SingleDecl), it may have the same type as First (for
/// overloaded function declarations), or is may be used as a
/// Boolean value (if StoredKind == AmbiguousLookup).
mutable uintptr_t Last;
/// Context - The context in which we will build any
@ -655,32 +667,62 @@ public:
enum LookupKind {
/// @brief No entity found met the criteria.
NotFound = 0,
/// @brief Name lookup found a single declaration that met the
/// criteria.
/// criteria. getAsDecl will return this declaration.
Found,
/// @brief Name lookup found a set of overloaded functions that
/// met the criteria.
/// met the criteria. getAsDecl will turn this set of overloaded
/// functions into an OverloadedFunctionDecl.
FoundOverloaded,
/// @brief Name lookup resulted in an ambiguity, e.g., because
/// the name was found in two different base classes.
Ambiguous
/// Name lookup results in an ambiguity because multiple
/// entities that meet the lookup criteria were found in
/// subobjects of different types. For example:
/// @code
/// struct A { void f(int); }
/// struct B { void f(double); }
/// struct C : A, B { };
/// void test(C c) {
/// c.f(0); // error: A::f and B::f come from subobjects of different
/// // types. overload resolution is not performed.
/// }
/// @endcode
AmbiguousBaseSubobjectTypes,
/// Name lookup results in an ambiguity because multiple
/// nonstatic entities that meet the lookup criteria were found
/// in different subobjects of the same type. For example:
/// @code
/// struct A { int x; };
/// struct B : A { };
/// struct C : A { };
/// struct D : B, C { };
/// int test(D d) {
/// return d.x; // error: 'x' is found in two A subobjects (of B and C)
/// }
/// @endcode
AmbiguousBaseSubobjects
};
LookupResult() : StoredKind(SingleDecl), First(0), Last(0), Context(0) { }
LookupResult(ASTContext &Context, Decl *D)
: StoredKind(SingleDecl), First(reinterpret_cast<uintptr_t>(D)),
Last(0), Context(&Context) { }
LookupResult(ASTContext &Context,
IdentifierResolver::iterator F, IdentifierResolver::iterator L)
: StoredKind(OverloadedDeclFromIdResolver),
First(F.getAsOpaqueValue()), Last(L.getAsOpaqueValue()),
Context(&Context) { }
IdentifierResolver::iterator F, IdentifierResolver::iterator L);
LookupResult(ASTContext &Context,
DeclContext::lookup_iterator F, DeclContext::lookup_iterator L)
: StoredKind(OverloadedDeclFromDeclContext),
First(reinterpret_cast<uintptr_t>(F)),
Last(reinterpret_cast<uintptr_t>(L)),
DeclContext::lookup_iterator F, DeclContext::lookup_iterator L);
LookupResult(ASTContext &Context, BasePaths *Paths,
bool DifferentSubobjectTypes)
: StoredKind(AmbiguousLookup),
First(reinterpret_cast<uintptr_t>(Paths)),
Last(DifferentSubobjectTypes? 1 : 0),
Context(&Context) { }
LookupKind getKind() const;
@ -688,11 +730,16 @@ public:
/// @brief Determine whether name look found something.
operator bool() const { return getKind() != NotFound; }
/// @brief Determines whether the lookup resulted in an ambiguity.
bool isAmbiguous() const { return StoredKind == AmbiguousLookup; }
/// @brief Allows conversion of a lookup result into a
/// declaration, with the same behavior as getAsDecl.
operator Decl*() const { return getAsDecl(); }
Decl* getAsDecl() const;
BasePaths *getBasePaths() const;
};
LookupResult LookupName(Scope *S, DeclarationName Name,
@ -701,12 +748,15 @@ public:
LookupCriteria Criteria);
LookupResult LookupParsedName(Scope *S, const CXXScopeSpec &SS,
DeclarationName Name, LookupCriteria Criteria);
LookupResult LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
const DeclContext *LookupCtx = 0,
bool enableLazyBuiltinCreation = true,
bool LookInParent = true,
bool NamespaceNameOnly = false);
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
SourceLocation NameLoc,
SourceRange LookupRange = SourceRange());
//@}
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
@ -1270,7 +1320,8 @@ public:
bool IsDerivedFrom(QualType Derived, QualType Base);
bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths);
bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria,
BasePaths &Paths);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range);

Просмотреть файл

@ -39,12 +39,28 @@ Sema::TypeTy *Sema::isTypeName(IdentifierInfo &II, Scope *S,
return 0;
DC = static_cast<DeclContext*>(SS->getScopeRep());
}
Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
LookupResult Result = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
if (IIDecl && (isa<TypedefDecl>(IIDecl) ||
isa<ObjCInterfaceDecl>(IIDecl) ||
isa<TagDecl>(IIDecl) ||
isa<TemplateTypeParmDecl>(IIDecl)))
Decl *IIDecl = 0;
switch (Result.getKind()) {
case LookupResult::NotFound:
case LookupResult::FoundOverloaded:
case LookupResult::AmbiguousBaseSubobjectTypes:
case LookupResult::AmbiguousBaseSubobjects:
// FIXME: In the event of an ambiguous lookup, we could visit all of
// the entities found to determine whether they are all types. This
// might provide better diagnostics.
return 0;
case LookupResult::Found:
IIDecl = Result.getAsDecl();
break;
}
if (isa<TypedefDecl>(IIDecl) ||
isa<ObjCInterfaceDecl>(IIDecl) ||
isa<TagDecl>(IIDecl) ||
isa<TemplateTypeParmDecl>(IIDecl))
return IIDecl;
return 0;
}

Просмотреть файл

@ -546,14 +546,22 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
}
// Could be enum-constant, value decl, instance variable, etc.
Decl *D;
Decl *D = 0;
LookupResult Lookup;
if (SS && !SS->isEmpty()) {
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
if (DC == 0)
return true;
D = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
Lookup = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
} else
D = LookupDecl(Name, Decl::IDNS_Ordinary, S);
Lookup = LookupDecl(Name, Decl::IDNS_Ordinary, S);
if (Lookup.isAmbiguous())
return DiagnoseAmbiguousLookup(Lookup, Name, Loc,
SS && SS->isSet()? SS->getRange()
: SourceRange());
else
D = Lookup.getAsDecl();
// If this reference is in an Objective-C method, then ivar lookup happens as
// well.
@ -1444,11 +1452,21 @@ ActOnMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc,
// The record definition is complete, now make sure the member is valid.
// FIXME: Qualified name lookup for C++ is a bit more complicated
// than this.
Decl *MemberDecl = LookupDecl(DeclarationName(&Member), Decl::IDNS_Ordinary,
S, RDecl, false, false);
if (!MemberDecl)
LookupResult Result
= LookupQualifiedName(RDecl, DeclarationName(&Member),
LookupCriteria(LookupCriteria::Member,
/*RedeclarationOnly=*/false,
getLangOptions().CPlusPlus));
Decl *MemberDecl = 0;
if (!Result)
return Diag(MemberLoc, diag::err_typecheck_no_member)
<< &Member << BaseExpr->getSourceRange();
else if (Result.isAmbiguous())
return DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
MemberLoc, BaseExpr->getSourceRange());
else
MemberDecl = Result;
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
// We may have found a field within an anonymous union or struct

Просмотреть файл

@ -20,6 +20,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include <algorithm>
#include <memory>
#include <set>
#include <string>
@ -45,6 +46,17 @@ void BasePaths::clear() {
DetectedVirtual = 0;
}
/// @brief Swaps the contents of this BasePaths structure with the
/// contents of Other.
void BasePaths::swap(BasePaths &Other) {
Paths.swap(Other.Paths);
ClassSubobjects.swap(Other.ClassSubobjects);
std::swap(FindAmbiguities, Other.FindAmbiguities);
std::swap(RecordPaths, Other.RecordPaths);
std::swap(DetectVirtual, Other.DetectVirtual);
std::swap(DetectedVirtual, Other.DetectedVirtual);
}
/// IsDerivedFrom - Determine whether the type Derived is derived from
/// the type Base, ignoring qualifiers on Base and Derived. This
/// routine does not assess whether an actual conversion from a
@ -65,8 +77,6 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
/// information about all of the paths (if @c Paths.isRecordingPaths()).
bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
bool FoundPath = false;
Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
Base = Context.getCanonicalType(Base).getUnqualifiedType();
@ -76,71 +86,112 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
if (Derived == Base)
return false;
if (const RecordType *DerivedType = Derived->getAsRecordType()) {
const CXXRecordDecl *Decl
= static_cast<const CXXRecordDecl *>(DerivedType->getDecl());
for (CXXRecordDecl::base_class_const_iterator BaseSpec = Decl->bases_begin();
BaseSpec != Decl->bases_end(); ++BaseSpec) {
// Find the record of the base class subobjects for this type.
QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
BaseType = BaseType.getUnqualifiedType();
// Determine whether we need to visit this base class at all,
// updating the count of subobjects appropriately.
std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
bool VisitBase = true;
bool SetVirtual = false;
if (BaseSpec->isVirtual()) {
VisitBase = !Subobjects.first;
Subobjects.first = true;
if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
Paths.DetectedVirtual = static_cast<const CXXRecordType*>(
BaseType->getAsRecordType());
SetVirtual = true;
}
} else
++Subobjects.second;
return LookupInBases(cast<CXXRecordType>(Derived->getAsRecordType())->getDecl(),
MemberLookupCriteria(Base), Paths);
}
/// LookupInBases - Look for something that meets the specified
/// Criteria within the base classes of Class (or any of its base
/// classes, transitively). This routine populates BasePaths with the
/// list of paths that one can take to find the entity that meets the
/// search criteria, and returns true if any such entity is found. The
/// various options passed to the BasePath constructor will affect the
/// behavior of this lookup, e.g., whether it finds ambiguities,
/// records paths, or attempts to detect the use of virtual base
/// classes.
bool Sema::LookupInBases(CXXRecordDecl *Class,
const MemberLookupCriteria& Criteria,
BasePaths &Paths) {
bool FoundPath = false;
for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(),
BaseSpecEnd = Class->bases_end();
BaseSpec != BaseSpecEnd; ++BaseSpec) {
// Find the record of the base class subobjects for this type.
QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
BaseType = BaseType.getUnqualifiedType();
// Determine whether we need to visit this base class at all,
// updating the count of subobjects appropriately.
std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
bool VisitBase = true;
bool SetVirtual = false;
if (BaseSpec->isVirtual()) {
VisitBase = !Subobjects.first;
Subobjects.first = true;
if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
Paths.DetectedVirtual = cast<CXXRecordType>(BaseType->getAsRecordType());
SetVirtual = true;
}
} else
++Subobjects.second;
if (Paths.isRecordingPaths()) {
// Add this base specifier to the current path.
BasePathElement Element;
Element.Base = &*BaseSpec;
if (BaseSpec->isVirtual())
Element.SubobjectNumber = 0;
else
Element.SubobjectNumber = Subobjects.second;
Paths.ScratchPath.push_back(Element);
}
CXXRecordDecl *BaseRecord
= cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl());
// Either look at the base class type or look into the base class
// type to see if we've found a member that meets the search
// criteria.
bool FoundPathToThisBase = false;
if (Criteria.LookupBase) {
FoundPathToThisBase
= (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
} else {
Paths.ScratchPath.Decls = BaseRecord->lookup(Criteria.Name);
while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
if (Criteria.Criteria.isLookupResult(*Paths.ScratchPath.Decls.first)) {
FoundPathToThisBase = true;
break;
}
++Paths.ScratchPath.Decls.first;
}
}
if (FoundPathToThisBase) {
// We've found a path that terminates that this base.
FoundPath = true;
if (Paths.isRecordingPaths()) {
// Add this base specifier to the current path.
BasePathElement Element;
Element.Base = &*BaseSpec;
if (BaseSpec->isVirtual())
Element.SubobjectNumber = 0;
else
Element.SubobjectNumber = Subobjects.second;
Paths.ScratchPath.push_back(Element);
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
} else if (!Paths.isFindingAmbiguities()) {
// We found a path and we don't care about ambiguities;
// return immediately.
return FoundPath;
}
}
// C++ [class.member.lookup]p2:
// A member name f in one sub-object B hides a member name f in
// a sub-object A if A is a base class sub-object of B. Any
// declarations that are so hidden are eliminated from
// consideration.
else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
// There is a path to a base class that meets the criteria. If we're not
// collecting paths or finding ambiguities, we're done.
FoundPath = true;
if (!Paths.isFindingAmbiguities())
return FoundPath;
}
if (Context.getCanonicalType(BaseSpec->getType()) == Base) {
// We've found the base we're looking for.
FoundPath = true;
if (Paths.isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
} else if (!Paths.isFindingAmbiguities()) {
// We found a path and we don't care about ambiguities;
// return immediately.
return FoundPath;
}
} else if (VisitBase && IsDerivedFrom(BaseSpec->getType(), Base, Paths)) {
// There is a path to the base we want. If we're not
// collecting paths or finding ambiguities, we're done.
FoundPath = true;
if (!Paths.isFindingAmbiguities())
return FoundPath;
}
// Pop this base specifier off the current path (if we're
// collecting paths).
if (Paths.isRecordingPaths())
Paths.ScratchPath.pop_back();
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPath) {
Paths.DetectedVirtual = 0;
}
// Pop this base specifier off the current path (if we're
// collecting paths).
if (Paths.isRecordingPaths())
Paths.ScratchPath.pop_back();
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPath) {
Paths.DetectedVirtual = 0;
}
}
@ -208,4 +259,3 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
<< Derived << Base << PathDisplayStr << Range;
return true;
}

Просмотреть файл

@ -16,6 +16,8 @@
#ifndef LLVM_CLANG_SEMA_INHERIT_H
#define LLVM_CLANG_SEMA_INHERIT_H
#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ADT/SmallVector.h"
@ -48,12 +50,17 @@ namespace clang {
/// BasePath - Represents a path from a specific derived class
/// (which is not represented as part of the path) to a particular
/// (direct or indirect) base class subobject. Individual elements
/// (direct or indirect) base class subobject that contains some
/// number of declarations with the same name. Individual elements
/// in the path are described by the BasePathElement structure,
/// which captures both the link from a derived class to one of its
/// direct bases and identification describing which base class
/// subobject is being used.
typedef llvm::SmallVector<BasePathElement, 4> BasePath;
/// subobject is being used.
struct BasePath : public llvm::SmallVector<BasePathElement, 4> {
/// Decls - The set of declarations found inside this base class
/// subobject.
DeclContext::lookup_result Decls;
};
/// BasePaths - Represents the set of paths from a derived class to
/// one of its (direct or indirect) bases. For example, given the
@ -137,6 +144,9 @@ namespace clang {
paths_iterator begin() const { return Paths.begin(); }
paths_iterator end() const { return Paths.end(); }
BasePath& front() { return Paths.front(); }
const BasePath& front() const { return Paths.front(); }
bool isAmbiguous(QualType BaseType);
/// isFindingAmbiguities - Whether we are finding multiple paths
@ -159,6 +169,41 @@ namespace clang {
}
void clear();
void swap(BasePaths &Other);
};
/// MemberLookupCriteria - Criteria for performing lookup of a
/// member of a C++ class. Objects of this type are used to direct
/// Sema::LookupCXXClassMember.
struct MemberLookupCriteria {
/// MemberLookupCriteria - Constructs member lookup criteria to
/// search for a base class of type Base.
explicit MemberLookupCriteria(QualType Base)
: LookupBase(true), Base(Base) { }
/// MemberLookupCriteria - Constructs member lookup criteria to
/// search for a class member with the given Name.
explicit MemberLookupCriteria(DeclarationName Name,
Sema::LookupCriteria Criteria)
: LookupBase(false), Name(Name), Criteria(Criteria) { }
/// LookupBase - True if we are looking for a base class (whose
/// type is Base). If false, we are looking for a named member of
/// the class (with the name Name).
bool LookupBase;
/// Base - The type of the base class we're searching for, if
/// LookupBase is true.
QualType Base;
/// Name - The name of the member we're searching for, if
/// LookupBase is false.
DeclarationName Name;
/// Criteria - The criteria by which we evaluate a named member,
/// if LookupBase is false.
Sema::LookupCriteria Criteria;
};
}

Просмотреть файл

@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
#include "SemaInherit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@ -125,6 +127,46 @@ bool Sema::LookupCriteria::isLookupResult(Decl *D) const {
return false;
}
Sema::LookupResult::LookupResult(ASTContext &Context,
IdentifierResolver::iterator F,
IdentifierResolver::iterator L)
: Context(&Context) {
if (F != L && isa<FunctionDecl>(*F)) {
IdentifierResolver::iterator Next = F;
++Next;
if (Next != L && isa<FunctionDecl>(*Next)) {
StoredKind = OverloadedDeclFromIdResolver;
First = F.getAsOpaqueValue();
Last = L.getAsOpaqueValue();
return;
}
}
StoredKind = SingleDecl;
First = reinterpret_cast<uintptr_t>(*F);
Last = 0;
}
Sema::LookupResult::LookupResult(ASTContext &Context,
DeclContext::lookup_iterator F,
DeclContext::lookup_iterator L)
: Context(&Context) {
if (F != L && isa<FunctionDecl>(*F)) {
DeclContext::lookup_iterator Next = F;
++Next;
if (Next != L && isa<FunctionDecl>(*Next)) {
StoredKind = OverloadedDeclFromDeclContext;
First = reinterpret_cast<uintptr_t>(F);
Last = reinterpret_cast<uintptr_t>(L);
return;
}
}
StoredKind = SingleDecl;
First = reinterpret_cast<uintptr_t>(*F);
Last = 0;
}
/// @brief Determine the result of name lookup.
Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
switch (StoredKind) {
@ -136,11 +178,11 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
return FoundOverloaded;
case AmbiguousLookup:
return Ambiguous;
return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
}
// We can't get here, but GCC complains nonetheless.
return Ambiguous;
// We can't ever get here.
return NotFound;
}
/// @brief Converts the result of name lookup into a single (possible
@ -180,6 +222,14 @@ Decl *Sema::LookupResult::getAsDecl() const {
return 0;
}
/// @brief Retrieves the BasePaths structure describing an ambiguous
/// name lookup.
BasePaths *Sema::LookupResult::getBasePaths() const {
assert((StoredKind == AmbiguousLookup) &&
"getBasePaths can only be used on an ambiguous lookup");
return reinterpret_cast<BasePaths *>(First);
}
/// @brief Perform unqualified name lookup starting from a given
/// scope.
///
@ -379,13 +429,99 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
Criteria.IDNS |= Decl::IDNS_Member;
// Perform qualified name lookup into the LookupCtx.
// FIXME: Will need to look into base classes and such.
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
if (Criteria.isLookupResult(*I))
return LookupResult(Context, I, E);
return LookupResult(Context, 0);
// If this isn't a C++ class or we aren't allowed to look into base
// classes, we're done.
if (Criteria.RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
return LookupResult(Context, 0);
// Perform lookup into our base classes.
BasePaths Paths;
// Look for this member in our base classes
if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx),
MemberLookupCriteria(Name, Criteria), Paths))
return LookupResult(Context, 0);
// C++ [class.member.lookup]p2:
// [...] If the resulting set of declarations are not all from
// sub-objects of the same type, or the set has a nonstatic member
// and includes members from distinct sub-objects, there is an
// ambiguity and the program is ill-formed. Otherwise that set is
// the result of the lookup.
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber;
for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
const BasePathElement &PathElement = Path->back();
// Determine whether we're looking at a distinct sub-object or not.
if (SubobjectType.isNull()) {
// This is the first subobject we've looked at. Record it's type.
SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
SubobjectNumber = PathElement.SubobjectNumber;
} else if (SubobjectType
!= Context.getCanonicalType(PathElement.Base->getType())) {
// We found members of the given name in two subobjects of
// different types. This lookup is ambiguous.
BasePaths *PathsOnHeap = new BasePaths;
PathsOnHeap->swap(Paths);
return LookupResult(Context, PathsOnHeap, true);
} else if (SubobjectNumber != PathElement.SubobjectNumber) {
// We have a different subobject of the same type.
// C++ [class.member.lookup]p5:
// A static member, a nested type or an enumerator defined in
// a base class T can unambiguously be found even if an object
// has more than one base class subobject of type T.
ScopedDecl *FirstDecl = *Path->Decls.first;
if (isa<VarDecl>(FirstDecl) ||
isa<TypeDecl>(FirstDecl) ||
isa<EnumConstantDecl>(FirstDecl))
continue;
if (isa<CXXMethodDecl>(FirstDecl)) {
// Determine whether all of the methods are static.
bool AllMethodsAreStatic = true;
for (DeclContext::lookup_iterator Func = Path->Decls.first;
Func != Path->Decls.second; ++Func) {
if (!isa<CXXMethodDecl>(*Func)) {
assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl");
break;
}
if (!cast<CXXMethodDecl>(*Func)->isStatic()) {
AllMethodsAreStatic = false;
break;
}
}
if (AllMethodsAreStatic)
continue;
}
// We have found a nonstatic member name in multiple, distinct
// subobjects. Name lookup is ambiguous.
BasePaths *PathsOnHeap = new BasePaths;
PathsOnHeap->swap(Paths);
return LookupResult(Context, PathsOnHeap, false);
}
}
// Lookup in a base class succeeded; return these results.
// If we found a function declaration, return an overload set.
if (isa<FunctionDecl>(*Paths.front().Decls.first))
return LookupResult(Context,
Paths.front().Decls.first, Paths.front().Decls.second);
// We found a non-function declaration; return a single declaration.
return LookupResult(Context, *Paths.front().Decls.first);
}
/// @brief Performs name lookup for a name that was parsed in the
@ -419,4 +555,41 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec &SS,
return LookupName(S, Name, Criteria);
}
/// @brief Produce a diagnostic describing the ambiguity that resulted
/// from name lookup.
///
/// @param Result The ambiguous name lookup result.
///
/// @param Name The name of the entity that name lookup was
/// searching for.
///
/// @param NameLoc The location of the name within the source code.
///
/// @param LookupRange A source range that provides more
/// source-location information concerning the lookup itself. For
/// example, this range might highlight a nested-name-specifier that
/// precedes the name.
///
/// @returns true
bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
SourceLocation NameLoc,
SourceRange LookupRange) {
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
BasePaths *Paths = Result.getBasePaths();
QualType SubobjectType = Paths->front().back().Base->getType();
return Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
<< Name << SubobjectType << LookupRange;
}
assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
"Unhandled form of name lookup ambiguity");
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
<< Name << LookupRange;
// FIXME: point out the members we found using notes.
return true;
}