bool AllowFunctionTemplates = true,
bool AllowDependent = true);
+ enum TemplateNameIsRequiredTag { TemplateNameIsRequired };
+ /// Whether and why a template name is required in this lookup.
+ class RequiredTemplateKind {
+ public:
+ /// Template name is required if TemplateKWLoc is valid.
+ RequiredTemplateKind(SourceLocation TemplateKWLoc = SourceLocation())
+ : TemplateKW(TemplateKWLoc) {}
+ /// Template name is unconditionally required.
+ RequiredTemplateKind(TemplateNameIsRequiredTag) : TemplateKW() {}
+
+ SourceLocation getTemplateKeywordLoc() const {
+ return TemplateKW.getValueOr(SourceLocation());
+ }
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+ bool isRequired() const { return TemplateKW != SourceLocation(); }
+ explicit operator bool() const { return isRequired(); }
+
+ private:
+ llvm::Optional<SourceLocation> TemplateKW;
+ };
+
enum class AssumedTemplateKind {
/// This is not assumed to be a template name.
None,
/// functions (but no function templates).
FoundFunctions,
};
- bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext,
- bool &MemberOfUnknownSpecialization,
- SourceLocation TemplateKWLoc = SourceLocation(),
- AssumedTemplateKind *ATK = nullptr,
- bool Disambiguation = false);
+ bool LookupTemplateName(
+ LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
+ bool EnteringContext, bool &MemberOfUnknownSpecialization,
+ RequiredTemplateKind RequiredTemplate = SourceLocation(),
+ AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
MemberOfUnknownSpecialization, SourceLocation(),
- &AssumedTemplate, Disambiguation))
+ &AssumedTemplate,
+ /*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
if (AssumedTemplate != AssumedTemplateKind::None) {
QualType ObjectType,
bool EnteringContext,
bool &MemberOfUnknownSpecialization,
- SourceLocation TemplateKWLoc,
+ RequiredTemplateKind RequiredTemplate,
AssumedTemplateKind *ATK,
- bool Disambiguation) {
+ bool AllowTypoCorrection) {
if (ATK)
*ATK = AssumedTemplateKind::None;
if (Found.isAmbiguous())
return false;
- if (ATK && SS.isEmpty() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
+ if (ATK && SS.isEmpty() && ObjectType.isNull() &&
+ !RequiredTemplate.hasTemplateKeyword()) {
// C++2a [temp.names]p2:
// A name is also considered to refer to a template if it is an
// unqualified-id followed by a < and name lookup finds either one or more
}
}
- if (Found.empty() && !IsDependent && !Disambiguation) {
+ if (Found.empty() && !IsDependent && AllowTypoCorrection) {
// If we did not find any names, and this is not a disambiguation, attempt
// to correct any typos.
DeclarationName Name = Found.getLookupName();
// If a 'template' keyword was used, a lookup that finds only non-template
// names is an error.
- if (ExampleLookupResult && TemplateKWLoc.isValid()) {
+ if (ExampleLookupResult && RequiredTemplate) {
Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template)
- << Found.getLookupName() << SS.getRange();
+ << Found.getLookupName() << SS.getRange()
+ << RequiredTemplate.hasTemplateKeyword()
+ << RequiredTemplate.getTemplateKeywordLoc();
Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(),
diag::note_template_kw_refers_to_non_template)
<< Found.getLookupName();
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
LookupOrdinaryName);
bool MOUS;
- // FIXME: If LookupTemplateName fails here, we'll have produced its
- // diagnostics twice.
- if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
- MOUS, TemplateKWLoc) && !R.isAmbiguous()) {
+ // Tell LookupTemplateName that we require a template so that it diagnoses
+ // cases where it finds a non-template.
+ RequiredTemplateKind RTK = TemplateKWLoc.isValid()
+ ? RequiredTemplateKind(TemplateKWLoc)
+ : TemplateNameIsRequired;
+ if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
+ RTK, nullptr, /*AllowTypoCorrection=*/false) &&
+ !R.isAmbiguous()) {
if (LookupCtx)
Diag(Name.getBeginLoc(), diag::err_no_member)
<< DNI.getName() << LookupCtx << SS.getRange();
void h3(N::G<int> *p) { p->~G<int>(); }
void h4(N::G<int> *p) { f(p); }
}
+
+ namespace TemplateNamesNonTemplate {
+ int A; // expected-note 2{{non-template here}}
+ template<typename> int B; // expected-note 2{{variable template 'B' declared here}} expected-warning {{extension}}
+ using C = int; // expected-note 2{{non-template here}}
+
+ template<typename T> void f1(int *p) { p->~A<int>(); } // expected-error {{'A' does not refer to a template}}
+ template<typename T> void f2(int *p) { p->~B<int>(); } // expected-error {{template name refers to non-type template 'B'}}
+ template<typename T> void f3(int *p) { p->~C<int>(); } // expected-error {{'C' does not refer to a template}}
+ template<typename T> void f4(int *p) { p->TemplateNamesNonTemplate::C::~A<int>(); } // expected-error {{'A' does not refer to a template}}
+ template<typename T> void f5(int *p) { p->TemplateNamesNonTemplate::C::~B<int>(); } // expected-error {{template name refers to non-type template 'TemplateNamesNonTemplate::B'}}
+ template<typename T> void f6(int *p) { p->TemplateNamesNonTemplate::C::~C<int>(); } // expected-error {{'C' does not refer to a template}}
+ }
}