[clang] 88c7ffa - Form invalid template-id annotations when parsing a construct that is
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 27 20:34:42 PDT 2020
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 at -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.
More information about the cfe-commits
mailing list