From b28fcac460a31d6d033e23357ed4b3aeb4e30dbc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 4 Dec 2013 00:28:23 +0000 Subject: [PATCH] Fix several crash-on-invalids when using template-ids that aren't simple-template-ids (eg, 'operator+') in weird places. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196333 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 6 ++--- include/clang/Basic/TemplateKinds.h | 1 + lib/Parse/ParseDeclCXX.cpp | 1 + lib/Parse/ParseExprCXX.cpp | 7 ++--- lib/Parse/Parser.cpp | 5 +++- lib/Sema/SemaCXXScopeSpec.cpp | 13 ++++----- lib/Sema/SemaTemplate.cpp | 2 +- test/CXX/drs/dr3xx.cpp | 27 ++++++++++++++++++- .../cxx1y-variable-templates_top_level.cpp | 8 ++++++ 9 files changed, 55 insertions(+), 15 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 2feab52ef4..3415a0078c 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -578,8 +578,8 @@ def err_class_on_template_template_param : Error< "template template parameter requires 'class' after the parameter list">; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " - "%0 %select{does not refer to a template|refers to a function " - "template||refers to a template template parameter}1">; + "%0 %select{does not refer to a template|refers to a function template|" + "|refers to a variable template|}1">; def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_two_right_angle_brackets_need_space : Error< @@ -643,7 +643,7 @@ def err_expected_semi_after_tagdecl : Error< "expected ';' after %0">; def err_typename_refers_to_non_type_template : Error< - "typename specifier refers to a non-template">; + "typename specifier refers to a non-type template">; def err_expected_type_name_after_typename : Error< "expected an identifier or template-id after '::'">; def err_explicit_spec_non_template : Error< diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h index c5218933a2..b730143b63 100644 --- a/include/clang/Basic/TemplateKinds.h +++ b/include/clang/Basic/TemplateKinds.h @@ -17,6 +17,7 @@ namespace clang { /// \brief Specifies the kind of template name that an identifier refers to. +/// Be careful when changing this: this enumeration is used in diagnostics. enum TemplateNameKind { /// The name does not refer to a template. TNK_Non_template = 0, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d4a4ded252..9c56022941 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1287,6 +1287,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (SS.isNotEmpty()) Range.setBegin(SS.getBeginLoc()); + // FIXME: Name may be null here. Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) << TemplateId->Name << static_cast(TemplateId->Kind) << Range; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fe357cf0ad..f07428a0f3 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -341,10 +341,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { // We have // - // simple-template-id '::' + // template-id '::' // - // So we need to check whether the simple-template-id is of the - // right kind (it should name a type or be dependent), and then + // So we need to check whether the template-id is a simple-template-id of + // the right kind (it should name a type or be dependent), and then // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { @@ -1882,6 +1882,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); + // FIXME: Store name for literal operator too. if (Id.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = Id.Identifier; TemplateId->Operator = OO_None; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 59ffc0562a..c4c0898661 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1615,7 +1615,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { Tok.getLocation()); } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - if (TemplateId->Kind == TNK_Function_template) { + if (TemplateId->Kind != TNK_Type_template && + TemplateId->Kind != TNK_Dependent_template_name) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); return true; @@ -1740,6 +1741,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, AnnotateTemplateIdTokenAsType(); return false; } else if (TemplateId->Kind == TNK_Var_template) + // FIXME: This looks suspicious. Why are we not annotating the scope token + // in this case? return false; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 674411ec06..13c9993bf4 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -747,7 +747,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){ + DependentTemplateName *DTN = Template.get().getAsDependentTemplateName(); + if (DTN && DTN->isIdentifier()) { // Handle a dependent template specialization for which we cannot resolve // the template name. assert(DTN->getQualifier() == SS.getScopeRep()); @@ -773,20 +774,20 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, CCLoc); return false; } - - - if (Template.get().getAsOverloadedTemplate() || + + // FIXME: Variable templates + if (Template.get().getAsOverloadedTemplate() || DTN || 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 7b901d2df8..eb10758bc1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2910,7 +2910,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, case UnqualifiedId::IK_OperatorFunctionId: Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.OperatorFunctionId.Operator)); - return TNK_Dependent_template_name; + return TNK_Function_template; case UnqualifiedId::IK_LiteralOperatorId: llvm_unreachable( diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp index b7bf6ffa8e..c9b1fe7733 100644 --- a/test/CXX/drs/dr3xx.cpp +++ b/test/CXX/drs/dr3xx.cpp @@ -8,4 +8,29 @@ namespace dr300 { // dr300: yes void h() { f(g); } } -// expected-no-diagnostics +namespace dr301 { // dr301 WIP + // see also dr38 + struct S; + template void operator+(T, T); + void operator-(S, S); + + void f() { + bool a = (void(*)(S, S))operator+ < + (void(*)(S, S))operator+; + bool b = (void(*)(S, S))operator- < + (void(*)(S, S))operator-; + bool c = (void(*)(S, S))operator+ < + (void(*)(S, S))operator-; // expected-error {{expected '>'}} + } + + template void f() { + typename T::template operator+ a; // expected-error {{typename specifier refers to a non-type template}} expected-error +{{}} + // FIXME: This shouldn't say (null). + class T::template operator+ b; // expected-error {{identifier followed by '<' indicates a class template specialization but (null) refers to a function template}} + enum T::template operator+ c; // expected-error {{expected identifier}} expected-error {{does not declare anything}} + enum T::template operator+::E d; // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}} expected-error {{forward reference}} + enum T::template X::E e; + T::template operator+::foobar(); // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}} + T::template operator+(0); // ok + } +} diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp index b6e8762f5d..5af6c0ab5b 100644 --- a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -432,3 +432,11 @@ namespace nested { } } +namespace nested_name { + template int a; + // FIXME: This triggers a crash. + //a::b c; + + class a {}; // expected-error {{identifier followed by '<' indicates a class template specialization but 'a' refers to a variable template}} + enum a {}; // expected-error {{expected identifier or '{'}} expected-warning {{does not declare anything}} +} -- 2.40.0