Teach Sema::ActOnCXXNestedNameSpecifier and Sema::CheckTemplateIdType

to cope with non-type templates by providing appropriate
errors. Previously, we would either assert, crash, or silently build a
dependent type when we shouldn't. Fixes PR9226.

llvm-svn: 127037
This commit is contained in:
Douglas Gregor 2011-03-04 21:37:14 +00:00
parent d7e1bb80a9
commit 8b6070bb9d
7 changed files with 116 additions and 38 deletions

View File

@ -1927,6 +1927,14 @@ def err_template_kw_missing : Error<
def ext_template_outside_of_template : ExtWarn<
"'template' keyword outside of a template">, InGroup<CXX0x>;
def err_non_type_template_in_nested_name_specifier : Error<
"qualified name refers into a specialization of function template '%0'">;
def err_template_id_not_a_type : Error<
"template name refers to non-type template '%0'">;
def note_template_declared_here : Note<
"%select{function template|class template|template template parameter}0 "
"%1 declared here">;
// C++0x Variadic Templates
def err_template_param_pack_default_arg : Error<
"template parameter pack cannot have a default argument">;

View File

@ -3180,6 +3180,8 @@ public:
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
void NoteAllFoundTemplates(TemplateName Name);
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs);

View File

@ -118,6 +118,10 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
OS << SubstPack->getParameterPack()->getNameAsString();
else {
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
(*OTS->begin())->printName(OS);
}
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,

View File

@ -197,42 +197,37 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
// Consume the template-id token.
ConsumeToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
// Consume the template-id token.
ConsumeToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
if (!HasScopeSpecifier)
HasScopeSpecifier = true;
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
/*FIXME:*/SourceLocation(),
SS,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
CCLoc,
EnteringContext)) {
SourceLocation StartLoc
= SS.getBeginLoc().isValid()? SS.getBeginLoc()
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
TemplateId->Destroy();
continue;
if (!HasScopeSpecifier)
HasScopeSpecifier = true;
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
/*FIXME:*/SourceLocation(),
SS,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
CCLoc,
EnteringContext)) {
SourceLocation StartLoc
= SS.getBeginLoc().isValid()? SS.getBeginLoc()
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
assert(false && "FIXME: Only type template names supported here");
TemplateId->Destroy();
continue;
}

View File

@ -684,6 +684,19 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
return false;
}
if (Template.get().getAsOverloadedTemplate() ||
isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) {
SourceRange R(TemplateNameLoc, RAngleLoc);
if (SS.getRange().isValid())
R.setBegin(SS.getRange().getBegin());
Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
<< Template.get() << R;
NoteAllFoundTemplates(Template.get());
return true;
}
// We were able to resolve the template name to an actual template.
// Build an appropriate nested-name-specifier.
QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc,

View File

@ -1632,14 +1632,42 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
return ParamLists[NumParamLists - 1];
}
void Sema::NoteAllFoundTemplates(TemplateName Name) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
Diag(Template->getLocation(), diag::note_template_declared_here)
<< (isa<FunctionTemplateDecl>(Template)? 0
: isa<ClassTemplateDecl>(Template)? 1
: 2)
<< Template->getDeclName();
return;
}
if (OverloadedTemplateStorage *OST = Name.getAsOverloadedTemplate()) {
for (OverloadedTemplateStorage::iterator I = OST->begin(),
IEnd = OST->end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_template_declared_here)
<< 0 << (*I)->getDeclName();
return;
}
}
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
// The template name does not resolve to a template, so we just
// build a dependent template-id type.
return Context.getTemplateSpecializationType(Name, TemplateArgs);
if (!Template || isa<FunctionTemplateDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
return Context.getTemplateSpecializationType(Name, TemplateArgs);
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
NoteAllFoundTemplates(Name);
return QualType();
}
// Check that the template argument list is well-formed for this

View File

@ -99,3 +99,31 @@ namespace PR7725 {
}
};
}
namespace PR9226 {
template<typename a>
void nt() // expected-note{{function template 'nt' declared here}}
{ nt<>:: } // expected-error{{qualified name refers into a specialization of function template 'nt'}} \
// expected-error{{expected unqualified-id}}
template<typename T>
void f(T*); // expected-note{{function template 'f' declared here}}
template<typename T>
void f(T*, T*); // expected-note{{function template 'f' declared here}}
void g() {
f<int>:: // expected-error{{qualified name refers into a specialization of function template 'f'}}
} // expected-error{{expected unqualified-id}}
struct X {
template<typename T> void f(); // expected-note{{function template 'f' declared here}}
};
template<typename T, typename U>
struct Y {
typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::f'}}
};
Y<X, int> yxi; // expected-note{{in instantiation of template class 'PR9226::Y<PR9226::X, int>' requested here}}
}