Author: Erich Keane
Date: 2026-07-20T07:32:26-07:00
New Revision: 35aa7b529ebeafc9767a4c5398047a92b86bd4a8

URL: 
https://github.com/llvm/llvm-project/commit/35aa7b529ebeafc9767a4c5398047a92b86bd4a8
DIFF: 
https://github.com/llvm/llvm-project/commit/35aa7b529ebeafc9767a4c5398047a92b86bd4a8.diff

LOG: Ensure that we properly propagate template decl attributes to redecls 
(#209873)

Variable and class templates weren't forwarding their declaration
attributes that were attached directly to them (at the moment, the only
one I could find that had this issue is the no_specialization attr). The
result was that intermediate redeclarations would prevent the
diagnostics from happening.

This patch ensures we propagate them properly for variable and class
templates. It seems our function templates already do the right thing.

Fixes: #209812

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.md
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/SemaCXX/attr-no-specializations.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 9301745b9628e..5f759555e371c 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -123,6 +123,8 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 ### Attribute Changes in Clang
 
+- Clang now properly propagates attributes on class and variable templates to 
their redeclarations, which will result in redeclarations not interfering with 
diagnostics. (#GH209812)
+
 ### Improvements to Clang's diagnostics
 
 - Fixed bug in `-Wdocumentation` so that it correctly handles explicit

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 47f2b9f597c72..7de5542e72559 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4768,7 +4768,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult 
&Previous) {
     New->setInvalidDecl();
   }
 
+  if (NewTemplate && OldTemplate)
+    mergeDeclAttributes(NewTemplate, OldTemplate);
+
   mergeDeclAttributes(New, Old);
+
   // Warn if an already-defined variable is made a weak_import in a subsequent
   // declaration
   if (New->hasAttr<WeakImportAttr>())

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0d1e01df75d94..643392833759d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2289,8 +2289,10 @@ DeclResult Sema::CheckClassTemplate(
 
   ProcessDeclAttributeList(S, NewClass, Attr);
 
-  if (PrevClassTemplate)
+  if (PrevClassTemplate) {
+    mergeDeclAttributes(NewTemplate, PrevClassTemplate);
     mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
+  }
 
   AddPushedVisibilityAttribute(NewClass);
   inferGslOwnerPointerAttribute(NewClass);

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2a711db70280e..921a9f965fb9c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2538,6 +2538,8 @@ Decl 
*TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
   }
 
   Owner->addDecl(Inst);
+  SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, Inst, LateAttrs,
+                                  StartingScope);
 
   if (!PrevVarTemplate) {
     // Queue up any out-of-line partial specializations of this member

diff  --git a/clang/test/SemaCXX/attr-no-specializations.cpp 
b/clang/test/SemaCXX/attr-no-specializations.cpp
index 1fb57db14a446..4ff23bb6e8a04 100644
--- a/clang/test/SemaCXX/attr-no-specializations.cpp
+++ b/clang/test/SemaCXX/attr-no-specializations.cpp
@@ -60,3 +60,25 @@ template <class T>
 [[clang::no_specializations]] void func(); // expected-note {{marked 
'clang::no_specializations' here}}
 
 template <> void func<int>(); // expected-error {{'func' cannot be 
specialized}}
+
+namespace DeclBetween {
+template <class T>
+[[clang::no_specializations]] void func(); // expected-note {{marked 
'clang::no_specializations' here}}
+template<class t> void func(){}
+template <> void func<int>(); // expected-error {{'func' cannot be 
specialized}}
+
+template<typename T>
+struct HasVarDecl {
+template<typename U> static int var_decl[[clang::no_specializations]];// 
expected-note {{marked 'clang::no_specializations' here}}
+};
+
+template<typename T>
+template<typename U> int HasVarDecl<T>::var_decl = 5;
+template<>
+template<>
+int HasVarDecl<int>::var_decl<int>; // expected-error{{'var_decl' cannot be 
specialized}}
+
+template<typename> struct [[clang::no_specializations]] ClassTempl; // 
expected-note {{marked 'clang::no_specializations' here}}
+template<typename> struct ClassTempl { };
+template<> struct ClassTempl<int> { }; // expected-error{{'ClassTempl' cannot 
be specialized}}
+};


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to