[clang] [Clang] Fix stale linkage cache when merging redeclarations (PR #222523)

via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 21 06:54:56 PDT 2026


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

>From 62ac8ff76f2bf0111d419e964599e19d89cddcb5 Mon Sep 17 00:00:00 2001
From: yixiao <yixiao at hygon.cn>
Date: Thu, 10 Sep 2026 14:46:10 +0800
Subject: [PATCH] [Clang] Fix stale linkage cache when merging redeclarations

Sema may cache external linkage for an extern declaration
before it is connected to a preceding static declaration,
leaving stale linkage information that can trigger an assertion
while building the redeclaration chain.

Invalidate the cached linkage before connecting variable and function
declarations to their previous declarations, allowing it to be recomputed
from the complete redeclaration chain.

Add regression tests for both variable and function declarations.
---
 clang/docs/ReleaseNotes.md         |  1 +
 clang/lib/AST/Decl.cpp             |  2 ++
 clang/lib/Sema/SemaDecl.cpp        |  3 +++
 clang/test/Sema/redefine_extname.c | 11 +++++++++++
 4 files changed, 17 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 59b5c14c59242..670857884dc64 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -509,6 +509,7 @@ features cannot lower the translation-unit ABI level;
 - Fixed a bug where repeated #imports of modular headers in non-modular compilation were translated to #pragma clang module import. (#GH216924)
 - Fixed an assertion when `#pragma omp declare simd` or `#pragma omp declare variant` is followed by another OpenMP declarative directive containing a qualified identifier. (#GH217204)
 - Fixed a crash when an `asm` label names the register for a global variable of incomplete type. (#GH219746)
+- 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
 
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a620e9f211ca6..84a1648c78c1c 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3775,6 +3775,8 @@ bool FunctionDecl::isTargetVersionMultiVersion() const {
 
 void
 FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
+  // Linking this declaration to a previous one may change its linkage.
+  invalidateCachedLinkage();
   redeclarable_base::setPreviousDecl(PrevDecl);
 
   if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a9047f61a8bf5..7a5f1cb6bddb6 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4984,6 +4984,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
   if (Old->getMostRecentDecl()->isUsed(false))
     New->setIsUsed();
 
+  // Linking this declaration to a previous one may change its linkage.
+  New->invalidateCachedLinkage();
+
   // Keep a chain of previous declarations.
   New->setPreviousDecl(Old);
   if (NewTemplate)
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}}



More information about the cfe-commits mailing list