required to be a template-id but names an undeclared identifier.
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);
// 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;
<< 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;
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,
<< 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) {
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- TNK = Actions.ActOnDependentTemplateName(
+ TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
EnteringContext, Template, /*AllowInjectedClassName*/ true);
} else {
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)
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)
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)) {
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
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;
}
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 ?
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();
}
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();
}
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'}}
};
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
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>'}}
}
};
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>'}}
}
};
}
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.