Skip to content

Commit a5458bb

Browse files
committed
Don't claim template names that name non-templates are undeclared.
1 parent 00c76f3 commit a5458bb

File tree

4 files changed

+60
-18
lines changed

4 files changed

+60
-18
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4916,7 +4916,8 @@ def note_using_value_decl_missing_typename : Note<
49164916
"add 'typename' to treat this using declaration as a type">;
49174917

49184918
def err_template_kw_refers_to_non_template : Error<
4919-
"%0 following the 'template' keyword does not refer to a template">;
4919+
"%0%select{| following the 'template' keyword}1 "
4920+
"does not refer to a template">;
49204921
def note_template_kw_refers_to_non_template : Note<
49214922
"declared as a non-template here">;
49224923
def err_template_kw_refers_to_dependent_non_template : Error<

clang/include/clang/Sema/Sema.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6999,6 +6999,27 @@ class Sema final {
69996999
bool AllowFunctionTemplates = true,
70007000
bool AllowDependent = true);
70017001

7002+
enum TemplateNameIsRequiredTag { TemplateNameIsRequired };
7003+
/// Whether and why a template name is required in this lookup.
7004+
class RequiredTemplateKind {
7005+
public:
7006+
/// Template name is required if TemplateKWLoc is valid.
7007+
RequiredTemplateKind(SourceLocation TemplateKWLoc = SourceLocation())
7008+
: TemplateKW(TemplateKWLoc) {}
7009+
/// Template name is unconditionally required.
7010+
RequiredTemplateKind(TemplateNameIsRequiredTag) : TemplateKW() {}
7011+
7012+
SourceLocation getTemplateKeywordLoc() const {
7013+
return TemplateKW.getValueOr(SourceLocation());
7014+
}
7015+
bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
7016+
bool isRequired() const { return TemplateKW != SourceLocation(); }
7017+
explicit operator bool() const { return isRequired(); }
7018+
7019+
private:
7020+
llvm::Optional<SourceLocation> TemplateKW;
7021+
};
7022+
70027023
enum class AssumedTemplateKind {
70037024
/// This is not assumed to be a template name.
70047025
None,
@@ -7008,12 +7029,11 @@ class Sema final {
70087029
/// functions (but no function templates).
70097030
FoundFunctions,
70107031
};
7011-
bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
7012-
QualType ObjectType, bool EnteringContext,
7013-
bool &MemberOfUnknownSpecialization,
7014-
SourceLocation TemplateKWLoc = SourceLocation(),
7015-
AssumedTemplateKind *ATK = nullptr,
7016-
bool Disambiguation = false);
7032+
bool LookupTemplateName(
7033+
LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
7034+
bool EnteringContext, bool &MemberOfUnknownSpecialization,
7035+
RequiredTemplateKind RequiredTemplate = SourceLocation(),
7036+
AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
70177037

70187038
TemplateNameKind isTemplateName(Scope *S,
70197039
CXXScopeSpec &SS,

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
205205
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
206206
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
207207
MemberOfUnknownSpecialization, SourceLocation(),
208-
&AssumedTemplate, Disambiguation))
208+
&AssumedTemplate,
209+
/*AllowTypoCorrection=*/!Disambiguation))
209210
return TNK_Non_template;
210211

