https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/79683
Reapplies #78274 with the addition of a default-error warning (`strict-primary-template-shadow`) that is issued for instances of shadowing which were previously accepted prior to this patch. >From abc8f062add9e41ce00b9d035c796256a62859ef Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 16 Jan 2024 08:05:33 -0500 Subject: [PATCH] Reapply "[Clang][Sema] Diagnose function/variable templates that shadow their own template parameters (#78274)" --- clang/docs/ReleaseNotes.rst | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/SemaDecl.cpp | 31 +++++++++++++------ clang/lib/Sema/SemaTemplate.cpp | 9 ++++-- .../test/CXX/temp/temp.res/temp.local/p6.cpp | 22 ++++++++++--- 6 files changed, 51 insertions(+), 17 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5330cd9caad8011..24d3ada5bfd9dfc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -97,6 +97,7 @@ Attribute Changes in Clang Improvements to Clang's diagnostics ----------------------------------- +- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``. Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 649de9f47c46195..4e3b20548913ab5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4966,6 +4966,9 @@ def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def ext_template_param_shadow : ExtWarn< err_template_param_shadow.Summary>, InGroup<MicrosoftTemplateShadow>; +def ext_compat_template_param_shadow : ExtWarn< + err_template_param_shadow.Summary>, InGroup< + DiagGroup<"strict-primary-template-shadow">>, DefaultError; def note_template_param_here : Note<"template parameter is declared here">; def note_template_param_external : Note< "template parameter from hidden source: %0">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1f1cbd11ff73581..5c148db48140ed4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8256,7 +8256,7 @@ class Sema final { TemplateSpecializationKind TSK, bool Complain = true); - void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl, bool IssueWarning = false); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); NamedDecl *ActOnTypeParameter(Scope *S, bool Typename, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f9bf1d14bdc4f68..de65b3c09c28cfe 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6377,12 +6377,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) return nullptr; - // The scope passed in may not be a decl scope. Zip up the scope tree until - // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0 || - (S->getFlags() & Scope::TemplateParamScope) != 0) - S = S->getParent(); - DeclContext *DC = CurContext; if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); @@ -6506,12 +6500,25 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, RemoveUsingDecls(Previous); } - if (Previous.isSingleResult() && - Previous.getFoundDecl()->isTemplateParameter()) { + // if (Previous.isSingleResult() && + // Previous.getFoundDecl()->isTemplateParameter()) { + if (auto *TPD = Previous.getAsSingle<NamedDecl>(); TPD && TPD->isTemplateParameter()) { + // Older versions of clang allowed the names of function/variable templates + // to shadow the names of their template parameters. For the compatibility purposes + // we detect such cases and issue a default-to-error warning that can be disabled with + // -fno-strict-primary-template-shadow. + bool IssueShadowingWarning = false; + for (Scope *Inner = S; (Inner->getFlags() & Scope::DeclScope) == 0 || + Inner->isTemplateParamScope(); Inner = Inner->getParent()) { + if (IssueShadowingWarning = Inner->isDeclScope(TPD)) + break; + } + // Maybe we will complain about the shadowed template parameter. if (!D.isInvalidType()) DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), - Previous.getFoundDecl()); + TPD, + IssueShadowingWarning); // Just pretend that we didn't see the previous declaration. Previous.clear(); @@ -6535,6 +6542,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (getLangOpts().CPlusPlus) CheckExtraCXXDefaultArguments(D); + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) + S = S->getParent(); + NamedDecl *New; bool AddToScope = true; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9bfa71dc8bcf1db..4ba8dfc19d2f6d6 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -885,7 +885,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, /// that the template parameter 'PrevDecl' is being shadowed by a new /// declaration at location Loc. Returns true to indicate that this is /// an error, and false otherwise. -void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { +void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl, bool IssueWarning) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); // C++ [temp.local]p4: @@ -893,8 +893,11 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { // scope (including nested scopes). // // Make this a warning when MSVC compatibility is requested. - unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow - : diag::err_template_param_shadow; + unsigned DiagId = getLangOpts().MSVCCompat + ? diag::ext_template_param_shadow + : (IssueWarning + ? diag::ext_compat_template_param_shadow + : diag::err_template_param_shadow); const auto *ND = cast<NamedDecl>(PrevDecl); Diag(Loc, DiagId) << ND->getDeclName(); NoteTemplateParameterLocation(*ND); diff --git a/clang/test/CXX/temp/temp.res/temp.local/p6.cpp b/clang/test/CXX/temp/temp.res/temp.local/p6.cpp index e2aa0ff344291d2..00bb35813c39af6 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p6.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p6.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y +// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y -Wno-error=strict-primary-template-shadow namespace N {} @@ -127,16 +127,30 @@ template<int T> struct Z { // expected-note 16{{declared here}} template<typename T> // expected-note {{declared here}} void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}} -// FIXME: These are ill-formed: a template-parameter shall not have the same name as the template name. namespace A { template<typename T> struct T {}; // expected-error{{declaration of 'T' shadows template parameter}} // expected-note@-1{{template parameter is declared here}} + template<typename T> struct U { + template<typename V> struct V {}; // expected-error{{declaration of 'V' shadows template parameter}} + // expected-note@-1{{template parameter is declared here}} + }; } namespace B { - template<typename T> void T() {} + template<typename T> void T() {} // expected-warning{{declaration of 'T' shadows template parameter}} + // expected-note@-1{{template parameter is declared here}} + + template<typename T> struct U { + template<typename V> void V(); // expected-warning{{declaration of 'V' shadows template parameter}} + // expected-note@-1{{template parameter is declared here}} + }; } namespace C { - template<typename T> int T; + template<typename T> int T; // expected-warning{{declaration of 'T' shadows template parameter}} + // expected-note@-1{{template parameter is declared here}} + template<typename T> struct U { + template<typename V> static int V; // expected-warning{{declaration of 'V' shadows template parameter}} + // expected-note@-1{{template parameter is declared here}} + }; } namespace PR28023 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits