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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89048 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a6996a4..bdc8047 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -289,6 +289,10 @@
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 @@
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))
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6cfdcdd..da3b19d 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -97,7 +97,7 @@
}
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 @@
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 @@
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
- case Using:
- case UnresolvedUsing:
case ObjCMethod:
case ObjCContainer:
case ObjCCategory:
@@ -210,6 +209,15 @@
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 @@
case ClassTemplatePartialSpecialization:
return 0;
}
+
+ return 0;
}
void Decl::addAttr(Attr *NewAttr) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 3768796..520206d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -914,11 +914,10 @@
}
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,
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index b88a971..199ed35 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -73,6 +73,7 @@
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
};
}
@@ -825,7 +826,7 @@
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 @@
D->getTargetNestedNameSpecifier()->print(Out, Policy);
Out << D->getTargetName().getAsString();
}
+
+void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ // ignore
+}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index acf52c9..fea6f80 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1197,6 +1197,7 @@
LookupKind(LookupKind),
IDNS(0),
Redecl(Redecl != NotForRedeclaration),
+ HideTags(true),
Diagnose(Redecl == NotForRedeclaration)
{}
@@ -1212,6 +1213,7 @@
LookupKind(Other.LookupKind),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
+ HideTags(Other.HideTags),
Diagnose(false)
{}
@@ -1235,6 +1237,12 @@
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 @@
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 @@
SourceLocation IdentLoc,
IdentifierInfo *Ident);
- NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc,
+ NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
+ SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 84262a4..de30441 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -198,7 +198,7 @@
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);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9ba03a9..698d81e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2835,7 +2835,7 @@
}
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 @@
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,
@@ -2880,7 +2907,7 @@
// anonymous union that is a member of a base class of the class being
// defined, or shall refer to an enumerator for an enumeration type that is
// a member of a base class of the class being defined.
-
+
CXXRecordDecl *LookupRD = dyn_cast<CXXRecordDecl>(LookupContext);
if (!LookupRD || !RD->isDerivedFrom(LookupRD)) {
Diag(SS.getRange().getBegin(),
@@ -2898,8 +2925,12 @@
}
}
- // 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 @@
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
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1c7dce0..58b95fc6 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -297,7 +297,7 @@
// 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);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 721bfb9..58fe59e 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -788,10 +788,46 @@
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;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a37f3a2..208352f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1019,9 +1019,9 @@
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);