211212
if (AssumedTemplate != AssumedTemplateKind::None) {
@@ -371,9 +372,9 @@ bool Sema::LookupTemplateName(LookupResult &Found,
371372
QualType ObjectType,
372373
bool EnteringContext,
373374
bool &MemberOfUnknownSpecialization,
374-
SourceLocation TemplateKWLoc,
375+
RequiredTemplateKind RequiredTemplate,
375376
AssumedTemplateKind *ATK,
376-
bool Disambiguation) {
377+
bool AllowTypoCorrection) {
377378
if (ATK)
378379
*ATK = AssumedTemplateKind::None;
379380

@@ -473,7 +474,8 @@ bool Sema::LookupTemplateName(LookupResult &Found,
473474
if (Found.isAmbiguous())
474475
return false;
475476

476-
if (ATK && SS.isEmpty() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
477+
if (ATK && SS.isEmpty() && ObjectType.isNull() &&
478+
!RequiredTemplate.hasTemplateKeyword()) {
477479
// C++2a [temp.names]p2:
478480
// A name is also considered to refer to a template if it is an
479481
// unqualified-id followed by a < and name lookup finds either one or more
@@ -499,7 +501,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
499501
}
500502
}
501503

502-
if (Found.empty() && !IsDependent && !Disambiguation) {
504+
if (Found.empty() && !IsDependent && AllowTypoCorrection) {
503505
// If we did not find any names, and this is not a disambiguation, attempt
504506
// to correct any typos.
505507
DeclarationName Name = Found.getLookupName();
@@ -545,9 +547,11 @@ bool Sema::LookupTemplateName(LookupResult &Found,
545547

546548
// If a 'template' keyword was used, a lookup that finds only non-template
547549
// names is an error.
548-
if (ExampleLookupResult && TemplateKWLoc.isValid()) {
550+
if (ExampleLookupResult && RequiredTemplate) {
549551
Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template)
550-
<< Found.getLookupName() << SS.getRange();
552+
<< Found.getLookupName() << SS.getRange()
553+
<< RequiredTemplate.hasTemplateKeyword()
554+
<< RequiredTemplate.getTemplateKeywordLoc();
551555
Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(),
552556
diag::note_template_kw_refers_to_non_template)
553557
<< Found.getLookupName();
@@ -4722,10 +4726,14 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
47224726
LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
47234727
LookupOrdinaryName);
47244728
bool MOUS;
4725-
// FIXME: If LookupTemplateName fails here, we'll have produced its
4726-
// diagnostics twice.
4727-
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
4728-
MOUS, TemplateKWLoc) && !R.isAmbiguous()) {
4729+
// Tell LookupTemplateName that we require a template so that it diagnoses
4730+
// cases where it finds a non-template.
4731+
RequiredTemplateKind RTK = TemplateKWLoc.isValid()
4732+
? RequiredTemplateKind(TemplateKWLoc)
4733+
: TemplateNameIsRequired;
4734+
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
4735+
RTK, nullptr, /*AllowTypoCorrection=*/false) &&
4736+
!R.isAmbiguous()) {
47294737
if (LookupCtx)
47304738
Diag(Name.getBeginLoc(), diag::err_no_member)
47314739
<< DNI.getName() << LookupCtx << SS.getRange();

clang/test/SemaCXX/pseudo-destructors.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,17 @@ namespace TwoPhaseLookup {
169169
void h3(N::G<int> *p) { p->~G<int>(); }
170170
void h4(N::G<int> *p) { f(p); }
171171
}
172+
173+
namespace TemplateNamesNonTemplate {
174+
int A; // expected-note 2{{non-template here}}
175+
template<typename> int B; // expected-note 2{{variable template 'B' declared here}} expected-warning {{extension}}
176+
using C = int; // expected-note 2{{non-template here}}
177+
178+
template<typename T> void f1(int *p) { p->~A<int>(); } // expected-error {{'A' does not refer to a template}}
179+
template<typename T> void f2(int *p) { p->~B<int>(); } // expected-error {{template name refers to non-type template 'B'}}
180+
template<typename T> void f3(int *p) { p->~C<int>(); } // expected-error {{'C' does not refer to a template}}
181+
template<typename T> void f4(int *p) { p->TemplateNamesNonTemplate::C::~A<int>(); } // expected-error {{'A' does not refer to a template}}
182+
template<typename T> void f5(int *p) { p->TemplateNamesNonTemplate::C::~B<int>(); } // expected-error {{template name refers to non-type template 'TemplateNamesNonTemplate::B'}}
183+
template<typename T> void f6(int *p) { p->TemplateNamesNonTemplate::C::~C<int>(); } // expected-error {{'C' does not refer to a template}}
184+
}
172185
}

0 commit comments

Comments
 (0)