Author: rsmith Date: Thu Apr 26 19:00:13 2018 New Revision: 331013 URL: http://llvm.org/viewvc/llvm-project?rev=331013&view=rev Log: Parse A::template B as an identifier rather than as a template-id with no template arguments.
This fixes some cases where we'd incorrectly accept "A::template B" when B is a kind of template that requires template arguments (in particular, a variable template or a concept). Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/ParseOpenMP.cpp cfe/trunk/lib/Parse/ParseStmtAsm.cpp cfe/trunk/lib/Parse/Parser.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprMember.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/CXX/drs/dr1xx.cpp cfe/trunk/test/CXX/drs/dr4xx.cpp cfe/trunk/test/CXX/temp/temp.res/p3.cpp cfe/trunk/test/Parser/cxx-decl.cpp cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp cfe/trunk/test/SemaTemplate/template-id-expr.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Apr 26 19:00:13 2018 @@ -633,6 +633,8 @@ def err_template_spec_syntax_non_templat "<unused>|refers to a variable template|<unused>}1">; def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; +def err_unexpected_template_in_unqualified_id : Error< + "'template' keyword not permitted here">; def err_two_right_angle_brackets_need_space : Error< "a space is required between consecutive right angle brackets (use '> >')">; def err_right_angle_bracket_equal_needs_space : Error< Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Thu Apr 26 19:00:13 2018 @@ -2544,12 +2544,11 @@ private: struct UsingDeclarator { SourceLocation TypenameLoc; CXXScopeSpec SS; - SourceLocation TemplateKWLoc; UnqualifiedId Name; SourceLocation EllipsisLoc; void clear() { - TypenameLoc = TemplateKWLoc = EllipsisLoc = SourceLocation(); + TypenameLoc = EllipsisLoc = SourceLocation(); SS.clear(); Name.clear(); } @@ -2744,7 +2743,7 @@ public: bool AllowConstructorName, bool AllowDeductionGuide, ParsedType ObjectType, - SourceLocation& TemplateKWLoc, + SourceLocation *TemplateKWLoc, UnqualifiedId &Result); private: Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Apr 26 19:00:13 2018 @@ -6074,7 +6074,7 @@ public: TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, @@ -6244,7 +6244,7 @@ public: TemplateNameKind ActOnDependentTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); DeclResult Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Apr 26 19:00:13 2018 @@ -5600,12 +5600,11 @@ void Parser::ParseDirectDeclarator(Decla D.getContext() == DeclaratorContext::MemberContext); } - SourceLocation TemplateKWLoc; bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, - AllowDeductionGuide, nullptr, TemplateKWLoc, + AllowDeductionGuide, nullptr, nullptr, D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Apr 26 19:00:13 2018 @@ -602,7 +602,7 @@ bool Parser::ParseUsingDeclarator(Declar /*AllowConstructorName=*/!(Tok.is(tok::identifier) && NextToken().is(tok::equal)), /*AllowDeductionGuide=*/false, - nullptr, D.TemplateKWLoc, D.Name)) + nullptr, nullptr, D.Name)) return true; } @@ -2476,7 +2476,7 @@ Parser::ParseCXXClassMemberDeclaration(A SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, false, true, true, false, nullptr, - TemplateKWLoc, Name)) { + &TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } @@ -2488,6 +2488,7 @@ Parser::ParseCXXClassMemberDeclaration(A return nullptr; } + // FIXME: We should do something with the 'template' keyword here. return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( getCurScope(), AS, /*UsingLoc*/ SourceLocation(), /*TypenameLoc*/ SourceLocation(), SS, Name, Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Apr 26 19:00:13 2018 @@ -1755,7 +1755,7 @@ Parser::ParsePostfixExpressionSuffix(Exp /*AllowConstructorName=*/ getLangOpts().MicrosoftExt, /*AllowDeductionGuide=*/false, - ObjectType, TemplateKWLoc, Name)) { + ObjectType, &TemplateKWLoc, Name)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Apr 26 19:00:13 2018 @@ -553,7 +553,7 @@ ExprResult Parser::tryParseCXXIdExpressi /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, /*AllowDeductionGuide=*/false, - /*ObjectType=*/nullptr, TemplateKWLoc, Name)) + /*ObjectType=*/nullptr, &TemplateKWLoc, Name)) return ExprError(); // This is only the direct operand of an & operator if it is not @@ -2044,9 +2044,8 @@ bool Parser::ParseUnqualifiedIdTemplateI ParsedType ObjectType, UnqualifiedId &Id, bool AssumeTemplateId) { - assert((AssumeTemplateId || Tok.is(tok::less)) && - "Expected '<' to finish parsing a template-id"); - + assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + TemplateTy Template; TemplateNameKind TNK = TNK_Non_template; switch (Id.getKind()) { @@ -2142,10 +2141,10 @@ bool Parser::ParseUnqualifiedIdTemplateI // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName( - true, LAngleLoc, TemplateArgs, RAngleLoc)) + if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, + RAngleLoc)) return true; - + if (Id.getKind() == UnqualifiedIdKind::IK_Identifier || Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId || Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) { @@ -2465,16 +2464,23 @@ bool Parser::ParseUnqualifiedId(CXXScope bool AllowConstructorName, bool AllowDeductionGuide, ParsedType ObjectType, - SourceLocation& TemplateKWLoc, + SourceLocation *TemplateKWLoc, UnqualifiedId &Result) { + if (TemplateKWLoc) + *TemplateKWLoc = SourceLocation(); // Handle 'A::template B'. This is for template-ids which have not // already been annotated by ParseOptionalCXXScopeSpecifier(). bool TemplateSpecified = false; - if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) && - (ObjectType || SS.isSet())) { - TemplateSpecified = true; - TemplateKWLoc = ConsumeToken(); + if (Tok.is(tok::kw_template)) { + if (TemplateKWLoc && (ObjectType || SS.isSet())) { + TemplateSpecified = true; + *TemplateKWLoc = ConsumeToken(); + } else { + SourceLocation TemplateLoc = ConsumeToken(); + Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id) + << FixItHint::CreateRemoval(TemplateLoc); + } } // unqualified-id: @@ -2513,11 +2519,18 @@ bool Parser::ParseUnqualifiedId(CXXScope } // If the next token is a '<', we may have a template. - if (TemplateSpecified || Tok.is(tok::less)) - return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc, - EnteringContext, ObjectType, - Result, TemplateSpecified); - + TemplateTy Template; + if (Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId( + SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, + EnteringContext, ObjectType, Result, TemplateSpecified); + else if (TemplateSpecified && + Actions.ActOnDependentTemplateName( + getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, + EnteringContext, Template, + /*AllowInjectedClassName*/ true) == TNK_Non_template) + return true; + return false; } @@ -2558,7 +2571,14 @@ bool Parser::ParseUnqualifiedId(CXXScope // We have already parsed a template-id; consume the annotation token as // our unqualified-id. Result.setTemplateId(TemplateId); - TemplateKWLoc = TemplateId->TemplateKWLoc; + SourceLocation TemplateLoc = TemplateId->TemplateKWLoc; + if (TemplateLoc.isValid()) { + if (TemplateKWLoc && (ObjectType || SS.isSet())) + *TemplateKWLoc = TemplateLoc; + else + Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id) + << FixItHint::CreateRemoval(TemplateLoc); + } ConsumeAnnotationToken(); return false; } @@ -2575,13 +2595,20 @@ bool Parser::ParseUnqualifiedId(CXXScope // // template-id: // operator-function-id < template-argument-list[opt] > + TemplateTy Template; if ((Result.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId || Result.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) && - (TemplateSpecified || Tok.is(tok::less))) - return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, - nullptr, SourceLocation(), - EnteringContext, ObjectType, - Result, TemplateSpecified); + Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId( + SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr, + SourceLocation(), EnteringContext, ObjectType, Result, + TemplateSpecified); + else if (TemplateSpecified && + Actions.ActOnDependentTemplateName( + getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, + EnteringContext, Template, + /*AllowInjectedClassName*/ true) == TNK_Non_template) + return true; return false; } @@ -2649,12 +2676,11 @@ bool Parser::ParseUnqualifiedId(CXXScope IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); - if (TemplateSpecified || Tok.is(tok::less)) { + if (Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc); - return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, - ClassName, ClassNameLoc, - EnteringContext, ObjectType, - Result, TemplateSpecified); + return ParseUnqualifiedIdTemplateId( + SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), ClassName, + ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified); } // Note that this is a destructor name. Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original) +++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Thu Apr 26 19:00:13 2018 @@ -1154,7 +1154,6 @@ bool Parser::ParseOpenMPSimpleVarList( // Read tokens while ')' or annot_pragma_openmp_end is not found. while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { CXXScopeSpec SS; - SourceLocation TemplateKWLoc; UnqualifiedId Name; // Read var name. Token PrevTok = Tok; @@ -1166,7 +1165,7 @@ bool Parser::ParseOpenMPSimpleVarList( SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr, - TemplateKWLoc, Name)) { + nullptr, Name)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -1648,7 +1647,6 @@ OMPClause *Parser::ParseOpenMPSingleExpr static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, UnqualifiedId &ReductionId) { - SourceLocation TemplateKWLoc; if (ReductionIdScopeSpec.isEmpty()) { auto OOK = OO_None; switch (P.getCurToken().getKind()) { @@ -1690,7 +1688,7 @@ static bool ParseReductionId(Parser &P, /*AllowDestructorName*/ false, /*AllowConstructorName*/ false, /*AllowDeductionGuide*/ false, - nullptr, TemplateKWLoc, ReductionId); + nullptr, nullptr, ReductionId); } /// Parses clauses with list. Modified: cfe/trunk/lib/Parse/ParseStmtAsm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseStmtAsm.cpp (original) +++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp Thu Apr 26 19:00:13 2018 @@ -239,7 +239,7 @@ ExprResult Parser::ParseMSAsmIdentifier( /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, /*AllowDeductionGuide=*/false, - /*ObjectType=*/nullptr, TemplateKWLoc, Id); + /*ObjectType=*/nullptr, &TemplateKWLoc, Id); // Perform the lookup. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, IsUnevaluatedContext); Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Thu Apr 26 19:00:13 2018 @@ -2002,7 +2002,7 @@ bool Parser::ParseMicrosoftIfExistsCondi if (ParseUnqualifiedId( Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true, /*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr, - TemplateKWLoc, Result.Name)) { + &TemplateKWLoc, Result.Name)) { T.skipToEnd(); return true; } Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Apr 26 19:00:13 2018 @@ -2080,7 +2080,7 @@ Sema::ActOnIdExpression(Scope *S, CXXSco (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) ? LookupObjCImplicitSelfParam : LookupOrdinaryName); - if (TemplateArgs) { + if (TemplateKWLoc.isValid() || TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the // lookup to determine that it was a template name in the first place. If @@ -2089,7 +2089,7 @@ Sema::ActOnIdExpression(Scope *S, CXXSco bool MemberOfUnknownSpecialization; LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, MemberOfUnknownSpecialization); - + if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, @@ -2155,6 +2155,9 @@ Sema::ActOnIdExpression(Scope *S, CXXSco if (SS.isValid()) CCC->setTypoNNS(SS.getScopeRep()); } + // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for + // a template name, but we happen to have always already looked up the name + // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? std::move(CCC) : std::move(DefaultValidator), nullptr, None, &TE)) { Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Thu Apr 26 19:00:13 2018 @@ -759,9 +759,9 @@ Sema::BuildMemberReferenceExpr(Expr *Bas TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, nullptr, - RecordTy->getAs<RecordType>(), OpLoc, IsArrow, - SS, TemplateArgs != nullptr, TE)) + if (LookupMemberExprInRecord( + *this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow, + SS, TemplateKWLoc.isValid() || TemplateArgs != nullptr, TE)) return ExprError(); if (TE) return TE; @@ -769,10 +769,10 @@ Sema::BuildMemberReferenceExpr(Expr *Bas // Explicit member accesses. } else { ExprResult BaseResult = Base; - ExprResult Result = LookupMemberExpr( - *this, R, BaseResult, IsArrow, OpLoc, SS, - ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr, - TemplateArgs != nullptr); + ExprResult Result = + LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS, + ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr, + TemplateKWLoc.isValid() || TemplateArgs != nullptr); if (BaseResult.isInvalid()) return ExprError(); Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 26 19:00:13 2018 @@ -158,7 +158,7 @@ bool Sema::hasAnyAcceptableTemplateNames TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, @@ -4102,7 +4102,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXSc TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Result, Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr1xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr1xx.cpp Thu Apr 26 19:00:13 2018 @@ -67,7 +67,10 @@ namespace dr108 { // dr108: yes namespace dr109 { // dr109: yes struct A { template<typename T> void f(T); }; template<typename T> struct B : T { - using T::template f; // expected-error {{using declaration cannot refer to a template}} + using T::template f; // expected-error {{'template' keyword not permitted here}} + using T::template f<int>; // expected-error {{'template' keyword not permitted here}} expected-error {{using declaration cannot refer to a template specialization}} + // FIXME: We shouldn't suggest using the 'template' keyword in a location where it's not valid. + using T::f<int>; // expected-error {{use 'template' keyword}} expected-error {{using declaration cannot refer to a template specialization}} void g() { this->f<int>(123); } // expected-error {{use 'template'}} }; } Modified: cfe/trunk/test/CXX/drs/dr4xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr4xx.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr4xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr4xx.cpp Thu Apr 26 19:00:13 2018 @@ -318,8 +318,8 @@ namespace dr420 { // dr420: yes q->~id<int>(); p->id<int>::~id<int>(); q->id<int>::~id<int>(); - p->template id<int>::~id<int>(); // expected-error {{expected unqualified-id}} - q->template id<int>::~id<int>(); // expected-error {{expected unqualified-id}} + p->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}} + q->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}} p->A::template id<int>::~id<int>(); q->A::template id<int>::~id<int>(); } Modified: cfe/trunk/test/CXX/temp/temp.res/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/p3.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.res/p3.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.res/p3.cpp Thu Apr 26 19:00:13 2018 @@ -34,5 +34,5 @@ template<typename T> template<typename U // a type, and then complain about the rest of the tokens, and then complain // that we didn't get a function declaration. friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-error 3{{}} - friend A<U>::template C<T> f8(); // expected-error 3{{}} + friend A<U>::template C<T> f8(); // expected-error 4{{}} }; Modified: cfe/trunk/test/Parser/cxx-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-decl.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx-decl.cpp (original) +++ cfe/trunk/test/Parser/cxx-decl.cpp Thu Apr 26 19:00:13 2018 @@ -237,10 +237,11 @@ namespace PR5066 { namespace PR17255 { void foo() { typename A::template B<>; // expected-error {{use of undeclared identifier 'A'}} + // expected-error@-1 {{'template' keyword not permitted here}} #if __cplusplus <= 199711L - // expected-error@-2 {{'template' keyword outside of a template}} + // expected-error@-3 {{'template' keyword outside of a template}} #endif - // expected-error@-4 {{expected a qualified name after 'typename'}} + // expected-error@-5 {{expected a qualified name after 'typename'}} } } Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Thu Apr 26 19:00:13 2018 @@ -382,16 +382,16 @@ int main() { namespace dependent_static_var_template { struct A { - template<int = 0> static int n; // expected-note {{here}} + template<int = 0> static int n; // expected-note 2{{here}} }; - int &r = A::template n; // FIXME: ill-formed + int &r = A::template n; // expected-error {{use of variable template 'n' requires template arguments}} template<typename T> int &f() { return T::template n; } // expected-error {{use of variable template 'n' requires template arguments}} int &s = f<A>(); // expected-note {{instantiation of}} namespace B { - template<int = 0> static int n; + template<int = 0> static int n; // expected-note {{here}} } - int &t = B::template n; // FIXME: ill-formed + int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} } Modified: cfe/trunk/test/SemaTemplate/template-id-expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/template-id-expr.cpp?rev=331013&r1=331012&r2=331013&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/template-id-expr.cpp (original) +++ cfe/trunk/test/SemaTemplate/template-id-expr.cpp Thu Apr 26 19:00:13 2018 @@ -85,6 +85,52 @@ struct Y0 { } }; +template<typename U> void Y0 + ::template // expected-error {{expected unqualified-id}} + f1(U) {} + +// FIXME: error recovery is awful without this. + ; + +template<typename T> +struct Y1 { + template<typename U> + void f1(U); + + template<typename U> + static void f2(U); + + void f3(int); + + static int f4(int); + template<typename U> + static void f4(U); + + template<typename U> + void f() { + Y1::template f1<U>(0); + Y1::template f1(0); + this->template f1(0); + + Y1::template f2<U>(0); + Y1::template f2(0); + + Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y1::f4(0); + x = Y1::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = this->f4(0); + x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; + +void use_Y1(Y1<int> y1) { y1.f<int>(); } // expected-note {{in instantiation of}} + struct A { template<int I> struct B { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits