[clang] Reapply "[Clang][Sema] Diagnose function/variable templates that shadow their own template parameters (#78274)" (PR #79683)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 27 01:11:27 PST 2024


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 <sdkrystian at 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 at -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 at -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 at -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 at -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 at -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 at -1{{template parameter is declared here}}
+  };
 }
 
 namespace PR28023 {



More information about the cfe-commits mailing list