forked from OSchip/llvm-project
Initial implementation of member name lookup
llvm-svn: 62247
This commit is contained in:
parent
87cb84e9f0
commit
960b5bc7c1
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue