Incremental progress on using declarations. Split UnresolvedUsingDecl into
two classes, one for typenames and one for values; this seems to have some
support from Doug if not necessarily from the extremely-vague-on-this-point
standard. Track the location of the 'typename' keyword in a using-typename
decl. Make a new lookup result for unresolved values and deal with it in
most places.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89184 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b3db88a..35a7d78 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1110,6 +1110,11 @@
/// functions into an OverloadedFunctionDecl.
FoundOverloaded,
+ /// @brief Name lookup found an unresolvable value declaration
+ /// and cannot yet complete. This only happens in C++ dependent
+ /// contexts with dependent using declarations.
+ FoundUnresolvedValue,
+
/// @brief Name lookup results in an ambiguity; use
/// getAmbiguityKind to figure out what kind of ambiguity
/// we have.
@@ -1417,6 +1422,7 @@
assert(ResultKind != NotFound || Decls.size() == 0);
assert(ResultKind != Found || Decls.size() == 1);
assert(ResultKind == NotFound || ResultKind == Found ||
+ ResultKind == FoundUnresolvedValue ||
(ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
|| Decls.size() > 1);
assert((Paths != NULL) == (ResultKind == Ambiguous &&
@@ -2017,7 +2023,9 @@
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
- bool IsTypeName);
+ bool IsInstantiation,
+ bool IsTypeName,
+ SourceLocation TypenameLoc);
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
@@ -2025,7 +2033,8 @@
const CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName);
+ bool IsTypeName,
+ SourceLocation TypenameLoc);
/// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2228b41..3f20498 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -94,6 +94,7 @@
switch (Result.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
return 0;
case LookupResult::Ambiguous:
@@ -166,6 +167,10 @@
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
T = Context.getObjCInterfaceType(IDecl);
+ } else if (UnresolvedUsingTypenameDecl *UUDecl =
+ dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
+ // FIXME: preserve source structure information.
+ T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II);
} else {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
@@ -2446,7 +2451,9 @@
}
static bool isUsingDecl(Decl *D) {
- return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D);
+ return isa<UsingDecl>(D) ||
+ isa<UnresolvedUsingTypenameDecl>(D) ||
+ isa<UnresolvedUsingValueDecl>(D);
}
/// \brief Data used with FindOverriddenMethod
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 4f04bd2..cb18064 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2809,7 +2809,8 @@
const CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName) {
+ bool IsTypeName,
+ SourceLocation TypenameLoc) {
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
switch (Name.getKind()) {
@@ -2837,7 +2838,9 @@
DeclarationName TargetName = GetNameFromUnqualifiedId(Name);
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
Name.getSourceRange().getBegin(),
- TargetName, AttrList, IsTypeName);
+ TargetName, AttrList,
+ /* IsInstantiation */ false,
+ IsTypeName, TypenameLoc);
if (UD) {
PushOnScopeChains(UD, S);
UD->setAccess(AS);
@@ -2872,13 +2875,20 @@
return Shadow;
}
+/// Builds a using declaration.
+///
+/// \param IsInstantiation - Whether this call arises from an
+/// instantiation of an unresolved using declaration. We treat
+/// the lookup differently for these declarations.
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
- bool IsTypeName) {
+ bool IsInstantiation,
+ bool IsTypeName,
+ SourceLocation TypenameLoc) {
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
assert(IdentLoc.isValid() && "Invalid TargetName location.");
@@ -2895,9 +2905,16 @@
DeclContext *LookupContext = computeDeclContext(SS);
if (!LookupContext) {
- return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc,
- SS.getRange(), NNS,
- IdentLoc, Name, IsTypeName);
+ if (IsTypeName) {
+ return UnresolvedUsingTypenameDecl::Create(Context, CurContext,
+ UsingLoc, TypenameLoc,
+ SS.getRange(), NNS,
+ IdentLoc, Name);
+ } else {
+ return UnresolvedUsingValueDecl::Create(Context, CurContext,
+ UsingLoc, SS.getRange(), NNS,
+ IdentLoc, Name);
+ }
}
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
@@ -2929,7 +2946,12 @@
// 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);
+
+ // We don't hide tags behind ordinary decls if we're in a
+ // non-dependent context, but in a dependent context, this is
+ // important for the stability of two-phase lookup.
+ if (!IsInstantiation)
+ R.setHideTags(false);
LookupQualifiedName(R, LookupContext);
@@ -2942,11 +2964,27 @@
if (R.isAmbiguous())
return 0;
- if (IsTypeName &&
- (R.getResultKind() != LookupResult::Found
- || !isa<TypeDecl>(R.getFoundDecl()))) {
- Diag(IdentLoc, diag::err_using_typename_non_type);
- return 0;
+ if (IsTypeName) {
+ // If we asked for a typename and got a non-type decl, error out.
+ if (R.getResultKind() != LookupResult::Found
+ || !isa<TypeDecl>(R.getFoundDecl())) {
+ Diag(IdentLoc, diag::err_using_typename_non_type);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ Diag((*I)->getUnderlyingDecl()->getLocation(),
+ diag::note_using_decl_target);
+ return 0;
+ }
+ } else {
+ // If we asked for a non-typename and we got a type, error out,
+ // but only if this is an instantiation of an unresolved using
+ // decl. Otherwise just silently find the type name.
+ if (IsInstantiation &&
+ R.getResultKind() == LookupResult::Found &&
+ isa<TypeDecl>(R.getFoundDecl())) {
+ Diag(IdentLoc, diag::err_using_dependent_value_is_type);
+ Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target);
+ return 0;
+ }
}
// C++0x N2914 [namespace.udecl]p6:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2e33200..43f150f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -977,7 +977,7 @@
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
false, false, SS);
- else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D))
+ else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(D))
return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
/*TypeDependent=*/true,
/*ValueDependent=*/true, SS);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index d736d42..f37fb8b 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -245,7 +245,12 @@
unsigned N = Decls.size();
// Fast case: no possible ambiguity.
- if (N <= 1) return;
+ if (N == 0) return;
+ if (N == 1) {
+ if (isa<UnresolvedUsingValueDecl>(Decls[0]))
+ ResultKind = FoundUnresolvedValue;
+ return;
+ }
// Don't do any extra resolution if we've already resolved as ambiguous.
if (ResultKind == Ambiguous) return;
@@ -254,6 +259,7 @@
bool Ambiguous = false;
bool HasTag = false, HasFunction = false, HasNonFunction = false;
+ bool HasUnresolved = false;
unsigned UniqueTagIndex = 0;
@@ -266,12 +272,15 @@
// If it's not unique, pull something off the back (and
// continue at this index).
Decls[I] = Decls[--N];
- } else if (isa<UnresolvedUsingDecl>(D)) {
- // FIXME: support unresolved using decls
+ } else if (isa<UnresolvedUsingValueDecl>(D)) {
+ // FIXME: support unresolved using value declarations
Decls[I] = Decls[--N];
} else {
// Otherwise, do some decl type analysis and then continue.
- if (isa<TagDecl>(D)) {
+
+ if (isa<UnresolvedUsingValueDecl>(D)) {
+ HasUnresolved = true;
+ } else if (isa<TagDecl>(D)) {
if (HasTag)
Ambiguous = true;
UniqueTagIndex = I;
@@ -296,7 +305,8 @@
// 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 (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction))
+ if (HideTags && HasTag && !Ambiguous && !HasUnresolved &&
+ (HasFunction || HasNonFunction))
Decls[UniqueTagIndex] = Decls[--N];
Decls.set_size(N);
@@ -306,6 +316,8 @@
if (Ambiguous)
setAmbiguous(LookupResult::AmbiguousReference);
+ else if (HasUnresolved)
+ ResultKind = LookupResult::FoundUnresolvedValue;
else if (N > 1)
ResultKind = LookupResult::FoundOverloaded;
else
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index a799ddb..28fa6bd 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4501,6 +4501,10 @@
Referenced = Result.getFoundDecl();
break;
+ case LookupResult::FoundUnresolvedValue:
+ llvm::llvm_unreachable("unresolved using decl in non-dependent context");
+ return QualType();
+
case LookupResult::FoundOverloaded:
DiagID = diag::err_typename_nested_not_type;
Referenced = *Result.begin();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 00ef407..8d5741d 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -66,7 +66,8 @@
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
- Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
+ Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {
@@ -1025,8 +1026,8 @@
return Inst;
}
-Decl *
-TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+Decl * TemplateDeclInstantiator
+ ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
NestedNameSpecifier *NNS =
SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
D->getTargetNestedNameRange(),
@@ -1040,8 +1041,35 @@
NamedDecl *UD =
SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
- D->getLocation(), SS, D->getTargetNameLocation(),
- D->getDeclName(), 0, D->isTypeName());
+ D->getUsingLoc(), SS, D->getLocation(),
+ D->getDeclName(), 0,
+ /*instantiation*/ true,
+ /*typename*/ true, D->getTypenameLoc());
+ if (UD)
+ SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
+ D);
+ return UD;
+}
+
+Decl * TemplateDeclInstantiator
+ ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ NestedNameSpecifier *NNS =
+ SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
+ D->getTargetNestedNameRange(),
+ TemplateArgs);
+ if (!NNS)
+ return 0;
+
+ CXXScopeSpec SS;
+ SS.setRange(D->getTargetNestedNameRange());
+ SS.setScopeRep(NNS);
+
+ NamedDecl *UD =
+ SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
+ D->getUsingLoc(), SS, D->getLocation(),
+ D->getDeclName(), 0,
+ /*instantiation*/ true,
+ /*typename*/ false, SourceLocation());
if (UD)
SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
D);
@@ -1724,7 +1752,13 @@
return false;
}
-static bool isInstantiationOf(UnresolvedUsingDecl *Pattern,
+static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
@@ -1747,7 +1781,15 @@
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (D->getKind() != Other->getKind()) {
- if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) {
+ if (UnresolvedUsingTypenameDecl *UUD
+ = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
+ return isInstantiationOf(UUD, UD, Ctx);
+ }
+ }
+
+ if (UnresolvedUsingValueDecl *UUD
+ = dyn_cast<UnresolvedUsingValueDecl>(D)) {
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
return isInstantiationOf(UUD, UD, Ctx);
}