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
This commit is contained in:
Douglas Gregor 2009-08-26 00:04:55 +00:00
Родитель ec7738776b
Коммит dacd434c49
10 изменённых файлов: 71 добавлений и 31 удалений

Просмотреть файл

@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
@ -179,6 +180,15 @@ public:
void dump(const LangOptions &LO);
};
/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
/// into a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
NestedNameSpecifier *NNS) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
Diagnostic::ak_nestednamespec);
return DB;
}
}
#endif

Просмотреть файл

@ -156,7 +156,8 @@ public:
ak_identifierinfo, // IdentifierInfo
ak_qualtype, // QualType
ak_declarationname, // DeclarationName
ak_nameddecl // NamedDecl *
ak_nameddecl, // NamedDecl *
ak_nestednamespec // NestedNameSpecifier *
};
private:

Просмотреть файл

@ -889,8 +889,8 @@ def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer to a class "
"template or class template partial specialization">;
"nested name specifier %0 for declaration does not refer into a class, "
"class template or class template partial specialization">;
def err_template_spec_decl_out_of_scope_global : Error<
"class template %select{|partial }0specialization of %1 must occur in the "
"global scope">;

Просмотреть файл

@ -131,15 +131,33 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
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;
}

Просмотреть файл

@ -797,6 +797,7 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
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);

Просмотреть файл

@ -79,8 +79,7 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
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 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
"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('\'');

Просмотреть файл

@ -79,17 +79,6 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
// 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 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
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 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
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 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// 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);
}

Просмотреть файл

@ -1633,7 +1633,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
<< 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 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
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:

Просмотреть файл

@ -43,7 +43,7 @@ void X0<X, Y>::f3(size_type) const {
}
template<class X, class Y>
void X0<Y, X>::f4() { } // expected-error{{does not refer to}}
void X0<Y, X>::f4() { } // expected-error{{does not refer}}
// FIXME: error message should probably say, "redefinition of 'X0<T, U>::f0'"
// rather than just "redefinition of 'f0'"

Просмотреть файл

@ -87,3 +87,7 @@ Y Outer<X>::Inner1<Y>::value2 = Y();
template<typename X>
template<typename Y>
Y Outer<X>::Inner1<Y>::ReallyInner::value3 = Y();
template<typename X>
template<typename Y>
Y Outer<X>::Inner1<Y*>::ReallyInner::value4; // expected-error{{Outer<X>::Inner1<Y *>::ReallyInner::}}