Instead of hanging a using declaration's target decls directly off the using

decl, create shadow declarations and put them in scope like normal.
Work in progress.

llvm-svn: 89048
This commit is contained in:
John McCall 2009-11-17 05:59:44 +00:00
parent d6ea9028e7
commit 3f746828d7
13 changed files with 230 additions and 63 deletions

View File

@ -79,9 +79,11 @@ public:
/// namespaces, labels, tags, members and ordinary
/// identifiers. These are meant as bitmasks, so that searches in
/// C++ can look into the "tag" namespace during ordinary lookup. We
/// use additional namespaces for Objective-C entities. We also
/// put C++ friend declarations (of previously-undeclared entities) in
/// shadow namespaces.
/// use additional namespaces for Objective-C entities. We also put
/// C++ friend declarations (of previously-undeclared entities) in
/// shadow namespaces, and 'using' declarations (as opposed to their
/// implicit shadow declarations) can be found in their own
/// namespace.
enum IdentifierNamespace {
IDNS_Label = 0x1,
IDNS_Tag = 0x2,
@ -91,7 +93,8 @@ public:
IDNS_ObjCImplementation = 0x20,
IDNS_ObjCCategoryImpl = 0x40,
IDNS_OrdinaryFriend = 0x80,
IDNS_TagFriend = 0x100
IDNS_TagFriend = 0x100,
IDNS_Using = 0x200
};
/// ObjCDeclQualifier - Qualifier used on types in method declarations

View File

@ -1644,6 +1644,56 @@ public:
static bool classof(const NamespaceAliasDecl *D) { return true; }
};
/// UsingShadowDecl - Represents a shadow declaration introduced into
/// a scope by a (resolved) using declaration. For example,
///
/// namespace A {
/// void foo();
/// }
/// namespace B {
/// using A::foo(); // <- a UsingDecl
/// // Also creates a UsingShadowDecl for A::foo in B
/// }
///
class UsingShadowDecl : public NamedDecl {
/// The referenced declaration.
NamedDecl *Underlying;
/// The using declaration which introduced this decl.
UsingDecl *Using;
UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using,
NamedDecl *Target)
: NamedDecl(UsingShadow, DC, Loc, Target->getDeclName()),
Underlying(Target), Using(Using) {
IdentifierNamespace = Target->getIdentifierNamespace();
setImplicit();
}
public:
static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation Loc, UsingDecl *Using,
NamedDecl *Target) {
return new (C) UsingShadowDecl(DC, Loc, Using, Target);
}
/// Gets the underlying declaration which has been brought into the
/// local scope.
NamedDecl *getTargetDecl() const {
return Underlying;
}
/// Gets the using declaration to which this declaration is tied.
UsingDecl *getUsingDecl() const {
return Using;
}
static bool classof(const Decl *D) {
return D->getKind() == Decl::UsingShadow;
}
static bool classof(const UsingShadowDecl *D) { return true; }
};
/// UsingDecl - Represents a C++ using-declaration. For example:
/// using someNameSpace::someIdentifier;
class UsingDecl : public NamedDecl {
@ -1651,29 +1701,26 @@ class UsingDecl : public NamedDecl {
/// preceding the declaration name.
SourceRange NestedNameRange;
/// \brief The source location of the target declaration name.
SourceLocation TargetNameLocation;
/// \brief The source location of the "using" location itself.
SourceLocation UsingLocation;
/// \brief Target declaration.
NamedDecl* TargetDecl;
/// \brief Target nested name specifier.
NestedNameSpecifier* TargetNestedNameDecl;
NestedNameSpecifier* TargetNestedName;
/// \brief The collection of shadow declarations associated with
/// this using declaration. This set can change as a class is
/// processed.
llvm::SmallPtrSet<UsingShadowDecl*, 8> Shadows;
// \brief Has 'typename' keyword.
bool IsTypeName;
UsingDecl(DeclContext *DC, SourceLocation L, SourceRange NNR,
SourceLocation TargetNL, SourceLocation UL, NamedDecl* Target,
NestedNameSpecifier* TargetNNS, bool IsTypeNameArg)
: NamedDecl(Decl::Using, DC, L, Target->getDeclName()),
NestedNameRange(NNR), TargetNameLocation(TargetNL),
UsingLocation(UL), TargetDecl(Target),
TargetNestedNameDecl(TargetNNS), IsTypeName(IsTypeNameArg) {
this->IdentifierNamespace = TargetDecl->getIdentifierNamespace();
SourceLocation UL, NestedNameSpecifier* TargetNNS,
DeclarationName Name, bool IsTypeNameArg)
: NamedDecl(Decl::Using, DC, L, Name),
NestedNameRange(NNR), UsingLocation(UL), TargetNestedName(TargetNNS),
IsTypeName(IsTypeNameArg) {
}
public:
@ -1681,28 +1728,37 @@ public:
/// preceding the namespace name.
SourceRange getNestedNameRange() { return NestedNameRange; }
/// \brief Returns the source location of the target declaration name.
SourceLocation getTargetNameLocation() { return TargetNameLocation; }
/// \brief Returns the source location of the "using" location itself.
SourceLocation getUsingLocation() { return UsingLocation; }
/// \brief getTargetDecl - Returns target specified by using-decl.
NamedDecl *getTargetDecl() { return TargetDecl; }
const NamedDecl *getTargetDecl() const { return TargetDecl; }
/// \brief Get target nested name declaration.
NestedNameSpecifier* getTargetNestedNameDecl() {
return TargetNestedNameDecl;
return TargetNestedName;
}
/// isTypeName - Return true if using decl has 'typename'.
bool isTypeName() const { return IsTypeName; }
typedef llvm::SmallPtrSet<UsingShadowDecl*,8>::const_iterator shadow_iterator;
shadow_iterator shadow_begin() const { return Shadows.begin(); }
shadow_iterator shadow_end() const { return Shadows.end(); }
void addShadowDecl(UsingShadowDecl *S) {
assert(S->getUsingDecl() == this);
if (!Shadows.insert(S)) {
assert(false && "declaration already in set");
}
}
void removeShadowDecl(UsingShadowDecl *S) {
assert(S->getUsingDecl() == this);
if (!Shadows.erase(S)) {
assert(false && "declaration not in set");
}
}
static UsingDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
SourceLocation UL, NamedDecl* Target,
NestedNameSpecifier* TargetNNS, bool IsTypeNameArg);
SourceLocation IdentL, SourceRange NNR, SourceLocation UsingL,
NestedNameSpecifier* TargetNNS, DeclarationName Name, bool IsTypeNameArg);
static bool classof(const Decl *D) {
return D->getKind() == Decl::Using;

View File

@ -110,6 +110,7 @@ ABSTRACT_DECL(Named, Decl)
DECL(TemplateTemplateParm, TemplateDecl)
DECL(Using, NamedDecl)
DECL(UnresolvedUsing, NamedDecl)
DECL(UsingShadow, NamedDecl)
DECL(ObjCMethod, NamedDecl)
DECL(ObjCContainer, NamedDecl)
DECL(ObjCCategory, ObjCContainerDecl)

View File

@ -289,6 +289,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
return true;
if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD))
return cast<UsingShadowDecl>(this)->getTargetDecl() ==
cast<UsingShadowDecl>(OldD)->getTargetDecl();
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
@ -308,7 +312,7 @@ bool NamedDecl::hasLinkage() const {
NamedDecl *NamedDecl::getUnderlyingDecl() {
NamedDecl *ND = this;
while (true) {
if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
ND = UD->getTargetDecl();
else if (ObjCCompatibleAliasDecl *AD
= dyn_cast<ObjCCompatibleAliasDecl>(ND))

View File

@ -97,7 +97,7 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isFunctionOrFunctionTemplate() const {
if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
@ -189,10 +189,11 @@ ASTContext &Decl::getASTContext() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
default:
if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
return IDNS_Ordinary;
assert(0 && "Unknown decl kind!");
case Function:
case CXXMethod:
case CXXConstructor:
case CXXDestructor:
case CXXConversion:
case OverloadedFunction:
case Typedef:
case EnumConstant:
@ -200,8 +201,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
case Using:
case UnresolvedUsing:
case ObjCMethod:
case ObjCContainer:
case ObjCCategory:
@ -210,6 +209,15 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCompatibleAlias:
return IDNS_Ordinary;
case UsingShadow:
return 0; // we'll actually overwrite this later
case UnresolvedUsing:
return IDNS_Tag | IDNS_Ordinary | IDNS_Using;
case Using:
return IDNS_Using;
case ObjCProtocol:
return IDNS_ObjCProtocol;
@ -256,6 +264,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplatePartialSpecialization:
return 0;
}
return 0;
}
void Decl::addAttr(Attr *NewAttr) {

View File

@ -914,11 +914,10 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
}
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
SourceLocation UL, NamedDecl* Target,
NestedNameSpecifier* TargetNNS, bool IsTypeNameArg) {
return new (C) UsingDecl(DC, L, NNR, TargetNL, UL, Target,
TargetNNS, IsTypeNameArg);
SourceLocation L, SourceRange NNR, SourceLocation UL,
NestedNameSpecifier* TargetNNS, DeclarationName Name,
bool IsTypeNameArg) {
return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg);
}
UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC,

View File

@ -73,6 +73,7 @@ namespace {
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
};
}
@ -825,7 +826,7 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getTargetNestedNameDecl()->print(Out, Policy);
Out << D->getTargetDecl()->getNameAsString();
Out << D->getNameAsString();
}
void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
@ -833,3 +834,7 @@ void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
D->getTargetNestedNameSpecifier()->print(Out, Policy);
Out << D->getTargetName().getAsString();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
// ignore
}

View File

@ -1197,6 +1197,7 @@ public:
LookupKind(LookupKind),
IDNS(0),
Redecl(Redecl != NotForRedeclaration),
HideTags(true),
Diagnose(Redecl == NotForRedeclaration)
{}
@ -1212,6 +1213,7 @@ public:
LookupKind(Other.LookupKind),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
HideTags(Other.HideTags),
Diagnose(false)
{}
@ -1235,6 +1237,12 @@ public:
return Redecl;
}
/// Sets whether tag declarations should be hidden by non-tag
/// declarations during resolution. The default is true.
void setHideTags(bool Hide) {
HideTags = Hide;
}
/// The identifier namespace of this lookup. This information is
/// private to the lookup routines.
unsigned getIdentifierNamespace() const {
@ -1441,6 +1449,10 @@ public:
unsigned IDNS; // ill-defined until set by lookup
bool Redecl;
/// \brief True if tag declarations should be hidden if non-tags
/// are present
bool HideTags;
bool Diagnose;
};
@ -2007,7 +2019,8 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *Ident);
NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc,
NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,

View File

@ -198,7 +198,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
return;
// Look through using declarations.
if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration))
MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
CurContext);

View File

