diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7543742c19..1fc3d7b104 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1927,6 +1927,14 @@ def err_template_kw_missing : Error< def ext_template_outside_of_template : ExtWarn< "'template' keyword outside of a template">, InGroup; +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">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 26b3d96ff9..1607e6177b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3180,6 +3180,8 @@ public: void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); + void NoteAllFoundTemplates(TemplateName Name); + QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 6b378a0011..ebd07f4867 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -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, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index eef2f5e635..d09f20e113 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index d92f7599f2..fe7efb88d5 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -684,6 +684,19 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, return false; } + + if (Template.get().getAsOverloadedTemplate() || + isa(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, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f70efc1c8e..990fc228b3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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(Template)? 0 + : isa(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(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 diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index 9c72845fb6..7730ee395f 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -99,3 +99,31 @@ namespace PR7725 { } }; } + +namespace PR9226 { + template + 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 + void f(T*); // expected-note{{function template 'f' declared here}} + + template + void f(T*, T*); // expected-note{{function template 'f' declared here}} + + void g() { + f:: // expected-error{{qualified name refers into a specialization of function template 'f'}} + } // expected-error{{expected unqualified-id}} + + struct X { + template void f(); // expected-note{{function template 'f' declared here}} + }; + + template + struct Y { + typedef typename T::template f type; // expected-error{{template name refers to non-type template 'X::f'}} + }; + + Y yxi; // expected-note{{in instantiation of template class 'PR9226::Y' requested here}} +}