https://github.com/keepyixiao updated 
https://github.com/llvm/llvm-project/pull/222523

>From d5b96615e43b04cc6be70cd80627f6969fd511fa Mon Sep 17 00:00:00 2001
From: nudt_yixiao <[email protected]>
Date: Fri, 25 Sep 2026 10:13:26 +0800
Subject: [PATCH] [Clang] Fix stale linkage cache when merging redeclarations

A linkage query before a declaration is connected to a preceding static
declaration may leave stale cached linkage and trigger an assertion.

Invalidate cached linkage in Redeclarable::setPreviousDecl() so it is
recomputed from the complete redeclaration chain.

Add regression tests for C variables and functions and C++ variable
templates.
---
 clang/docs/ReleaseNotes.md           |  3 ++-
 clang/include/clang/AST/Decl.h       |  3 +++
 clang/test/Sema/redefine_extname.c   | 11 +++++++++++
 clang/test/Sema/redefine_extname.cpp |  8 ++++++++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 78eb1aab3ed66..d824dab47adbd 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -580,7 +580,8 @@ features cannot lower the translation-unit ABI level;
   (e.g. `({ s.b; })`) was not subject to integer promotion, unlike an ordinary
   bit-field access. (#GH221542)
 - No longer crashing due to follow-on diagnostics when there is an invalid 
operand in a logical operator involving a vector operand. (#GH227588)
-  
+- Fixed assertion failures caused by stale linkage information when an extern 
variable or function declaration is merged with a preceding static declaration. 
(#GH204759, #GH204754)
+
 #### Bug Fixes to Compiler Builtins
 
 - Fixed a crash when classifying a call to a builtin with dependent arguments,
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index c64dc8c02d40e..f809b475eea5c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -5472,6 +5472,9 @@ void Redeclarable<decl_type>::setPreviousDecl(decl_type 
*PrevDecl) {
          "setPreviousDecl on a decl already in a redeclaration chain");
 
   if (PrevDecl) {
+    // Linking this declaration to a previous one may change its linkage.
+    static_cast<decl_type *>(this)->invalidateCachedLinkage();
+
     // Point to previous. Make sure that this is actually the most recent
     // redeclaration, or we can build invalid chains. If the most recent
     // redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
diff --git a/clang/test/Sema/redefine_extname.c 
b/clang/test/Sema/redefine_extname.c
index 8ccac7ffcd413..c20d426295f1b 100644
--- a/clang/test/Sema/redefine_extname.c
+++ b/clang/test/Sema/redefine_extname.c
@@ -5,4 +5,15 @@
 #pragma redefine_extname foo_static bar_static
 static int foo_static(void) { return 1; } // expected-warning {{#pragma 
redefine_extname is applicable to external C declarations only; not applied to 
function 'foo_static'}}
 
+// Computing whether the declarations have external C linkage must not leave a
+// stale linkage cached before they are connected to the preceding static
+// declarations.
+#pragma redefine_extname variable_after_static variable_alias
+static int variable_after_static; // expected-warning {{#pragma 
redefine_extname is applicable to external C declarations only; not applied to 
variable 'variable_after_static'}}
+extern int variable_after_static;
+
+#pragma redefine_extname function_after_static function_alias
+static int function_after_static(void); // expected-warning {{#pragma 
redefine_extname is applicable to external C declarations only; not applied to 
function 'function_after_static'}}
+extern int function_after_static(void);
+
 unsigned __int128_t; // expected-error {{redefinition of '__int128_t' as 
different kind of symbol}}
diff --git a/clang/test/Sema/redefine_extname.cpp 
b/clang/test/Sema/redefine_extname.cpp
index 7a0066b887d0e..16a436fdfb996 100644
--- a/clang/test/Sema/redefine_extname.cpp
+++ b/clang/test/Sema/redefine_extname.cpp
@@ -22,6 +22,14 @@ int foo_cppfunc() { return 1; } // expected-warning 
{{#pragma redefine_extname i
 int foo_cppvar = 1; // expected-warning {{#pragma redefine_extname is 
applicable to external C declarations only; not applied to variable 
'foo_cppvar'}}
 // CHECK-DAG: {{@[^ ]*foo_cppvar}}
 
+/// Check that merging variable template declarations does not leave stale
+/// linkage information.
+#pragma redefine_extname a alias
+template <typename>
+static int a; // expected-warning {{#pragma redefine_extname is applicable to 
external C declarations only; not applied to variable 'a'}}
+template <typename>
+extern int a; // expected-warning {{#pragma redefine_extname is applicable to 
external C declarations only; not applied to variable 'a'}}
+
 /// Check that the warning goes away when doing it in a namespace.
 /// Such uses are clearly scoped and need no warning (and often can be 
intentional).
 #pragma redefine_extname foo_nsfunc check_not_bar_nsfunc

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

Reply via email to