Improve diagnostics and recovery when the nested-name-specifier of a
qualified name does not actually refer into a class/class
template/class template partial specialization.
Improve printing of nested-name-specifiers to eliminate redudant
qualifiers. Also, make it possible to output a nested-name-specifier
through a DiagnosticBuilder, although there are relatively few places
that will use this leeway.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80056 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 90ec4d3..0376f9d 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -131,15 +131,33 @@
std::string TypeStr;
Type *T = getAsType();
- // If this is a qualified name type, suppress the qualification:
- // it's part of our nested-name-specifier sequence anyway. FIXME:
- // We should be able to assert that this doesn't happen.
- if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T))
- T = QualT->getNamedType().getTypePtr();
-
PrintingPolicy InnerPolicy(Policy);
InnerPolicy.SuppressTagKind = true;
- T->getAsStringInternal(TypeStr, InnerPolicy);
+
+ // Nested-name-specifiers are intended to contain minimally-qualified
+ // types. An actual QualifiedNameType will not occur, since we'll store
+ // just the type that is referred to in the nested-name-specifier (e.g.,
+ // a TypedefType, TagType, etc.). However, when we are dealing with
+ // dependent template-id types (e.g., Outer<T>::template Inner<U>),
+ // the type requires its own nested-name-specifier for uniqueness, so we
+ // suppress that nested-name-specifier during printing.
+ assert(!isa<QualifiedNameType>(T) &&
+ "Qualified name type in nested-name-specifier");
+ if (const TemplateSpecializationType *SpecType
+ = dyn_cast<TemplateSpecializationType>(T)) {
+ // Print the template name without its corresponding
+ // nested-name-specifier.
+ SpecType->getTemplateName().print(OS, InnerPolicy, true);
+
+ // Print the template argument list.
+ TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
+ SpecType->getArgs(),
+ SpecType->getNumArgs(),
+ InnerPolicy);
+ } else {
+ // Print the type normally
+ T->getAsStringInternal(TypeStr, InnerPolicy);
+ }
OS << TypeStr;
break;
}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 6ba5907..922702f 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -797,6 +797,7 @@
case Diagnostic::ak_qualtype:
case Diagnostic::ak_declarationname:
case Diagnostic::ak_nameddecl:
+ case Diagnostic::ak_nestednamespec:
getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo),
Modifier, ModifierLen,
Argument, ArgumentLen, OutStr);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 5425c4f..24c5e09 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -79,8 +79,7 @@
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- } else {
- assert(Kind == Diagnostic::ak_nameddecl);
+ } else if (Kind == Diagnostic::ak_nameddecl) {
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
else {
@@ -88,6 +87,11 @@
"Invalid modifier for NamedDecl* argument");
S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
}
+ } else {
+ llvm::raw_string_ostream OS(S);
+ assert(Kind == Diagnostic::ak_nestednamespec);
+ reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
+ Context.PrintingPolicy);
}
Output.push_back('\'');
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9c9bff8..3dac5d7 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -79,17 +79,6 @@
// The nested name specifier refers to a member of a class template.
return RecordT->getDecl();
}
-
- std::string NNSString;
- {
- llvm::raw_string_ostream OS(NNSString);
- NNS->print(OS, Context.PrintingPolicy);
- }
-
- // FIXME: Allow us to pass a nested-name-specifier to Diag?
- Diag(SS.getRange().getBegin(),
- diag::err_template_qualified_declarator_no_match)
- << NNSString << SS.getRange();
}
return 0;
@@ -298,6 +287,9 @@
T.getTypePtr());
}
+ // FIXME: It would be nice to maintain the namespace alias name, then
+ // see through that alias when resolving the nested-name-specifier down to
+ // a declaration context.
if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
return NestedNameSpecifier::Create(Context, Prefix,
Alias->getNamespace());
@@ -404,8 +396,6 @@
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (DeclContext *DC = computeDeclContext(SS, true))
EnterDeclaratorContext(S, DC);
- else
- const_cast<CXXScopeSpec&>(SS).setScopeRep(0);
}
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
@@ -415,8 +405,8 @@
/// defining scope.
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- assert((SS.isInvalid() || S->getEntity() == computeDeclContext(SS, true)) &&
- "Context imbalance!");
- if (!SS.isInvalid())
+ if (SS.isInvalid())
+ return;
+ if (computeDeclContext(SS, true))
ExitDeclaratorContext(S);
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d478c04..fec9a07 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1633,7 +1633,7 @@
<< D.getDeclSpec().getSourceRange() << D.getSourceRange();
return DeclPtrTy();
}
-
+
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
@@ -1701,7 +1701,19 @@
D.getIdentifierLoc());
} else { // Something like "int foo::x;"
DC = computeDeclContext(D.getCXXScopeSpec(), true);
- // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
+
+ if (!DC) {
+ // If we could not compute the declaration context, it's because the
+ // declaration context is dependent but does not refer to a class,
+ // class template, or class template partial specialization. Complain
+ // and return early, to avoid the coming semantic disaster.
+ Diag(D.getIdentifierLoc(),
+ diag::err_template_qualified_declarator_no_match)
+ << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getRange();
+ return DeclPtrTy();
+ }
+
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
// C++ 7.3.1.2p2: