Author: Richard Smith Date: 2020-03-27T20:27:42-07:00 New Revision: 88c7ffaf947642b0cb2d13e5d1a4a54fc633d014
URL: https://github.com/llvm/llvm-project/commit/88c7ffaf947642b0cb2d13e5d1a4a54fc633d014 DIFF: https://github.com/llvm/llvm-project/commit/88c7ffaf947642b0cb2d13e5d1a4a54fc633d014.diff LOG: Form invalid template-id annotations when parsing a construct that is required to be a template-id but names an undeclared identifier. Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseExprCXX.cpp clang/lib/Parse/ParseTemplate.cpp clang/lib/Parse/ParseTentative.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/TreeTransform.h clang/test/SemaCXX/invalid-template-specifier.cpp clang/test/SemaObjCXX/parameterized_classes_subst.mm clang/test/SemaTemplate/dependent-base-classes.cpp clang/test/SemaTemplate/nested-name-spec-template.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6025175e7177..b4b2611481db 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7226,7 +7226,7 @@ class Sema final { const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); - TemplateNameKind ActOnDependentTemplateName( + TemplateNameKind ActOnTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 1f0d37154328..985bcf689d21 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -316,13 +316,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // Commit to parsing the template-id. TPA.Commit(); TemplateTy Template; - if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true)) { - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, - TemplateName, false)) - return true; - } else + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) return true; continue; @@ -528,16 +526,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier( << FixItHint::CreateInsertion(Tok.getLocation(), "template "); } - if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, Tok.getLocation(), TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true)) { - // Consume the identifier. - ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), - TemplateName, false)) - return true; - } - else + SourceLocation TemplateNameLoc = ConsumeToken(); + + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) return true; continue; @@ -2307,9 +2302,9 @@ bool Parser::ParseUnqualifiedIdTemplateId( if (AssumeTemplateId) { // We defer the injected-class-name checks until we've found whether // this template-id is used to form a nested-name-specifier or not. - TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, - Template, /*AllowInjectedClassName*/ true); + TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Id, + ObjectType, EnteringContext, Template, + /*AllowInjectedClassName*/ true); } else { bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(getCurScope(), SS, @@ -2346,7 +2341,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); } - TNK = Actions.ActOnDependentTemplateName( + TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true); } else if (TNK == TNK_Non_template) { @@ -2373,7 +2368,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - TNK = Actions.ActOnDependentTemplateName( + TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true); } else { @@ -2789,7 +2784,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, EnteringContext, Result, TemplateSpecified); else if (TemplateSpecified && - Actions.ActOnDependentTemplateName( + Actions.ActOnTemplateName( getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true) == TNK_Non_template) @@ -2875,7 +2870,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr, SourceLocation(), EnteringContext, Result, TemplateSpecified); else if (TemplateSpecified && - Actions.ActOnDependentTemplateName( + Actions.ActOnTemplateName( getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true) == TNK_Non_template) diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 518167321f18..d383839d9231 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1452,15 +1452,14 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { TryConsumeToken(tok::ellipsis, EllipsisLoc); - // If the next token signals the end of a template argument, - // then we have a dependent template name that could be a template - // template argument. + // If the next token signals the end of a template argument, then we have + // a (possibly-dependent) template name that could be a template template + // argument. TemplateTy Template; if (isEndOfTemplateArgument(Tok) && - Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, Name, - /*ObjectType=*/nullptr, - /*EnteringContext=*/false, Template)) + Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Name, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false, Template)) Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } else if (Tok.is(tok::identifier)) { diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 0c3824c3c984..529e3f321054 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1545,7 +1545,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If lookup for the template-name found nothing, don't assume we have a // definitive disambiguation result yet. - if (TemplateId->Kind == TNK_Undeclared_template && InvalidAsDeclSpec) { + if ((TemplateId->hasInvalidName() || + TemplateId->Kind == TNK_Undeclared_template) && + InvalidAsDeclSpec) { // 'template-id(' can be a valid expression but not a valid decl spec if // the template-name is not declared, but we don't consider this to be a // definitive disambiguation. In any other context, it's an error either @@ -1574,8 +1576,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, NextToken().is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(NextToken()); - if (TemplateId->hasInvalidName()) + if (TemplateId->hasInvalidName()) { + if (InvalidAsDeclSpec) { + *InvalidAsDeclSpec = NextToken().is(tok::l_paren); + return TPResult::Ambiguous; + } return TPResult::Error; + } if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1)) return TPResult::True; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f95b16c1cbae..74d1fbe2ec77 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4623,21 +4623,28 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs); } -/// Form a dependent template name. +/// Form a template name from a name that is syntactically required to name a +/// template, either due to use of the 'template' keyword or because a name in +/// this syntactic context is assumed to name a template (C++ [temp.names]p2-4). /// -/// This action forms a dependent template name given the template -/// name and its (presumably dependent) scope specifier. For -/// example, given "MetaFun::template apply", the scope specifier \p -/// SS will be "MetaFun::", \p TemplateKWLoc contains the location +/// This action forms a template name given the name of the template and its +/// optional scope specifier. This is used when the 'template' keyword is used +/// or when the parsing context unambiguously treats a following '<' as +/// introducing a template argument list. Note that this may produce a +/// non-dependent template name if we can perform the lookup now and identify +/// the named template. +/// +/// For example, given "x.MetaFun::template apply", the scope specifier +/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. -TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const UnqualifiedId &Name, - ParsedType ObjectType, - bool EnteringContext, - TemplateTy &Result, - bool AllowInjectedClassName) { +TemplateNameKind Sema::ActOnTemplateName(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Result, + bool AllowInjectedClassName) { if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TemplateKWLoc, getLangOpts().CPlusPlus11 ? diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 867ca5ffa644..dda3a3934d3b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13681,11 +13681,10 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, TemplateName, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, + TemplateName, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, + AllowInjectedClassName); return Template.get(); } @@ -13702,11 +13701,9 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, Name, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName( + /*Scope=*/nullptr, SS, TemplateKWLoc, Name, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, AllowInjectedClassName); return Template.get(); } diff --git a/clang/test/SemaCXX/invalid-template-specifier.cpp b/clang/test/SemaCXX/invalid-template-specifier.cpp index 140ad00c9e6f..f8f97ded5da5 100644 --- a/clang/test/SemaCXX/invalid-template-specifier.cpp +++ b/clang/test/SemaCXX/invalid-template-specifier.cpp @@ -7,6 +7,5 @@ const template basic_istream<char>; // expected-error {{expected unqualified-id} namespace S {} template <class X> class Y { - void x() { S::template y<char>(1); } // expected-error {{no member named 'y' in namespace 'S'}} \ - // expected-error {{unqualified-id}} + void x() { S::template y<char>(1); } // expected-error {{no member named 'y' in namespace 'S'}} }; diff --git a/clang/test/SemaObjCXX/parameterized_classes_subst.mm b/clang/test/SemaObjCXX/parameterized_classes_subst.mm index 2eb630aeedf4..8aacf21faf09 100644 --- a/clang/test/SemaObjCXX/parameterized_classes_subst.mm +++ b/clang/test/SemaObjCXX/parameterized_classes_subst.mm @@ -427,7 +427,6 @@ void testVariadicInstantiation() { template<typename K, typename V> struct NonDependentTemplate { typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} - // expected-error@-1{{expected member name or }} }; // However, one can use an alias template to turn a parameterized diff --git a/clang/test/SemaTemplate/dependent-base-classes.cpp b/clang/test/SemaTemplate/dependent-base-classes.cpp index bb4f3ca1f17c..f8f36b2a077d 100644 --- a/clang/test/SemaTemplate/dependent-base-classes.cpp +++ b/clang/test/SemaTemplate/dependent-base-classes.cpp @@ -55,8 +55,7 @@ namespace PR6031 { struct NoDepBase { int foo() { class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}} - typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} \ - // FIXME: expected-error{{unqualified-id}} + typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}} } }; @@ -103,10 +102,7 @@ namespace PR6081 { template< class X > void f0(const X & k) { - this->template f1<int>()(k); // expected-error{{no member named 'f1' in 'C<T>'}} \ - // FIXME: expected-error{{unqualified-id}} \ - // expected-error{{function-style cast or type construction}} \ - // expected-error{{expected expression}} + this->template f1<int>()(k); // expected-error{{no member named 'f1' in 'C<T>'}} } }; } diff --git a/clang/test/SemaTemplate/nested-name-spec-template.cpp b/clang/test/SemaTemplate/nested-name-spec-template.cpp index e9d0eb202033..3e7f506040a6 100644 --- a/clang/test/SemaTemplate/nested-name-spec-template.cpp +++ b/clang/test/SemaTemplate/nested-name-spec-template.cpp @@ -58,8 +58,7 @@ struct ::N::A<int>::X { template<typename T> struct TestA { - typedef typename N::template B<T>::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} \ - // expected-error{{expected member name}} + typedef typename N::template B<T>::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} }; // Reduced from a Boost failure. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits