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,
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 "
class ObjCContainerDecl;
struct BlockSemaInfo;
class BasePaths;
+ class MemberLookupCriteria;
/// PragmaPackStack - Simple class to wrap the stack used by #pragma
/// pack.
/// 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;
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;
/// 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
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;
/// @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,
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);
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);
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);
+
+ 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 (IIDecl && (isa<TypedefDecl>(IIDecl) ||
- isa<ObjCInterfaceDecl>(IIDecl) ||
- isa<TagDecl>(IIDecl) ||
- isa<TemplateTypeParmDecl>(IIDecl)))
+ if (isa<TypedefDecl>(IIDecl) ||
+ isa<ObjCInterfaceDecl>(IIDecl) ||
+ isa<TagDecl>(IIDecl) ||
+ isa<TemplateTypeParmDecl>(IIDecl))
return IIDecl;
return 0;
}
}
// 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.
// 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
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
+#include <algorithm>
#include <memory>
#include <set>
#include <string>
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
/// 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();
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);
+}
- 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);
+/// 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 (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;
+ 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;
}
- } 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;
+ ++Paths.ScratchPath.Decls.first;
}
+ }
- // 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;
+ if (FoundPathToThisBase) {
+ // We've found a path that terminates that this base.
+ 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;
}
+ }
+ // 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;
+ }
+
+ // 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;
}
}
<< Derived << Base << PathDisplayStr << Range;
return true;
}
-
#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"
/// 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
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
}
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;
};
}
//
//===----------------------------------------------------------------------===//
#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"
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) {
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
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.
///
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
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;
+}