@ -2835,7 +2835,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
}
DeclarationName TargetName = GetNameFromUnqualifiedId(Name);
NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS,
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
Name.getSourceRange().getBegin(),
TargetName, AttrList, IsTypeName);
if (UD) {
@ -2846,7 +2846,34 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
return DeclPtrTy::make(UD);
}
NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
/// Builds a shadow declaration corresponding to a 'using' declaration.
static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S,
AccessSpecifier AS,
UsingDecl *UD, NamedDecl *Orig) {
// FIXME: diagnose hiding, collisions
// If we resolved to another shadow declaration, just coalesce them.
if (isa<UsingShadowDecl>(Orig)) {
Orig = cast<UsingShadowDecl>(Orig)->getTargetDecl();
assert(!isa<UsingShadowDecl>(Orig) && "nested shadow declaration");
}
UsingShadowDecl *Shadow
= UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext,
UD->getLocation(), UD, Orig);
UD->addShadowDecl(Shadow);
if (S)
SemaRef.PushOnScopeChains(Shadow, S);
else
SemaRef.CurContext->addDecl(Shadow);
Shadow->setAccess(AS);
return Shadow;
}
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
@ -2898,8 +2925,12 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
}
}
// Lookup target name.
// Look up the target name. Unlike most lookups, we do not want to
// hide tag declarations: tag names are visible through the using
// declaration even if hidden by ordinary names.
LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName);
R.setHideTags(false);
LookupQualifiedName(R, LookupContext);
if (R.empty()) {
@ -2908,24 +2939,33 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
return 0;
}
// FIXME: handle ambiguity?
NamedDecl *ND = R.getAsSingleDecl(Context);
if (R.isAmbiguous())
return 0;
if (IsTypeName && !isa<TypeDecl>(ND)) {
if (IsTypeName &&
(R.getResultKind() != LookupResult::Found
|| !isa<TypeDecl>(R.getFoundDecl()))) {
Diag(IdentLoc, diag::err_using_typename_non_type);
return 0;
}
// C++0x N2914 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
if (isa<NamespaceDecl>(ND)) {
if (R.getResultKind() == LookupResult::Found
&& isa<NamespaceDecl>(R.getFoundDecl())) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
<< SS.getRange();
return 0;
}
return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
ND->getLocation(), UsingLoc, ND, NNS, IsTypeName);
UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc,
SS.getRange(), UsingLoc, NNS, Name,
IsTypeName);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
BuildUsingShadowDecl(*this, S, AS, UD, *I);
return UD;
}
/// getNamespaceDecl - Returns the namespace a decl represents. If the decl

View File

@ -297,7 +297,7 @@ void Sema::LookupResult::resolveKind() {
// wherever the object, function, or enumerator name is visible.
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
if (HasTag && !Ambiguous && (HasFunction || HasNonFunction))
if (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction))
Decls[UniqueTagIndex] = Decls[--N];
Decls.set_size(N);

View File

@ -788,10 +788,46 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
if (!InstD)
return SemaRef.ExprError();
// If we instantiated an UnresolvedUsingDecl and got back an UsingDecl,
// we need to get the underlying decl.
// FIXME: Is this correct? Maybe FindInstantiatedDecl should do this?
InstD = InstD->getUnderlyingDecl();
// Flatten using declarations into their shadow declarations.
if (isa<UsingDecl>(InstD)) {
UsingDecl *UD = cast<UsingDecl>(InstD);
bool HasNonFunction = false;
llvm::SmallVector<NamedDecl*, 8> Decls;
for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
E = UD->shadow_end(); I != E; ++I) {
NamedDecl *TD = (*I)->getTargetDecl();
if (!TD->isFunctionOrFunctionTemplate())
HasNonFunction = true;
Decls.push_back(TD);
}
if (Decls.empty())
return SemaRef.ExprError();
if (Decls.size() == 1)
InstD = Decls[0];
else if (!HasNonFunction) {
OverloadedFunctionDecl *OFD
= OverloadedFunctionDecl::Create(SemaRef.Context,
UD->getDeclContext(),
UD->getDeclName());
for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Decls.begin(),
E = Decls.end(); I != E; ++I)
if (isa<FunctionDecl>(*I))
OFD->addOverload(cast<FunctionDecl>(*I));
else
OFD->addOverload(cast<FunctionTemplateDecl>(*I));
InstD = OFD;
} else {
// FIXME
assert(false && "using declaration resolved to mixed set");
return SemaRef.ExprError();
}
}
CXXScopeSpec SS;
NestedNameSpecifier *Qualifier = 0;

View File

@ -1019,9 +1019,9 @@ TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
SS.setScopeRep(NNS);
NamedDecl *UD =
SemaRef.BuildUsingDeclaration(D->getLocation(), SS,
D->getTargetNameLocation(),
D->getTargetName(), 0, D->isTypeName());
SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
D->getLocation(), SS, D->getTargetNameLocation(),
D->getDeclName(), 0, D->isTypeName());
if (UD)
SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
D);