forked from OSchip/llvm-project
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:
parent
d7e1bb80a9
commit
8b6070bb9d
|
@ -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">;
|
||||
|
|
|
@ -3180,6 +3180,8 @@ public:
|
|||
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
|
||||
TemplateArgumentListInfo &Out);
|
||||
|
||||
void NoteAllFoundTemplates(TemplateName Name);
|
||||
|
||||
QualType CheckTemplateIdType(TemplateName Template,
|
||||
SourceLocation TemplateLoc,
|
||||
TemplateArgumentListInfo &TemplateArgs);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue