Semantic analysis, ASTs, and unqualified name lookup support for C++

using directives, from Piotr Rak!

llvm-svn: 63646
This commit is contained in:
Douglas Gregor 2009-02-03 19:21:40 +00:00
parent 2f219b0770
commit 889ceb752d
20 changed files with 1027 additions and 159 deletions

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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,

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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;

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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>;

View File

@ -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");
}

View File

@ -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);"

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 { };
};

View 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 { };
}