Author: Richard Smith Date: 2020-03-29T13:15:30-07:00 New Revision: a5458bb0d6b1c35c7dcca4f339e77c40f5fc5e06
URL: https://github.com/llvm/llvm-project/commit/a5458bb0d6b1c35c7dcca4f339e77c40f5fc5e06 DIFF: https://github.com/llvm/llvm-project/commit/a5458bb0d6b1c35c7dcca4f339e77c40f5fc5e06.diff LOG: Don't claim template names that name non-templates are undeclared. Added: Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaTemplate.cpp clang/test/SemaCXX/pseudo-destructors.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b48f92f38939..cdc0d9688c08 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4916,7 +4916,8 @@ def note_using_value_decl_missing_typename : Note< "add 'typename' to treat this using declaration as a type">; def err_template_kw_refers_to_non_template : Error< - "%0 following the 'template' keyword does not refer to a template">; + "%0%select{| following the 'template' keyword}1 " + "does not refer to a template">; def note_template_kw_refers_to_non_template : Note< "declared as a non-template here">; def err_template_kw_refers_to_dependent_non_template : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b4b2611481db..ecda3f4692a5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6999,6 +6999,27 @@ class Sema final { 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, @@ -7008,12 +7029,11 @@ class Sema final { /// 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, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1e2ebc5037bc..342262522e61 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -205,7 +205,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, 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) { @@ -371,9 +372,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, - SourceLocation TemplateKWLoc, + RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, - bool Disambiguation) { + bool AllowTypoCorrection) { if (ATK) *ATK = AssumedTemplateKind::None; @@ -473,7 +474,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, 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 @@ -499,7 +501,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, } } - 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(); @@ -545,9 +547,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, // 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(); @@ -4722,10 +4726,14 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, 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(); diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index 292324893dd0..7a5c540794e2 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/clang/test/SemaCXX/pseudo-destructors.cpp @@ -169,4 +169,17 @@ namespace TwoPhaseLookup { 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}} + } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits