Semantic analysis, ASTs, and unqualified name lookup support for C++
using directives, from Piotr Rak! llvm-svn: 63646
This commit is contained in:
parent
2f219b0770
commit
889ceb752d
@ -452,7 +452,18 @@ public:
|
||||
const Type *getCanonicalType(const Type *T) {
|
||||
return T->getCanonicalTypeInternal().getTypePtr();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieves the "canonical" declaration of the given tag
|
||||
/// declaration.
|
||||
///
|
||||
/// The canonical declaration for the given tag declaration is
|
||||
/// either the definition of the tag (if it is a complete type) or
|
||||
/// the first declaration of that tag.
|
||||
TagDecl *getCanonicalDecl(TagDecl *Tag) {
|
||||
QualType T = getTagDeclType(Tag);
|
||||
return cast<TagDecl>(cast<TagType>(T)->getDecl());
|
||||
}
|
||||
|
||||
/// Type Query functions. If the type is an instance of the specified class,
|
||||
/// return the Type pointer for the underlying maximally pretty type. This
|
||||
/// is a member of ASTContext because this may need to do some amount of
|
||||
|
||||
@ -25,6 +25,7 @@ namespace clang {
|
||||
class DeclContext;
|
||||
class TranslationUnitDecl;
|
||||
class NamespaceDecl;
|
||||
class UsingDirectiveDecl;
|
||||
class NamedDecl;
|
||||
class FunctionDecl;
|
||||
class CXXRecordDecl;
|
||||
@ -768,6 +769,22 @@ public:
|
||||
/// replaced with D.
|
||||
void makeDeclVisibleInContext(NamedDecl *D);
|
||||
|
||||
/// udir_iterator - Iterates through the using-directives stored
|
||||
/// within this context.
|
||||
typedef UsingDirectiveDecl * const * udir_iterator;
|
||||
|
||||
typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range;
|
||||
|
||||
udir_iterator_range getUsingDirectives() const;
|
||||
|
||||
udir_iterator using_directives_begin() const {
|
||||
return getUsingDirectives().first;
|
||||
}
|
||||
|
||||
udir_iterator using_directives_end() const {
|
||||
return getUsingDirectives().second;
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
#define DECL_CONTEXT(Name) case Decl::Name:
|
||||
|
||||
@ -948,6 +948,82 @@ protected:
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// UsingDirectiveDecl - Represents C++ using-directive. For example:
|
||||
///
|
||||
/// using namespace std;
|
||||
///
|
||||
// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide
|
||||
// artificial name, for all using-directives in order to store
|
||||
// them in DeclContext effectively.
|
||||
class UsingDirectiveDecl : public NamedDecl {
|
||||
|
||||
/// SourceLocation - Location of 'namespace' token.
|
||||
SourceLocation NamespaceLoc;
|
||||
|
||||
/// IdentLoc - Location of nominated namespace-name identifier.
|
||||
// FIXME: We don't store location of scope specifier.
|
||||
SourceLocation IdentLoc;
|
||||
|
||||
/// NominatedNamespace - Namespace nominated by using-directive.
|
||||
NamespaceDecl *NominatedNamespace;
|
||||
|
||||
/// Enclosing context containing both using-directive and nomintated
|
||||
/// namespace.
|
||||
DeclContext *CommonAncestor;
|
||||
|
||||
/// getUsingDirectiveName - Returns special DeclarationName used by
|
||||
/// using-directives. This is only used by DeclContext for storing
|
||||
/// UsingDirectiveDecls in its lookup structure.
|
||||
static DeclarationName getName() {
|
||||
return DeclarationName::getUsingDirectiveName();
|
||||
}
|
||||
|
||||
UsingDirectiveDecl(DeclContext *DC, SourceLocation L,
|
||||
SourceLocation NamespcLoc,
|
||||
SourceLocation IdentLoc,
|
||||
NamespaceDecl *Nominated,
|
||||
DeclContext *CommonAncestor)
|
||||
: NamedDecl(Decl::UsingDirective, DC, L, getName()),
|
||||
NamespaceLoc(NamespcLoc), IdentLoc(IdentLoc),
|
||||
NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0),
|
||||
CommonAncestor(CommonAncestor) {
|
||||
}
|
||||
|
||||
public:
|
||||
/// getNominatedNamespace - Returns namespace nominated by using-directive.
|
||||
NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; }
|
||||
|
||||
const NamespaceDecl *getNominatedNamespace() const {
|
||||
return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace();
|
||||
}
|
||||
|
||||
/// getCommonAncestor - returns common ancestor context of using-directive,
|
||||
/// and nominated by it namespace.
|
||||
DeclContext *getCommonAncestor() { return CommonAncestor; }
|
||||
const DeclContext *getCommonAncestor() const { return CommonAncestor; }
|
||||
|
||||
/// getNamespaceKeyLocation - Returns location of namespace keyword.
|
||||
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
|
||||
|
||||
/// getIdentLocation - Returns location of identifier.
|
||||
SourceLocation getIdentLocation() const { return IdentLoc; }
|
||||
|
||||
static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
SourceLocation NamespaceLoc,
|
||||
SourceLocation IdentLoc,
|
||||
NamespaceDecl *Nominated,
|
||||
DeclContext *CommonAncestor);
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Decl::UsingDirective;
|
||||
}
|
||||
static bool classof(const UsingDirectiveDecl *D) { return true; }
|
||||
|
||||
// Friend for getUsingDirectiveName.
|
||||
friend class DeclContext;
|
||||
};
|
||||
|
||||
/// TemplateParameterList - Stores a list of template parameters.
|
||||
class TemplateParameterList {
|
||||
/// NumParams - The number of template parameters in this template
|
||||
|
||||
@ -76,6 +76,7 @@ ABSTRACT_DECL(Named, Decl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Namespace, NamedDecl)
|
||||
DECL(UsingDirective, NamedDecl)
|
||||
ABSTRACT_DECL(Type, NamedDecl)
|
||||
DECL(Typedef, TypeDecl)
|
||||
ABSTRACT_DECL(Tag, TypeDecl)
|
||||
|
||||
@ -27,6 +27,7 @@ namespace clang {
|
||||
class DeclarationNameExtra;
|
||||
class IdentifierInfo;
|
||||
class MultiKeywordSelector;
|
||||
class UsingDirectiveDecl;
|
||||
|
||||
/// DeclarationName - The name of a declaration. In the common case,
|
||||
/// this just stores an IdentifierInfo pointer to a normal
|
||||
@ -45,7 +46,8 @@ public:
|
||||
CXXConstructorName,
|
||||
CXXDestructorName,
|
||||
CXXConversionFunctionName,
|
||||
CXXOperatorName
|
||||
CXXOperatorName,
|
||||
CXXUsingDirective
|
||||
};
|
||||
|
||||
private:
|
||||
@ -153,7 +155,12 @@ private:
|
||||
/// Construct a declaration name from a raw pointer.
|
||||
DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
|
||||
|
||||
/// getUsingDirectiveName - Return name for all using-directives.
|
||||
static DeclarationName getUsingDirectiveName();
|
||||
|
||||
friend class DeclarationNameTable;
|
||||
friend class UsingDirectiveDecl;
|
||||
friend class NamedDecl;
|
||||
|
||||
/// getFETokenInfoAsVoid - Retrieves the front end-specified pointer
|
||||
/// for this name as a void pointer.
|
||||
|
||||
@ -1041,6 +1041,10 @@ DIAG(err_ambiguous_member_multiple_subobject_types, ERROR,
|
||||
"member %0 found in multiple base classes of different types")
|
||||
DIAG(note_ambiguous_member_found, NOTE,
|
||||
"member found by ambiguous name lookup")
|
||||
DIAG(err_ambiguous_reference, ERROR,
|
||||
"reference to %0 is ambiguous")
|
||||
DIAG(note_ambiguous_candidate, NOTE,
|
||||
"candidate found by name lookup is '%0'")
|
||||
|
||||
// C++ operator overloading
|
||||
DIAG(err_operator_overload_needs_class_or_enum, ERROR,
|
||||
|
||||
@ -449,6 +449,7 @@ public:
|
||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
|
||||
CXXOperator##Name,
|
||||
#include "clang/Basic/OperatorKinds.def"
|
||||
CXXUsingDirective,
|
||||
NUM_EXTRA_KINDS
|
||||
};
|
||||
|
||||
@ -456,8 +457,9 @@ public:
|
||||
/// operator-id (if the value is one of the CXX* enumerators of
|
||||
/// ExtraKind), in which case the DeclarationNameExtra is also a
|
||||
/// CXXSpecialName (for CXXConstructor, CXXDestructor, or
|
||||
/// CXXConversionFunction) or CXXOperatorIdName, otherwise it is
|
||||
/// NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of
|
||||
/// CXXConversionFunction) or CXXOperatorIdName, it may be also
|
||||
/// name common to C++ using-directives (CXXUsingDirective), otherwise
|
||||
/// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of
|
||||
/// arguments in the Objective-C selector, in which case the
|
||||
/// DeclarationNameExtra is also a MultiKeywordSelector.
|
||||
unsigned ExtraKindOrNumArgs;
|
||||
|
||||
@ -122,6 +122,9 @@ private:
|
||||
/// maintained by the Action implementation.
|
||||
void *Entity;
|
||||
|
||||
typedef llvm::SmallVector<Action::DeclTy*, 2> UsingDirectivesTy;
|
||||
UsingDirectivesTy UsingDirectives;
|
||||
|
||||
public:
|
||||
Scope(Scope *Parent, unsigned ScopeFlags) {
|
||||
Init(Parent, ScopeFlags);
|
||||
@ -234,6 +237,29 @@ public:
|
||||
|
||||
void setWithinElse(bool WE) { WithinElse = WE; }
|
||||
|
||||
typedef UsingDirectivesTy::iterator udir_iterator;
|
||||
typedef UsingDirectivesTy::const_iterator const_udir_iterator;
|
||||
|
||||
void PushUsingDirective(Action::DeclTy *UDir) {
|
||||
UsingDirectives.push_back(UDir);
|
||||
}
|
||||
|
||||
udir_iterator using_directives_begin() {
|
||||
return UsingDirectives.begin();
|
||||
}
|
||||
|
||||
udir_iterator using_directives_end() {
|
||||
return UsingDirectives.end();
|
||||
}
|
||||
|
||||
const_udir_iterator using_directives_begin() const {
|
||||
return UsingDirectives.begin();
|
||||
}
|
||||
|
||||
const_udir_iterator using_directives_end() const {
|
||||
return UsingDirectives.end();
|
||||
}
|
||||
|
||||
/// Init - This is used by the parser to implement scope caching.
|
||||
///
|
||||
void Init(Scope *Parent, unsigned ScopeFlags) {
|
||||
@ -265,6 +291,7 @@ public:
|
||||
if (Flags & BlockScope) BlockParent = this;
|
||||
if (Flags & TemplateParamScope) TemplateParamParent = this;
|
||||
DeclsInScope.clear();
|
||||
UsingDirectives.clear();
|
||||
Entity = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
@ -146,6 +147,13 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
|
||||
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
|
||||
|
||||
// UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
|
||||
// We want to keep it, unless it nominates same namespace.
|
||||
if (getKind() == Decl::UsingDirective) {
|
||||
return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() ==
|
||||
cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace();
|
||||
}
|
||||
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
|
||||
// For function declarations, we keep track of redeclarations.
|
||||
return FD->getPreviousDeclaration() == OldD;
|
||||
|
||||
@ -499,8 +499,9 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
|
||||
|
||||
// [FirstMatch, LastMatch) contains the set of declarations that
|
||||
// have the same name as this declaration. Determine where the
|
||||
// declaration D will be inserted into this range.
|
||||
if (D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
// declaration D will be inserted into this range.
|
||||
if (D->getKind() == Decl::UsingDirective ||
|
||||
D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
InsertPos = LastMatch;
|
||||
else if (Array[LastMatch-1]->getIdentifierNamespace() == Decl::IDNS_Tag)
|
||||
InsertPos = LastMatch - 1;
|
||||
@ -549,7 +550,9 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
|
||||
}
|
||||
|
||||
// Put this declaration into the appropriate slot.
|
||||
if (D->getIdentifierNamespace() == Decl::IDNS_Tag || Pos->second.empty())
|
||||
if (D->getKind() == Decl::UsingDirective ||
|
||||
D->getIdentifierNamespace() == Decl::IDNS_Tag
|
||||
|| Pos->second.empty())
|
||||
Pos->second.push_back(D);
|
||||
else if (Pos->second.back()->getIdentifierNamespace() == Decl::IDNS_Tag) {
|
||||
NamedDecl *TagD = Pos->second.back();
|
||||
@ -561,3 +564,12 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
|
||||
(*Map)[D->getDeclName()].push_back(D);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
|
||||
/// this context.
|
||||
DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const {
|
||||
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
|
||||
return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
|
||||
reinterpret_cast<udir_iterator>(Result.second));
|
||||
}
|
||||
|
||||
|
||||
@ -363,3 +363,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
||||
LanguageIDs Lang, bool Braces) {
|
||||
return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
|
||||
}
|
||||
|
||||
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
SourceLocation NamespaceLoc,
|
||||
SourceLocation IdentLoc,
|
||||
NamespaceDecl *Used,
|
||||
DeclContext *CommonAncestor) {
|
||||
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, IdentLoc,
|
||||
Used, CommonAncestor);
|
||||
}
|
||||
|
||||
|
||||
@ -203,6 +203,10 @@ void NamedDecl::EmitInRec(Serializer& S) const {
|
||||
case DeclarationName::CXXOperatorName:
|
||||
S.EmitInt(Name.getCXXOverloadedOperator());
|
||||
break;
|
||||
|
||||
case DeclarationName::CXXUsingDirective:
|
||||
// No extra data to emit
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,6 +246,10 @@ void NamedDecl::ReadInRec(Deserializer& D, ASTContext& C) {
|
||||
Name = C.DeclarationNames.getCXXOperatorName(Op);
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationName::CXXUsingDirective:
|
||||
Name = DeclarationName::getUsingDirectiveName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -95,10 +95,13 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
|
||||
case DeclarationNameExtra::CXXConversionFunction:
|
||||
return CXXConversionFunctionName;
|
||||
|
||||
case DeclarationNameExtra::CXXUsingDirective:
|
||||
return CXXUsingDirective;
|
||||
|
||||
default:
|
||||
// Check if we have one of the CXXOperator* enumeration values.
|
||||
if (getExtra()->ExtraKindOrNumArgs <
|
||||
DeclarationNameExtra::NUM_EXTRA_KINDS)
|
||||
DeclarationNameExtra::CXXUsingDirective)
|
||||
return CXXOperatorName;
|
||||
|
||||
return ObjCMultiArgSelector;
|
||||
@ -165,6 +168,8 @@ std::string DeclarationName::getAsString() const {
|
||||
Result += Type.getAsString();
|
||||
return Result;
|
||||
}
|
||||
case CXXUsingDirective:
|
||||
return "<using-directive>";
|
||||
}
|
||||
|
||||
assert(false && "Unexpected declaration name kind");
|
||||
@ -246,6 +251,17 @@ void DeclarationName::setFETokenInfo(void *T) {
|
||||
}
|
||||
}
|
||||
|
||||
DeclarationName DeclarationName::getUsingDirectiveName() {
|
||||
// Single instance of DeclarationNameExtra for using-directive
|
||||
static DeclarationNameExtra UDirExtra =
|
||||
{ DeclarationNameExtra::CXXUsingDirective };
|
||||
|
||||
uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra);
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
|
||||
return DeclarationName(Ptr);
|
||||
}
|
||||
|
||||
DeclarationNameTable::DeclarationNameTable() {
|
||||
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cstdio>
|
||||
@ -247,6 +248,14 @@ void StmtDumper::DumpDeclarator(Decl *D) {
|
||||
tagname = "<anonymous>";
|
||||
fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname);
|
||||
// FIXME: print tag bodies.
|
||||
} else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
|
||||
// print using-directive decl (e.g. "using namespace x;")
|
||||
const char *ns;
|
||||
if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
|
||||
ns = II->getName();
|
||||
else
|
||||
ns = "<anonymous>";
|
||||
fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns);
|
||||
} else {
|
||||
assert(0 && "Unexpected decl");
|
||||
}
|
||||
|
||||
@ -539,10 +539,6 @@ public:
|
||||
void CheckCXXDefaultArguments(FunctionDecl *FD);
|
||||
void CheckExtraCXXDefaultArguments(Declarator &D);
|
||||
|
||||
// FIXME: NamespaceNameOnly parameter is added temporarily
|
||||
// we will need a better way to specify lookup criteria for things
|
||||
// like template specializations, explicit template instantiations, etc.
|
||||
|
||||
Scope *getNonFieldDeclScope(Scope *S);
|
||||
|
||||
/// \name Name lookup
|
||||
@ -614,6 +610,9 @@ public:
|
||||
/// First is a single declaration (a Decl*), which may be NULL.
|
||||
SingleDecl,
|
||||
|
||||
/// First is a single declaration (an OverloadedFunctionDecl*).
|
||||
OverloadedDeclSingleDecl,
|
||||
|
||||
/// [First, Last) is an iterator range represented as opaque
|
||||
/// pointers used to reconstruct IdentifierResolver::iterators.
|
||||
OverloadedDeclFromIdResolver,
|
||||
@ -626,7 +625,13 @@ public:
|
||||
/// 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
|
||||
AmbiguousLookupStoresBasePaths,
|
||||
|
||||
/// [First, Last) is an iterator range represented as opaque
|
||||
/// pointers used to reconstruct new'ed Decl*[] array containing
|
||||
/// found ambiguous decls. LookupResult is owner of this array.
|
||||
AmbiguousLookupStoresDecls
|
||||
|
||||
} StoredKind;
|
||||
|
||||
/// The first lookup result, whose contents depend on the kind of
|
||||
@ -635,14 +640,14 @@ public:
|
||||
/// IdentifierResolver::iterator (if StoredKind ==
|
||||
/// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator
|
||||
/// (if StoredKind == OverloadedDeclFromDeclContext), or a
|
||||
/// BasePaths pointer (if StoredKind == AmbiguousLookup).
|
||||
/// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths).
|
||||
mutable uintptr_t First;
|
||||
|
||||
/// The last lookup result, whose contents depend on the kind of
|
||||
/// lookup result. This may be unused (if StoredKind ==
|
||||
/// 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).
|
||||
/// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths).
|
||||
mutable uintptr_t Last;
|
||||
|
||||
/// Context - The context in which we will build any
|
||||
@ -690,17 +695,25 @@ public:
|
||||
/// return d.x; // error: 'x' is found in two A subobjects (of B and C)
|
||||
/// }
|
||||
/// @endcode
|
||||
AmbiguousBaseSubobjects
|
||||
AmbiguousBaseSubobjects,
|
||||
|
||||
/// Name lookup results in an ambiguity because multiple definitions
|
||||
/// of entity that meet the lookup criteria were found in different
|
||||
/// declaration contexts.
|
||||
/// @code
|
||||
/// namespace A {
|
||||
/// int i;
|
||||
/// namespace B { int i; }
|
||||
/// int test() {
|
||||
/// using namespace B;
|
||||
/// return i; // error 'i' is found in namespace A and A::B
|
||||
/// }
|
||||
/// }
|
||||
/// @endcode
|
||||
AmbiguousReference
|
||||
};
|
||||
|
||||
static LookupResult CreateLookupResult(ASTContext &Context, Decl *D) {
|
||||
LookupResult Result;
|
||||
Result.StoredKind = SingleDecl;
|
||||
Result.First = reinterpret_cast<uintptr_t>(D);
|
||||
Result.Last = 0;
|
||||
Result.Context = &Context;
|
||||
return Result;
|
||||
}
|
||||
static LookupResult CreateLookupResult(ASTContext &Context, Decl *D);
|
||||
|
||||
static LookupResult CreateLookupResult(ASTContext &Context,
|
||||
IdentifierResolver::iterator F,
|
||||
@ -713,20 +726,37 @@ public:
|
||||
static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths,
|
||||
bool DifferentSubobjectTypes) {
|
||||
LookupResult Result;
|
||||
Result.StoredKind = AmbiguousLookup;
|
||||
Result.StoredKind = AmbiguousLookupStoresBasePaths;
|
||||
Result.First = reinterpret_cast<uintptr_t>(Paths);
|
||||
Result.Last = DifferentSubobjectTypes? 1 : 0;
|
||||
Result.Context = &Context;
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static LookupResult CreateLookupResult(ASTContext &Context,
|
||||
Iterator B, std::size_t Len) {
|
||||
Decl ** Array = new Decl*[Len];
|
||||
for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B)
|
||||
Array[Idx] = *B;
|
||||
LookupResult Result;
|
||||
Result.StoredKind = AmbiguousLookupStoresDecls;
|
||||
Result.First = reinterpret_cast<uintptr_t>(Array);
|
||||
Result.Last = reinterpret_cast<uintptr_t>(Array + Len);
|
||||
Result.Context = &Context;
|
||||
return Result;
|
||||
}
|
||||
|
||||
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; }
|
||||
bool isAmbiguous() const {
|
||||
return StoredKind == AmbiguousLookupStoresBasePaths ||
|
||||
StoredKind == AmbiguousLookupStoresDecls;
|
||||
}
|
||||
|
||||
/// @brief Allows conversion of a lookup result into a
|
||||
/// declaration, with the same behavior as getAsDecl.
|
||||
@ -786,6 +816,14 @@ public:
|
||||
iterator end();
|
||||
};
|
||||
|
||||
private:
|
||||
typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy;
|
||||
|
||||
std::pair<bool, LookupResult> CppLookupName(Scope *S, DeclarationName Name,
|
||||
LookupNameKind NameKind,
|
||||
bool RedeclarationOnly);
|
||||
|
||||
public:
|
||||
/// Determines whether D is a suitable lookup result according to the
|
||||
/// lookup criteria.
|
||||
bool isAcceptableLookupResult(Decl *D, LookupNameKind NameKind,
|
||||
@ -1171,6 +1209,8 @@ public:
|
||||
IdentifierInfo *NamespcName,
|
||||
AttributeList *AttrList);
|
||||
|
||||
void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir);
|
||||
|
||||
/// AddCXXDirectInitializerToDecl - This action is called immediately after
|
||||
/// ActOnDeclarator, when a C++ direct initializer is present.
|
||||
/// e.g: "int x(1);"
|
||||
|
||||
@ -42,6 +42,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, Scope *S,
|
||||
// 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.
|
||||
case LookupResult::AmbiguousReference:
|
||||
// FIXME: We need source location of identifier to diagnose more correctly.
|
||||
return 0;
|
||||
case LookupResult::Found:
|
||||
IIDecl = Result.getAsDecl();
|
||||
@ -2813,7 +2815,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
SearchDC = DC;
|
||||
// Look-up name inside 'foo::'.
|
||||
PrevDecl = dyn_cast_or_null<TagDecl>(
|
||||
LookupQualifiedName(DC, Name, LookupTagName).getAsDecl());
|
||||
LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
|
||||
|
||||
// A tag 'foo::bar' must already exist.
|
||||
if (PrevDecl == 0) {
|
||||
@ -2824,8 +2826,23 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
|
||||
} else if (Name) {
|
||||
// If this is a named struct, check to see if there was a previous forward
|
||||
// declaration or definition.
|
||||
Decl *D = LookupName(S, Name, LookupTagName);
|
||||
PrevDecl = dyn_cast_or_null<NamedDecl>(D);
|
||||
// FIXME: We're looking into outer scopes here, even when we
|
||||
// shouldn't be. Doing so can result in ambiguities that we
|
||||
// shouldn't be diagnosing.
|
||||
LookupResult R = LookupName(S, Name, LookupTagName);
|
||||
if (R.isAmbiguous()) {
|
||||
DiagnoseAmbiguousLookup(R, Name, NameLoc);
|
||||
// FIXME: This is not best way to recover from case like:
|
||||
//
|
||||
// struct S s;
|
||||
//
|
||||
// causes needless err_ovl_no_viable_function_in_init latter.
|
||||
Name = 0;
|
||||
PrevDecl = 0;
|
||||
Invalid = true;
|
||||
}
|
||||
else
|
||||
PrevDecl = dyn_cast_or_null<NamedDecl>(static_cast<Decl*>(R));
|
||||
|
||||
if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
|
||||
// FIXME: This makes sure that we ignore the contexts associated
|
||||
|
||||
@ -1433,21 +1433,59 @@ Sema::DeclTy *Sema::ActOnUsingDirective(Scope *S,
|
||||
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
|
||||
assert(NamespcName && "Invalid NamespcName.");
|
||||
assert(IdentLoc.isValid() && "Invalid NamespceName location.");
|
||||
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
|
||||
|
||||
// FIXME: This still requires lot more checks, and AST support.
|
||||
UsingDirectiveDecl *UDir = 0;
|
||||
|
||||
// Lookup namespace name.
|
||||
Decl *NS = LookupParsedName(S, &SS, NamespcName, LookupNamespaceName, false);
|
||||
|
||||
if (NS) {
|
||||
LookupResult R = LookupParsedName(S, &SS, NamespcName,
|
||||
LookupNamespaceName, false);
|
||||
if (R.isAmbiguous()) {
|
||||
DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc);
|
||||
return 0;
|
||||
}
|
||||
if (Decl *NS = R) {
|
||||
assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
|
||||
// C++ [namespace.udir]p1:
|
||||
// A using-directive specifies that the names in the nominated
|
||||
// namespace can be used in the scope in which the
|
||||
// using-directive appears after the using-directive. During
|
||||
// unqualified name lookup (3.4.1), the names appear as if they
|
||||
// were declared in the nearest enclosing namespace which
|
||||
// contains both the using-directive and the nominated
|
||||
// namespace. [Note: in this context, “contains” means “contains
|
||||
// directly or indirectly”. ]
|
||||
|
||||
// Find enclosing context containing both using-directive and
|
||||
// nominated namespace.
|
||||
DeclContext *CommonAncestor = cast<DeclContext>(NS);
|
||||
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
|
||||
CommonAncestor = CommonAncestor->getParent();
|
||||
|
||||
UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc,
|
||||
NamespcLoc, IdentLoc,
|
||||
cast<NamespaceDecl>(NS),
|
||||
CommonAncestor);
|
||||
PushUsingDirective(S, UDir);
|
||||
} else {
|
||||
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
|
||||
}
|
||||
|
||||
// FIXME: We ignore AttrList for now, and delete it to avoid leak.
|
||||
// FIXME: We ignore attributes for now.
|
||||
delete AttrList;
|
||||
return 0;
|
||||
return UDir;
|
||||
}
|
||||
|
||||
void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
|
||||
// If scope has associated entity, then using directive is at namespace
|
||||
// or translation unit scope. We add UsingDirectiveDecls, into
|
||||
// it's lookup structure.
|
||||
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
|
||||
Ctx->addDecl(UDir);
|
||||
else
|
||||
// Otherwise it is block-sope. using-directives will affect lookup
|
||||
// only to the end of scope.
|
||||
S->PushUsingDirective(UDir);
|
||||
}
|
||||
|
||||
/// AddCXXDirectInitializerToDecl - This action is called immediately after
|
||||
|
||||
@ -21,14 +21,90 @@
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy;
|
||||
typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet;
|
||||
typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy;
|
||||
|
||||
/// UsingDirAncestorCompare - Implements strict weak ordering of
|
||||
/// UsingDirectives. It orders them by address of its common ancestor.
|
||||
struct UsingDirAncestorCompare {
|
||||
|
||||
/// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
|
||||
bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const {
|
||||
return U->getCommonAncestor() < Ctx;
|
||||
}
|
||||
|
||||
/// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
|
||||
bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const {
|
||||
return Ctx < U->getCommonAncestor();
|
||||
}
|
||||
|
||||
/// @brief Compares UsingDirectiveDecl common ancestors.
|
||||
bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const {
|
||||
return U1->getCommonAncestor() < U2->getCommonAncestor();
|
||||
}
|
||||
};
|
||||
|
||||
/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs
|
||||
/// (ordered by common ancestors), found in namespace NS,
|
||||
/// including all found (recursively) in their nominated namespaces.
|
||||
void AddNamespaceUsingDirectives(DeclContext *NS,
|
||||
UsingDirectivesTy &UDirs,
|
||||
NamespaceSet &Visited) {
|
||||
DeclContext::udir_iterator I, End;
|
||||
|
||||
for (llvm::tie(I, End) = NS->getUsingDirectives(); I !=End; ++I) {
|
||||
UDirs.push_back(*I);
|
||||
std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
|
||||
NamespaceDecl *Nominated = (*I)->getNominatedNamespace();
|
||||
if (Visited.insert(Nominated).second)
|
||||
AddNamespaceUsingDirectives(Nominated, UDirs, /*ref*/ Visited);
|
||||
}
|
||||
}
|
||||
|
||||
/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S,
|
||||
/// including all found in the namespaces they nominate.
|
||||
static void AddScopeUsingDirectives(Scope *S, UsingDirectivesTy &UDirs) {
|
||||
NamespaceSet VisitedNS;
|
||||
|
||||
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
|
||||
|
||||
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(Ctx))
|
||||
VisitedNS.insert(NS);
|
||||
|
||||
AddNamespaceUsingDirectives(Ctx, UDirs, /*ref*/ VisitedNS);
|
||||
|
||||
} else {
|
||||
Scope::udir_iterator
|
||||
I = S->using_directives_begin(),
|
||||
End = S->using_directives_end();
|
||||
|
||||
for (; I != End; ++I) {
|
||||
UsingDirectiveDecl * UD = static_cast<UsingDirectiveDecl*>(*I);
|
||||
UDirs.push_back(UD);
|
||||
std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
|
||||
|
||||
NamespaceDecl *Nominated = UD->getNominatedNamespace();
|
||||
if (!VisitedNS.count(Nominated)) {
|
||||
VisitedNS.insert(Nominated);
|
||||
AddNamespaceUsingDirectives(Nominated, UDirs, /*ref*/ VisitedNS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// MaybeConstructOverloadSet - Name lookup has determined that the
|
||||
/// elements in [I, IEnd) have the name that we are looking for, and
|
||||
/// *I is a match for the namespace. This routine returns an
|
||||
/// appropriate Decl for name lookup, which may either be *I or an
|
||||
/// OverloadeFunctionDecl that represents the overloaded functions in
|
||||
/// OverloadedFunctionDecl that represents the overloaded functions in
|
||||
/// [I, IEnd).
|
||||
///
|
||||
/// The existance of this routine is temporary; users of LookupResult
|
||||
@ -69,6 +145,236 @@ MaybeConstructOverloadSet(ASTContext &Context,
|
||||
return *I;
|
||||
}
|
||||
|
||||
/// Merges together multiple LookupResults dealing with duplicated Decl's.
|
||||
static Sema::LookupResult
|
||||
MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) {
|
||||
typedef Sema::LookupResult LResult;
|
||||
typedef llvm::SmallVector<NamedDecl*, 3> DeclsVecTy;
|
||||
|
||||
DeclsVecTy FoundDecls;
|
||||
OverloadedFunctionDecl *FoundOverloaded = 0;
|
||||
|
||||
LookupResultsTy::iterator I = Results.begin(), End = Results.end();
|
||||
for (; I != End; ++I) {
|
||||
|
||||
switch (I->getKind()) {
|
||||
case LResult::NotFound:
|
||||
assert(false &&
|
||||
"Should be always successful name lookup result here.");
|
||||
break;
|
||||
|
||||
case LResult::AmbiguousReference:
|
||||
assert(false &&
|
||||
"Shouldn't get ambiguous reference here.");
|
||||
break;
|
||||
|
||||
case LResult::Found:
|
||||
FoundDecls.push_back(cast<NamedDecl>(I->getAsDecl()));
|
||||
break;
|
||||
|
||||
case LResult::AmbiguousBaseSubobjectTypes:
|
||||
case LResult::AmbiguousBaseSubobjects: {
|
||||
LResult Ambig = *I;
|
||||
// Free rest of OverloadedFunctionDecl, and other BasePaths
|
||||
// stored in LookupResults.
|
||||
#if 0
|
||||
// FIXME:
|
||||
// It should not happen, when we look start in each DeclContext only once.
|
||||
// See FIXME in CppLookupName.
|
||||
assert(Results.size() == 1 && "Multiple LookupResults should be not case "
|
||||
"here, since using-directives can't occur at class scope.");
|
||||
#else
|
||||
if (FoundOverloaded)
|
||||
FoundOverloaded->Destroy(Context);
|
||||
|
||||
for (++I; I != End; ++I) {
|
||||
if (I->getKind() == LResult::FoundOverloaded)
|
||||
cast<OverloadedFunctionDecl>(I->getAsDecl())->Destroy(Context);
|
||||
else if (BasePaths *Paths = I->getBasePaths())
|
||||
delete Paths;
|
||||
assert(I->getKind() != LResult::AmbiguousReference &&
|
||||
"Shouldn't get ambiguous reference here.");
|
||||
}
|
||||
#endif
|
||||
return Ambig;
|
||||
}
|
||||
|
||||
case LResult::FoundOverloaded:
|
||||
if (FoundOverloaded) {
|
||||
// We have one spare OverloadedFunctionDecl already, so we store
|
||||
// its function decls.
|
||||
#if 0
|
||||
FIXME: As soon as, stop call MaybeConstructOverloadSet here,
|
||||
which requires iterator::reference of type NamedDecl*, FoundDecls
|
||||
can be SmallVector<Decl*, >
|
||||
or when Lookup*Name() starts return NamedDecl's* instead of Decl's
|
||||
|
||||
this will work:
|
||||
std::copy(I->begin(), I->end(), std::back_inserter(FoundDecls));
|
||||
#else
|
||||
Sema::LookupResult::iterator OI = I->begin(), OEnd = I->end();
|
||||
for (; OI != OEnd; ++OI)
|
||||
FoundDecls.push_back(cast<NamedDecl>(*OI));
|
||||
#endif
|
||||
} else {
|
||||
// First time we found OverloadedFunctionDecl, we want to conserve
|
||||
// it, and possibly add other found Decls later.
|
||||
FoundOverloaded = cast<OverloadedFunctionDecl>(I->getAsDecl());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicated Decl pointing at same Decl, this might be case
|
||||
// for code like:
|
||||
//
|
||||
// namespace A { int i; }
|
||||
// namespace B { using namespace A; }
|
||||
// namespace C { using namespace A; }
|
||||
//
|
||||
// void foo() {
|
||||
// using namespace B;
|
||||
// using namespace C;
|
||||
// ++i; // finds A::i, from both namespace B and C at global scope
|
||||
// }
|
||||
//
|
||||
// C++ [namespace.qual].p3:
|
||||
// The same declaration found more than once is not an ambiguity
|
||||
// (because it is still a unique declaration).
|
||||
//
|
||||
// FIXME: At this point happens too, because we are doing redundant lookups.
|
||||
//
|
||||
DeclsVecTy::iterator DI = FoundDecls.begin(), DEnd = FoundDecls.end();
|
||||
// FIXME: Using SmallPtrSet instead would be better, once OverloadedFunctionDecl
|
||||
// dies.
|
||||
std::sort(DI, DEnd);
|
||||
DEnd = std::unique(DI, DEnd);
|
||||
|
||||
if (FoundOverloaded) {
|
||||
// We found overloaded functions result. We want to add any other
|
||||
// found decls, that are not already in FoundOverloaded, and are functions
|
||||
// or methods.
|
||||
OverloadedFunctionDecl::function_iterator
|
||||
FBegin = FoundOverloaded->function_begin(),
|
||||
FEnd = FoundOverloaded->function_end();
|
||||
// FIXME: This is O(n^2)!
|
||||
for (DI ; DI < DEnd; ++DI) {
|
||||
FunctionDecl *Fun = dyn_cast<FunctionDecl>(*DI);
|
||||
if (Fun && (std::find(FBegin, FEnd, Fun) != FEnd)) { /* Skip.*/ }
|
||||
else DEnd = std::remove(DI, DEnd, *DI);
|
||||
}
|
||||
|
||||
for (DI = FoundDecls.begin(); DI != DEnd; ++DI)
|
||||
FoundOverloaded->addOverload(cast<FunctionDecl>(*DI));
|
||||
|
||||
return LResult::CreateLookupResult(Context, FoundOverloaded);
|
||||
} else if (std::size_t FoundLen = std::distance(FoundDecls.begin(), DEnd)) {
|
||||
// We might found multiple TagDecls pointing at same definition.
|
||||
if (TagDecl *R = dyn_cast<TagDecl>(*FoundDecls.begin())) {
|
||||
TagDecl *Canonical = Context.getCanonicalDecl(R);
|
||||
DeclsVecTy::iterator RI = FoundDecls.begin(), REnd = DEnd;
|
||||
for (;;) {
|
||||
++RI;
|
||||
if (RI == REnd) {
|
||||
FoundLen = 1;
|
||||
break;
|
||||
}
|
||||
R = dyn_cast<TagDecl>(*RI);
|
||||
if (R && Canonical == Context.getCanonicalDecl(R)) { /* Skip */}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
// We might find FunctionDecls in two (or more) distinct DeclContexts.
|
||||
// 3.4.1.p1 ... Name lookup may associate more than one declaration with
|
||||
// a name if it finds the name to be a function name; the declarations
|
||||
// are said to form a set of overloaded functions (13.1).
|
||||
// Overload resolution (13.3) takes place after name lookup has succeeded.
|
||||
|
||||
Decl *D = MaybeConstructOverloadSet(Context, DI, DEnd);
|
||||
if ((FoundLen == 1) || isa<OverloadedFunctionDecl>(D))
|
||||
return LResult::CreateLookupResult(Context, D);
|
||||
|
||||
// Found multiple Decls, it is ambiguous reference.
|
||||
return LResult::CreateLookupResult(Context, FoundDecls.begin(), FoundLen);
|
||||
}
|
||||
|
||||
LResult Result = LResult::CreateLookupResult(Context, 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Retrieve the set of identifier namespaces that correspond to a
|
||||
// specific kind of name lookup.
|
||||
inline unsigned
|
||||
getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
|
||||
bool CPlusPlus) {
|
||||
unsigned IDNS = 0;
|
||||
switch (NameKind) {
|
||||
case Sema::LookupOrdinaryName:
|
||||
IDNS = Decl::IDNS_Ordinary;
|
||||
if (CPlusPlus)
|
||||
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
|
||||
break;
|
||||
|
||||
case Sema::LookupTagName:
|
||||
IDNS = Decl::IDNS_Tag;
|
||||
break;
|
||||
|
||||
case Sema::LookupMemberName:
|
||||
IDNS = Decl::IDNS_Member;
|
||||
if (CPlusPlus)
|
||||
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
|
||||
break;
|
||||
|
||||
case Sema::LookupNestedNameSpecifierName:
|
||||
case Sema::LookupNamespaceName:
|
||||
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
|
||||
break;
|
||||
}
|
||||
return IDNS;
|
||||
}
|
||||
|
||||
// Return qualified name for Decl D, like A::B::i, for i being member of
|
||||
// namespace A::B.
|
||||
std::string
|
||||
getQualifiedName(Decl *D) {
|
||||
std::vector<std::string> Names;
|
||||
std::string QualName;
|
||||
DeclContext *Ctx = D->getDeclContext();
|
||||
|
||||
if (Ctx->isFunctionOrMethod())
|
||||
return cast<NamedDecl>(D)->getNameAsString();
|
||||
|
||||
while (Ctx) {
|
||||
if (Ctx->isFunctionOrMethod()) {
|
||||
// FIXME: That probably is happend, because D was member of local
|
||||
// scope class/struct/union. How do we handle this case?
|
||||
break;
|
||||
}
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) {
|
||||
Names.push_back(ND->getNameAsString());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
Ctx = Ctx->getParent();
|
||||
}
|
||||
for (std::vector<std::string>::reverse_iterator I= Names.rbegin(), End =Names.rend(); I!=End; ++I)
|
||||
QualName += *I + "::";
|
||||
QualName += cast<NamedDecl>(D)->getNameAsString();
|
||||
return QualName;
|
||||
}
|
||||
|
||||
Sema::LookupResult
|
||||
Sema::LookupResult::CreateLookupResult(ASTContext &Context, Decl *D) {
|
||||
LookupResult Result;
|
||||
Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
|
||||
OverloadedDeclSingleDecl : SingleDecl;
|
||||
Result.First = reinterpret_cast<uintptr_t>(D);
|
||||
Result.Last = 0;
|
||||
Result.Context = &Context;
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// @brief Moves the name-lookup results from Other to this LookupResult.
|
||||
Sema::LookupResult
|
||||
Sema::LookupResult::CreateLookupResult(ASTContext &Context,
|
||||
@ -124,12 +430,16 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
|
||||
case SingleDecl:
|
||||
return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound;
|
||||
|
||||
case OverloadedDeclSingleDecl:
|
||||
case OverloadedDeclFromIdResolver:
|
||||
case OverloadedDeclFromDeclContext:
|
||||
return FoundOverloaded;
|
||||
|
||||
case AmbiguousLookup:
|
||||
case AmbiguousLookupStoresBasePaths:
|
||||
return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
|
||||
|
||||
case AmbiguousLookupStoresDecls:
|
||||
return AmbiguousReference;
|
||||
}
|
||||
|
||||
// We can't ever get here.
|
||||
@ -164,7 +474,11 @@ Decl *Sema::LookupResult::getAsDecl() const {
|
||||
reinterpret_cast<DeclContext::lookup_iterator>(First),
|
||||
reinterpret_cast<DeclContext::lookup_iterator>(Last));
|
||||
|
||||
case AmbiguousLookup:
|
||||
case OverloadedDeclSingleDecl:
|
||||
return reinterpret_cast<OverloadedFunctionDecl*>(First);
|
||||
|
||||
case AmbiguousLookupStoresDecls:
|
||||
case AmbiguousLookupStoresBasePaths:
|
||||
assert(false &&
|
||||
"Name lookup returned an ambiguity that could not be handled");
|
||||
break;
|
||||
@ -174,11 +488,11 @@ Decl *Sema::LookupResult::getAsDecl() const {
|
||||
}
|
||||
|
||||
/// @brief Retrieves the BasePaths structure describing an ambiguous
|
||||
/// name lookup.
|
||||
/// name lookup, or null.
|
||||
BasePaths *Sema::LookupResult::getBasePaths() const {
|
||||
assert((StoredKind == AmbiguousLookup) &&
|
||||
"getBasePaths can only be used on an ambiguous lookup");
|
||||
return reinterpret_cast<BasePaths *>(First);
|
||||
if (StoredKind == AmbiguousLookupStoresBasePaths)
|
||||
return reinterpret_cast<BasePaths *>(First);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sema::LookupResult::iterator::reference
|
||||
@ -187,13 +501,17 @@ Sema::LookupResult::iterator::operator*() const {
|
||||
case SingleDecl:
|
||||
return reinterpret_cast<Decl*>(Current);
|
||||
|
||||
case OverloadedDeclSingleDecl:
|
||||
return *reinterpret_cast<Decl**>(Current);
|
||||
|
||||
case OverloadedDeclFromIdResolver:
|
||||
return *IdentifierResolver::iterator::getFromOpaqueValue(Current);
|
||||
|
||||
case OverloadedDeclFromDeclContext:
|
||||
return *reinterpret_cast<DeclContext::lookup_iterator>(Current);
|
||||
|
||||
case AmbiguousLookup:
|
||||
|
||||
case AmbiguousLookupStoresDecls:
|
||||
case AmbiguousLookupStoresBasePaths:
|
||||
assert(false && "Cannot look into ambiguous lookup results");
|
||||
break;
|
||||
}
|
||||
@ -207,6 +525,12 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
|
||||
Current = reinterpret_cast<uintptr_t>((Decl*)0);
|
||||
break;
|
||||
|
||||
case OverloadedDeclSingleDecl: {
|
||||
Decl ** I = reinterpret_cast<Decl**>(Current);
|
||||
++I;
|
||||
Current = reinterpret_cast<uintptr_t>(I);
|
||||
}
|
||||
|
||||
case OverloadedDeclFromIdResolver: {
|
||||
IdentifierResolver::iterator I
|
||||
= IdentifierResolver::iterator::getFromOpaqueValue(Current);
|
||||
@ -223,7 +547,8 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
|
||||
break;
|
||||
}
|
||||
|
||||
case AmbiguousLookup:
|
||||
case AmbiguousLookupStoresDecls:
|
||||
case AmbiguousLookupStoresBasePaths:
|
||||
assert(false && "Cannot look into ambiguous lookup results");
|
||||
break;
|
||||
}
|
||||
@ -232,44 +557,228 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
|
||||
}
|
||||
|
||||
Sema::LookupResult::iterator Sema::LookupResult::begin() {
|
||||
assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result");
|
||||
return iterator(this, First);
|
||||
assert(!isAmbiguous() && "Lookup into an ambiguous result");
|
||||
if (StoredKind != OverloadedDeclSingleDecl)
|
||||
return iterator(this, First);
|
||||
OverloadedFunctionDecl * Ovl =
|
||||
reinterpret_cast<OverloadedFunctionDecl*>(First);
|
||||
return iterator(this, reinterpret_cast<uintptr_t>(&(*Ovl->function_begin())));
|
||||
}
|
||||
|
||||
Sema::LookupResult::iterator Sema::LookupResult::end() {
|
||||
assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result");
|
||||
return iterator(this, Last);
|
||||
assert(!isAmbiguous() && "Lookup into an ambiguous result");
|
||||
if (StoredKind != OverloadedDeclSingleDecl)
|
||||
return iterator(this, Last);
|
||||
OverloadedFunctionDecl * Ovl =
|
||||
reinterpret_cast<OverloadedFunctionDecl*>(First);
|
||||
return iterator(this, reinterpret_cast<uintptr_t>(&(*Ovl->function_end())));
|
||||
}
|
||||
|
||||
// Retrieve the set of identifier namespaces that correspond to a
|
||||
// specific kind of name lookup.
|
||||
inline unsigned
|
||||
getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
|
||||
bool CPlusPlus) {
|
||||
unsigned IDNS = 0;
|
||||
switch (NameKind) {
|
||||
case Sema::LookupOrdinaryName:
|
||||
IDNS = Decl::IDNS_Ordinary;
|
||||
if (CPlusPlus)
|
||||
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
|
||||
break;
|
||||
static bool isFunctionLocalScope(Scope *S) {
|
||||
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
|
||||
return Ctx->isFunctionOrMethod();
|
||||
return true;
|
||||
}
|
||||
|
||||
case Sema::LookupTagName:
|
||||
IDNS = Decl::IDNS_Tag;
|
||||
break;
|
||||
std::pair<bool, Sema::LookupResult>
|
||||
Sema::CppLookupName(Scope *S, DeclarationName Name,
|
||||
LookupNameKind NameKind, bool RedeclarationOnly) {
|
||||
assert(getLangOptions().CPlusPlus &&
|
||||
"Can perform only C++ lookup");
|
||||
unsigned IDNS
|
||||
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
|
||||
Scope *Initial = S;
|
||||
IdentifierResolver::iterator
|
||||
I = IdResolver.begin(Name),
|
||||
IEnd = IdResolver.end();
|
||||
|
||||
case Sema::LookupMemberName:
|
||||
IDNS = Decl::IDNS_Member;
|
||||
if (CPlusPlus)
|
||||
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
|
||||
break;
|
||||
|
||||
case Sema::LookupNestedNameSpecifierName:
|
||||
case Sema::LookupNamespaceName:
|
||||
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
|
||||
break;
|
||||
// First we lookup local scope.
|
||||
// We don't consider using-dirctives, as per 7.3.4.p1 [namespace.udir]
|
||||
// ...During unqualified name lookup (3.4.1), the names appear as if
|
||||
// they were declared in the nearest enclosing namespace which contains
|
||||
// both the using-directive and the nominated namespace.
|
||||
// [Note: in this context, “contains” means “contains directly or
|
||||
// indirectly”.
|
||||
//
|
||||
// For example:
|
||||
// namespace A { int i; }
|
||||
// void foo() {
|
||||
// int i;
|
||||
// {
|
||||
// using namespace A;
|
||||
// ++i; // finds local 'i', A::i appears at global scope
|
||||
// }
|
||||
// }
|
||||
//
|
||||
for (; S && isFunctionLocalScope(S); S = S->getParent()) {
|
||||
// Check whether the IdResolver has anything in this scope.
|
||||
for (; I != IEnd && S->isDeclScope(*I); ++I) {
|
||||
if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
|
||||
// We found something. Look for anything else in our scope
|
||||
// with this same name and in an acceptable identifier
|
||||
// namespace, so that we can construct an overload set if we
|
||||
// need to.
|
||||
IdentifierResolver::iterator LastI = I;
|
||||
for (++LastI; LastI != IEnd; ++LastI) {
|
||||
if (!S->isDeclScope(*LastI))
|
||||
break;
|
||||
}
|
||||
LookupResult Result =
|
||||
LookupResult::CreateLookupResult(Context, I, LastI);
|
||||
return std::make_pair(true, Result);
|
||||
}
|
||||
}
|
||||
// NB: Icky, we need to look in function scope, but we need to check its
|
||||
// parent DeclContext (instead S->getParent()) for member name lookup,
|
||||
// in case it is out of line method definition. Like in:
|
||||
//
|
||||
// class C {
|
||||
// int i;
|
||||
// void foo();
|
||||
// };
|
||||
//
|
||||
// C::foo() {
|
||||
// (void) i;
|
||||
// }
|
||||
//
|
||||
// FIXME: Maybe we should do member name lookup here instead?
|
||||
if (S->getEntity() && isFunctionLocalScope(S))
|
||||
break;
|
||||
}
|
||||
return IDNS;
|
||||
|
||||
// Collect UsingDirectiveDecls in all scopes, and recursivly all
|
||||
// nominated namespaces by those using-directives.
|
||||
// UsingDirectives are pushed to heap, in common ancestor pointer
|
||||
// value order.
|
||||
// FIXME: Cache this sorted list in Scope structure, and maybe
|
||||
// DeclContext, so we don't build it for each lookup!
|
||||
UsingDirectivesTy UDirs;
|
||||
for (Scope *SC = Initial; SC; SC = SC->getParent())
|
||||
AddScopeUsingDirectives(SC, UDirs);
|
||||
|
||||
// Sort heapified UsingDirectiveDecls.
|
||||
std::sort_heap(UDirs.begin(), UDirs.end());
|
||||
|
||||
// Lookup namespace scope, global scope, or possibly (CXX)Record DeclContext
|
||||
// for member name lookup.
|
||||
// Unqualified name lookup in C++ requires looking into scopes
|
||||
// that aren't strictly lexical, and therefore we walk through the
|
||||
// context as well as walking through the scopes.
|
||||
for (; S; S = S->getParent()) {
|
||||
LookupResultsTy LookupResults;
|
||||
bool LookedInCtx = false;
|
||||
|
||||
// Check whether the IdResolver has anything in this scope.
|
||||
for (; I != IEnd && S->isDeclScope(*I); ++I) {
|
||||
if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
|
||||
// We found something. Look for anything else in our scope
|
||||
// with this same name and in an acceptable identifier
|
||||
// namespace, so that we can construct an overload set if we
|
||||
// need to.
|
||||
IdentifierResolver::iterator LastI = I;
|
||||
for (++LastI; LastI != IEnd; ++LastI) {
|
||||
if (!S->isDeclScope(*LastI))
|
||||
break;
|
||||
}
|
||||
|
||||
// We store name lookup result, and continue trying to look into
|
||||
// associated context, and maybe namespaces nominated by
|
||||
// using-directives.
|
||||
LookupResults.push_back(
|
||||
LookupResult::CreateLookupResult(Context, I, LastI));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is an entity associated with this scope, it's a
|
||||
// DeclContext. We might need to perform qualified lookup into
|
||||
// it, or namespaces nominated by using-directives.
|
||||
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
|
||||
|
||||
if (Ctx && isa<TranslationUnitDecl>(Ctx)) {
|
||||
UsingDirectivesTy::const_iterator UI, UEnd;
|
||||
// For each UsingDirectiveDecl, which common ancestor is equal
|
||||
// to Ctx, we preform qualified name lookup into namespace nominated
|
||||
// by it.
|
||||
llvm::tie(UI, UEnd) =
|
||||
std::equal_range(UDirs.begin(), UDirs.end(), Ctx,
|
||||
UsingDirAncestorCompare());
|
||||
for (; UI != UEnd; ++UI) {
|
||||
// FIXME: We will have to ensure, that we won't consider
|
||||
// again using-directives during qualified name lookup!
|
||||
// (Once using-directives support for qualified name lookup gets
|
||||
// implemented).
|
||||
if (LookupResult R = LookupQualifiedName((*UI)->getNominatedNamespace(),
|
||||
Name, NameKind, RedeclarationOnly))
|
||||
LookupResults.push_back(R);
|
||||
}
|
||||
LookupResult Result;
|
||||
if ((Result = MergeLookupResults(Context, LookupResults)) ||
|
||||
RedeclarationOnly) {
|
||||
return std::make_pair(true, Result);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: We're performing redundant lookups here, where the
|
||||
// scope stack mirrors the semantic nested of classes and
|
||||
// namespaces. We can save some work by checking the lexical
|
||||
// scope against the semantic scope and avoiding any lookups
|
||||
// when they are the same.
|
||||
// FIXME: In some cases, we know that every name that could be
|
||||
// found by this qualified name lookup will also be on the
|
||||
// identifier chain. For example, inside a class without any
|
||||
// base classes, we never need to perform qualified lookup
|
||||
// because all of the members are on top of the identifier
|
||||
// chain. However, we cannot perform this optimization when the
|
||||
// lexical and semantic scopes don't line up, e.g., in an
|
||||
// out-of-line member definition.
|
||||
while (Ctx && Ctx->isFunctionOrMethod())
|
||||
Ctx = Ctx->getParent();
|
||||
while (Ctx && (Ctx->isNamespace() || Ctx->isRecord())) {
|
||||
LookedInCtx = true;
|
||||
// Look for declarations of this name in this scope.
|
||||
if (LookupResult R = LookupQualifiedName(Ctx, Name, NameKind,
|
||||
RedeclarationOnly))
|
||||
// We store that, to investigate futher, wheather reference
|
||||
// to this Decl is no ambiguous.
|
||||
LookupResults.push_back(R);
|
||||
|
||||
if (Ctx->isNamespace()) {
|
||||
// For each UsingDirectiveDecl, which common ancestor is equal
|
||||
// to Ctx, we preform qualified name lookup into namespace nominated
|
||||
// by it.
|
||||
UsingDirectivesTy::const_iterator UI, UEnd;
|
||||
llvm::tie(UI, UEnd) =
|
||||
std::equal_range(UDirs.begin(), UDirs.end(), Ctx,
|
||||
UsingDirAncestorCompare());
|
||||
for (; UI != UEnd; ++UI) {
|
||||
// FIXME: We will have to ensure, that we won't consider
|
||||
// again using-directives during qualified name lookup!
|
||||
// (Once using-directives support for qualified name lookup gets
|
||||
// implemented).
|
||||
LookupResult R = LookupQualifiedName((*UI)->getNominatedNamespace(),
|
||||
Name, NameKind,
|
||||
RedeclarationOnly);
|
||||
if (R)
|
||||
LookupResults.push_back(R);
|
||||
}
|
||||
}
|
||||
LookupResult Result;
|
||||
if ((Result = MergeLookupResults(Context, LookupResults)) ||
|
||||
(RedeclarationOnly && !Ctx->isTransparentContext())) {
|
||||
return std::make_pair(true, Result);
|
||||
}
|
||||
Ctx = Ctx->getParent();
|
||||
}
|
||||
|
||||
if (!(LookedInCtx || LookupResults.empty())) {
|
||||
// We didn't Performed lookup in Scope entity, so we return
|
||||
// result form IdentifierResolver.
|
||||
assert((LookupResults.size() == 1) && "Wrong size!");
|
||||
return std::make_pair(true, LookupResults.front());
|
||||
}
|
||||
}
|
||||
return std::make_pair(false, LookupResult());
|
||||
}
|
||||
|
||||
/// @brief Perform unqualified name lookup starting from a given
|
||||
@ -346,65 +855,11 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
|
||||
if ((*I)->isInIdentifierNamespace(IDNS))
|
||||
return LookupResult::CreateLookupResult(Context, *I);
|
||||
} else {
|
||||
unsigned IDNS
|
||||
= getIdentifierNamespacesFromLookupNameKind(NameKind,
|
||||
getLangOptions().CPlusPlus);
|
||||
|
||||
// Unqualified name lookup in C++ requires looking into scopes
|
||||
// that aren't strictly lexical, and therefore we walk through the
|
||||
// context as well as walking through the scopes.
|
||||
|
||||
// FIXME: does "true" for LookInParentCtx actually make sense?
|
||||
IdentifierResolver::iterator I = IdResolver.begin(Name),
|
||||
IEnd = IdResolver.end();
|
||||
for (; S; S = S->getParent()) {
|
||||
// Check whether the IdResolver has anything in this scope.
|
||||
for (; I != IEnd && S->isDeclScope(*I); ++I) {
|
||||
if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
|
||||
// We found something. Look for anything else in our scope
|
||||
// with this same name and in an acceptable identifier
|
||||
// namespace, so that we can construct an overload set if we
|
||||
// need to.
|
||||
IdentifierResolver::iterator LastI = I;
|
||||
for (++LastI; LastI != IEnd; ++LastI) {
|
||||
if (!S->isDeclScope(*LastI))
|
||||
break;
|
||||
}
|
||||
return LookupResult::CreateLookupResult(Context, I, LastI);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is an entity associated with this scope, it's a
|
||||
// DeclContext. We might need to perform qualified lookup into
|
||||
// it.
|
||||
// FIXME: We're performing redundant lookups here, where the
|
||||
// scope stack mirrors the semantic nested of classes and
|
||||
// namespaces. We can save some work by checking the lexical
|
||||
// scope against the semantic scope and avoiding any lookups
|
||||
// when they are the same.
|
||||
// FIXME: In some cases, we know that every name that could be
|
||||
// found by this qualified name lookup will also be on the
|
||||
// identifier chain. For example, inside a class without any
|
||||
// base classes, we never need to perform qualified lookup
|
||||
// because all of the members are on top of the identifier
|
||||
// chain. However, we cannot perform this optimization when the
|
||||
// lexical and semantic scopes don't line up, e.g., in an
|
||||
// out-of-line member definition.
|
||||
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
|
||||
while (Ctx && Ctx->isFunctionOrMethod())
|
||||
Ctx = Ctx->getParent();
|
||||
while (Ctx && (Ctx->isNamespace() || Ctx->isRecord())) {
|
||||
// Look for declarations of this name in this scope.
|
||||
if (LookupResult Result = LookupQualifiedName(Ctx, Name, NameKind,
|
||||
RedeclarationOnly))
|
||||
return Result;
|
||||
|
||||
if (RedeclarationOnly && !Ctx->isTransparentContext())
|
||||
return LookupResult::CreateLookupResult(Context, 0);
|
||||
|
||||
Ctx = Ctx->getParent();
|
||||
}
|
||||
}
|
||||
// Perform C++ unqualified name lookup.
|
||||
std::pair<bool, LookupResult> MaybeResult =
|
||||
CppLookupName(S, Name, NameKind, RedeclarationOnly);
|
||||
if (MaybeResult.first)
|
||||
return MaybeResult.second;
|
||||
}
|
||||
|
||||
// If we didn't find a use of this identifier, and if the identifier
|
||||
@ -612,6 +1067,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
|
||||
return LookupName(S, Name, NameKind, RedeclarationOnly);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Produce a diagnostic describing the ambiguity that resulted
|
||||
/// from name lookup.
|
||||
///
|
||||
@ -633,37 +1089,57 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
|
||||
SourceRange LookupRange) {
|
||||
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
|
||||
|
||||
BasePaths *Paths = Result.getBasePaths();
|
||||
if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
|
||||
QualType SubobjectType = Paths->front().back().Base->getType();
|
||||
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
|
||||
<< Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
|
||||
<< LookupRange;
|
||||
if (BasePaths *Paths = Result.getBasePaths())
|
||||
{
|
||||
if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
|
||||
QualType SubobjectType = Paths->front().back().Base->getType();
|
||||
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
|
||||
<< Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
|
||||
<< LookupRange;
|
||||
|
||||
DeclContext::lookup_iterator Found = Paths->front().Decls.first;
|
||||
while (isa<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic())
|
||||
++Found;
|
||||
DeclContext::lookup_iterator Found = Paths->front().Decls.first;
|
||||
while (isa<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic())
|
||||
++Found;
|
||||
|
||||
Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
|
||||
Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
|
||||
"Unhandled form of name lookup ambiguity");
|
||||
|
||||
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
|
||||
<< Name << LookupRange;
|
||||
|
||||
std::set<Decl *> DeclsPrinted;
|
||||
for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
|
||||
Path != PathEnd; ++Path) {
|
||||
Decl *D = *Path->Decls.first;
|
||||
if (DeclsPrinted.insert(D).second)
|
||||
Diag(D->getLocation(), diag::note_ambiguous_member_found);
|
||||
}
|
||||
|
||||
delete Paths;
|
||||
return true;
|
||||
} else if (Result.getKind() == LookupResult::AmbiguousReference) {
|
||||
|
||||
Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
|
||||
|
||||
Decl **DI = reinterpret_cast<Decl **>(Result.First),
|
||||
**DEnd = reinterpret_cast<Decl **>(Result.Last);
|
||||
|
||||
for (DI; DI != DEnd; ++DI)
|
||||
Diag((*DI)->getLocation(), diag::note_ambiguous_candidate)
|
||||
<< getQualifiedName(*DI);
|
||||
|
||||
delete[] reinterpret_cast<Decl **>(Result.First);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
|
||||
"Unhandled form of name lookup ambiguity");
|
||||
|
||||
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
|
||||
<< Name << LookupRange;
|
||||
|
||||
std::set<Decl *> DeclsPrinted;
|
||||
for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
|
||||
Path != PathEnd; ++Path) {
|
||||
Decl *D = *Path->Decls.first;
|
||||
if (DeclsPrinted.insert(D).second)
|
||||
Diag(D->getLocation(), diag::note_ambiguous_member_found);
|
||||
}
|
||||
|
||||
delete Paths;
|
||||
assert(false && "Unhandled form of name lookup ambiguity");
|
||||
|
||||
// We can't reach here.
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -130,3 +130,17 @@ void G::test_virtual_lookup() {
|
||||
a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}}
|
||||
static_f(0); // okay
|
||||
}
|
||||
|
||||
|
||||
struct HasMemberType1 {
|
||||
struct type { };
|
||||
};
|
||||
|
||||
struct HasMemberType2 {
|
||||
struct type { };
|
||||
};
|
||||
|
||||
struct HasAnotherMemberType : HasMemberType1, HasMemberType2 {
|
||||
// FIXME: this is well-formed, but we diagnose an ambiguity here
|
||||
// struct type { };
|
||||
};
|
||||
|
||||
74
clang/test/SemaCXX/using-directive.cpp
Normal file
74
clang/test/SemaCXX/using-directive.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// RUN: clang -fsyntax-only -verify %s
|
||||
|
||||
namespace A {
|
||||
short i; // expected-note{{candidate found by name lookup is 'A::i'}}
|
||||
namespace B {
|
||||
long i; // expected-note{{candidate found by name lookup is 'A::B::i'}}
|
||||
void f() {} // expected-note{{candidate function}}
|
||||
int k;
|
||||
namespace E {} // \
|
||||
expected-note{{candidate found by name lookup is 'A::B::E'}}
|
||||
}
|
||||
|
||||
namespace E {} // expected-note{{candidate found by name lookup is 'A::E'}}
|
||||
|
||||
namespace C {
|
||||
using namespace B;
|
||||
namespace E {} // \
|
||||
expected-note{{candidate found by name lookup is 'A::C::E'}}
|
||||
}
|
||||
|
||||
void f() {} // expected-note{{candidate function}}
|
||||
|
||||
class K1 {
|
||||
void foo();
|
||||
};
|
||||
|
||||
void local_i() {
|
||||
char i;
|
||||
using namespace A;
|
||||
using namespace B;
|
||||
int a[sizeof(i) == sizeof(char)? 1 : -1]; // okay
|
||||
}
|
||||
namespace B {
|
||||
int j;
|
||||
}
|
||||
|
||||
void ambig_i() {
|
||||
using namespace A;
|
||||
using namespace A::B;
|
||||
(void) i; // expected-error{{reference to 'i' is ambiguous}}
|
||||
f(); // expected-error{{call to 'f' is ambiguous}}
|
||||
(void) j; // okay
|
||||
using namespace C;
|
||||
(void) k; // okay
|
||||
using namespace E; // expected-error{{reference to 'E' is ambiguous}}
|
||||
}
|
||||
|
||||
struct K2 {}; // expected-note{{candidate found by name lookup is 'A::K2'}}
|
||||
}
|
||||
|
||||
struct K2 {}; // expected-note{{candidate found by name lookup is 'K2'}}
|
||||
|
||||
using namespace A;
|
||||
|
||||
void K1::foo() {} // okay
|
||||
|
||||
// FIXME: Do we want err_ovl_no_viable_function_in_init here?
|
||||
struct K2 k2; // expected-error{{reference to 'K2' is ambiguous}} \
|
||||
expected-error{{no matching constructor}}
|
||||
|
||||
// FIXME: This case is incorrectly diagnosed!
|
||||
//K2 k3;
|
||||
|
||||
|
||||
class X {
|
||||
// FIXME: produce a suitable error message for this
|
||||
using namespace A; // expected-error{{expected unqualified-id}}
|
||||
};
|
||||
|
||||
namespace N {
|
||||
// FIXME: both of these should work, but they currently cause an ambiguity.
|
||||
// struct K2;
|
||||
// struct K2 { };
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user