[clang] [Clang] Avoid assertion failure for initialized extern aliases (PR #223124)

via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 3 02:10:35 PDT 2026


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

>From a632b459912d1fc82b0194ada9d0358ef117cfb6 Mon Sep 17 00:00:00 2001
From: nudt_yixiao <1272950933 at qq.com>
Date: Wed, 23 Sep 2026 10:39:13 +0800
Subject: [PATCH] [Clang] Fix handling of alias variable definitions

Fix an assertion when an alias variable has an initializer, and treat
defining attributes on in-class static data members as definitions so that
later out-of-line definitions are correctly diagnosed.

Add regression tests and a release note.
---
 clang/docs/ReleaseNotes.md           |  5 ++
 clang/lib/AST/Decl.cpp               |  2 +-
 clang/lib/Sema/SemaDecl.cpp          |  2 +-
 clang/test/Sema/alias-redefinition.c | 69 ++++++++++++++++++++++++++--
 4 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f6cdca91cea1035..bdad85326c6263e 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -590,6 +590,11 @@ features cannot lower the translation-unit ABI level;
   written after the declarator-id, where it appertains to the declared entity
   rather than to a declarator chunk. (#GH196982, #GH111463)
 
+- Fixed an assertion failure when the `alias` attribute was applied to an
+  `extern` variable with an initializer. Static data members declared with
+  `alias` are now correctly diagnosed as definitions when followed by an
+  out-of-line definition. (#GH204762)
+
 #### Bug Fixes to C++ Support
 
 - Fixed lambdas with specifiers or attributes after the capture list being
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index ffd9bd33c7501c4..b094137cee347b3 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2268,7 +2268,7 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
                     TSK_ExplicitSpecialization) ||
          isa<VarTemplatePartialSpecializationDecl>(this)))
       return Definition;
-    if (!isOutOfLine() && isInline())
+    if (!isOutOfLine() && (isInline() || hasDefiningAttr()))
       return Definition;
     return DeclarationOnly;
   }
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index db5e66cb96c3ec0..94da9e77e4d972b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7192,7 +7192,7 @@ static void checkAliasAttr(Sema &S, NamedDecl &ND) {
     if (VD->hasInit()) {
       if (const auto *Attr = VD->getAttr<AliasAttr>()) {
         assert(VD->isThisDeclarationADefinition() &&
-               !VD->isExternallyVisible() && "Broken AliasAttr handled late!");
+               "Broken AliasAttr handled late!");
         S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD << 0;
         VD->dropAttr<AliasAttr>();
       }
diff --git a/clang/test/Sema/alias-redefinition.c b/clang/test/Sema/alias-redefinition.c
index 526b67d9be7f298..7b5a8a0fe5993dc 100644
--- a/clang/test/Sema/alias-redefinition.c
+++ b/clang/test/Sema/alias-redefinition.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -Wno-strict-prototypes -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -Wno-strict-prototypes -fsyntax-only -verify=expected,c %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -Wno-strict-prototypes -x c++ -fsyntax-only -verify=expected,cxx %s
 
 void f0() {}
 void fun0(void) __attribute((alias("f0")));
@@ -22,11 +23,73 @@ void fun4(void);
 void f5() {}
 void __attribute((alias("f5"))) fun5(void) {} // expected-error {{definition 'fun5' cannot also be an alias}}
 
+typedef void (*func_ptr)(void);
+
+static void implementation(void) {}
+
+static func_ptr resolver1(void) {
+  return implementation;
+}
+
+void f6(void) __attribute__((ifunc("resolver1"))); // expected-note {{previous definition is here}}
+void f6(void) __attribute__((alias("implementation"))); // expected-error {{redefinition of 'f6'}}
+
+void f7(void) __attribute__((alias("implementation"))); // expected-note {{previous definition is here}}
+void f7(void) __attribute__((ifunc("resolver1"))); // expected-error {{redefinition of 'f7'}}
+
+void f8(void) __attribute__((ifunc("resolver1"), alias("implementation"))); // expected-error {{definition 'f8' cannot also be an alias}}
+
+void f9(void) __attribute__((alias("implementation"), ifunc("resolver1"))); // expected-error {{definition 'f9' cannot also be an ifunc}}
+
 int var1 __attribute((alias("v1"))); // expected-error {{definition 'var1' cannot also be an alias}}
 static int var2 __attribute((alias("v2"))) = 2; // expected-error {{definition 'var2' cannot also be an alias}}
+extern int var_with_extern_initializer __attribute__((alias(""))) = 42; // expected-error {{definition 'var_with_extern_initializer' cannot also be an alias}}
+// expected-warning at -1 {{'extern' variable has an initializer}}
+extern int var_with_extern_initializer1 __attribute__((alias("v1"))) = 42; // expected-error {{definition 'var_with_extern_initializer1' cannot also be an alias}}
+// expected-warning at -1 {{'extern' variable has an initializer}}
+
+int target;
+int loader_then_alias __attribute((loader_uninitialized, alias("target"))); // expected-error {{definition 'loader_then_alias' cannot also be an alias}}
+
+int alias_then_loader __attribute((alias("target"), loader_uninitialized)); // expected-error {{definition 'alias_then_loader' cannot also be an alias}}
+
+int loader_redecl_alias __attribute((loader_uninitialized)); // expected-note {{previous definition is here}}
+extern int loader_redecl_alias __attribute((alias("target"))); // expected-error {{redefinition of 'loader_redecl_alias'}}
+
+extern int loader_redecl_alias1 __attribute((alias("target"))); // c-note {{previous definition is here}} cxx-note 2 {{previous definition is here}}
+int loader_redecl_alias1 __attribute((loader_uninitialized));
+// c-error at -1 {{redeclaration cannot add 'loader_uninitialized' attribute}}
+// cxx-error at -2 {{redefinition of 'loader_redecl_alias1'}}
+// cxx-warning at -3 {{attribute declaration must precede definition}}
 
 extern int var3 __attribute__((alias("C"))); // expected-note{{previous definition is here}}
 int var3 = 3; // expected-error{{redefinition of 'var3'}}
 
-int var4; // expected-note{{previous definition is here}}
-extern int var4 __attribute__((alias("v4"))); // expected-error{{alias definition of 'var4' after tentative definition}}
+int var4; // expected-note {{previous definition is here}}
+extern int var4 __attribute__((alias("v4")));
+// c-error at -1 {{alias definition of 'var4' after tentative definition}}
+// cxx-error at -2 {{redefinition of 'var4'}}
+
+
+#ifdef __cplusplus
+
+int foo;
+struct S {
+  static const int i __attribute__((alias("foo"))) = 12; // expected-error {{definition 'i' cannot also be an alias}}
+};
+
+struct OutOfLineDefinitionWithInitializer {
+  static int i __attribute__((alias("foo"))); // expected-note {{previous definition is here}}
+};
+int OutOfLineDefinitionWithInitializer::i = 12; // expected-error {{redefinition of 'i'}}
+
+struct OutOfLineDefinitionWithoutInitializer {
+  static int i1 __attribute__((alias("foo"))); // expected-note {{previous definition is here}}
+};
+int OutOfLineDefinitionWithoutInitializer::i1; // expected-error {{redefinition of 'i1'}}
+
+struct AliasDefinition {
+  static int i2 __attribute__((alias("foo")));
+};
+
+#endif



More information about the cfe-commits mailing list