https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/237830

>From ec338f3ea77ffccb1d6a9f97a0b1d8e92929be41 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Thu, 29 Oct 2026 23:33:14 +0530
Subject: [PATCH 1/2] [clang] Add regression test for repeated target_clones
 redeclarations

Fixes #149372

A target_clones definition followed by a bare redeclaration and then one
that repeats the attribute asserted with "Default or Generic case must be
last" in the x86 resolver emitter. Sema never linked the bare
redeclaration to the definition, so lookup held two same-type functions
named f, each with the attribute, and emitMultiVersionFunctions collected
every version twice. Clang 18 read only the definition's attribute, which
is why this started in 19.

a redeclaration, so the attribute is inherited and each version is
collected once. This adds the shape from the report so the issue can be
closed.
---
 clang/test/CodeGen/attr-target-clones.c       | 25 ++++++
 .../CodeGenCXX/attr-target-clones-redecl.cpp  | 90 +++++++++++++++++++
 clang/test/Sema/attr-target-clones.c          | 18 ++++
 clang/test/SemaCXX/attr-target-clones.cpp     | 31 +++++++
 4 files changed, 164 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/attr-target-clones-redecl.cpp

diff --git a/clang/test/CodeGen/attr-target-clones.c 
b/clang/test/CodeGen/attr-target-clones.c
index ccf9b5615bde46..4c050870d9811f 100644
--- a/clang/test/CodeGen/attr-target-clones.c
+++ b/clang/test/CodeGen/attr-target-clones.c
@@ -155,6 +155,31 @@ int test_inherited(void) {
   // WINDOWS: call i32 @inherited()
 }
 
+// GH149372
+int __attribute__((target_clones("default,avx"))) redecl(int x) { return x; }
+int redecl(int);
+int __attribute__((target_clones("default,avx"))) redecl(int);
+// LINUX: define {{.*}}i32 @redecl.default.1(
+// LINUX: define {{.*}}i32 @redecl.avx.0(
+// LINUX: define weak_odr ptr @redecl.resolver() #[[ATTR_RESOLVER]] comdat
+// LINUX: ret ptr @redecl.avx.0
+// LINUX-NOT: ret ptr @redecl.avx.0
+// LINUX: ret ptr @redecl.default.1
+
+// DARWIN: define {{.*}}i32 @redecl.default.1(
+// DARWIN: define {{.*}}i32 @redecl.avx.0(
+// DARWIN: define weak_odr ptr @redecl.resolver() #[[ATTR_RESOLVER]] {
+// DARWIN: ret ptr @redecl.avx.0
+// DARWIN-NOT: ret ptr @redecl.avx.0
+// DARWIN: ret ptr @redecl.default.1
+
+// WINDOWS: define dso_local i32 @redecl.default.1(
+// WINDOWS: define dso_local i32 @redecl.avx.0(
+// WINDOWS: define weak_odr dso_local i32 @redecl(i32{{.*}}) 
#[[ATTR_RESOLVER]] comdat
+// WINDOWS: musttail call i32 @redecl.avx.0
+// WINDOWS-NOT: musttail call i32 @redecl.avx.0
+// WINDOWS: musttail call i32 @redecl.default.1
+
 inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
 foo_inline(void) { return 0; }
 inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
diff --git a/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp 
b/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp
new file mode 100644
index 00000000000000..c72beb1e11ccb9
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -emit-llvm-only %s
+
+// GH149372: redeclarations must not duplicate the versions in the resolver.
+
+// CHECK: @_Z1ci.ifunc = weak_odr alias i32 (i32), ptr @_Z1ci
+// CHECK: @_Z1fi.ifunc = weak_odr alias i32 (i32), ptr @_Z1fi
+// CHECK: @_ZN2ns1gEi.ifunc = weak_odr alias i32 (i32), ptr @_ZN2ns1gEi
+// CHECK: @h.ifunc = weak_odr alias i32 (i32), ptr @h
+// CHECK: @_ZL1si.ifunc = internal alias i32 (i32), ptr @_ZL1si
+// CHECK: @_Z1di.ifunc = weak_odr alias i32 (i32), ptr @_Z1di
+// CHECK: @_Z1ci = weak_odr ifunc i32 (i32), ptr @_Z1ci.resolver
+// CHECK: @_Z1fi = weak_odr ifunc i32 (i32), ptr @_Z1fi.resolver
+// CHECK: @_ZN2ns1gEi = weak_odr ifunc i32 (i32), ptr @_ZN2ns1gEi.resolver
+// CHECK: @h = weak_odr ifunc i32 (i32), ptr @h.resolver
+// CHECK: @_ZL1si = internal ifunc i32 (i32), ptr @_ZL1si.resolver
+// CHECK: @_Z1di = weak_odr ifunc i32 (i32), ptr @_Z1di.resolver
+
+int __attribute__((target_clones("default,avx"))) c(int x) { return x; }
+// CHECK: define {{.*}}i32 @_Z1ci.default.1(
+// CHECK: define {{.*}}i32 @_Z1ci.avx.0(
+// CHECK: define weak_odr ptr @_Z1ci.resolver() #[[ATTR_RESOLVER:[0-9]+]] 
comdat
+// CHECK: ret ptr @_Z1ci.avx.0
+// CHECK: ret ptr @_Z1ci.default.1
+
+enum { VALUE = 3 };
+
+extern int glob_x;
+
+int __attribute__((target_clones("default,avx"))) f(int x) { return x + glob_x 
+ VALUE; }
+
+int f(int);
+int __attribute__((target_clones("default,avx"))) f(int);
+// CHECK: define {{.*}}i32 @_Z1fi.default.1(
+// CHECK: define {{.*}}i32 @_Z1fi.avx.0(
+// CHECK: define weak_odr ptr @_Z1fi.resolver() #[[ATTR_RESOLVER]] comdat
+// CHECK: ret ptr @_Z1fi.avx.0
+// CHECK-NOT: ret ptr @_Z1fi.avx.0
+// CHECK: ret ptr @_Z1fi.default.1
+
+namespace ns {
+int __attribute__((target_clones("default,avx"))) g(int x) { return x; }
+int g(int);
+int __attribute__((target_clones("default,avx"))) g(int);
+}
+// CHECK: define {{.*}}i32 @_ZN2ns1gEi.default.1(
+// CHECK: define {{.*}}i32 @_ZN2ns1gEi.avx.0(
+// CHECK: define weak_odr ptr @_ZN2ns1gEi.resolver() #[[ATTR_RESOLVER]] comdat
+// CHECK: ret ptr @_ZN2ns1gEi.avx.0
+// CHECK-NOT: ret ptr @_ZN2ns1gEi.avx.0
+// CHECK: ret ptr @_ZN2ns1gEi.default.1
+
+extern "C" int __attribute__((target_clones("default,avx"))) h(int x) { return 
x; }
+extern "C" int h(int);
+extern "C" int __attribute__((target_clones("default,avx"))) h(int);
+// CHECK: define {{.*}}i32 @h.default.1(
+// CHECK: define {{.*}}i32 @h.avx.0(
+// CHECK: define weak_odr ptr @h.resolver() #[[ATTR_RESOLVER]] comdat
+// CHECK: ret ptr @h.avx.0
+// CHECK-NOT: ret ptr @h.avx.0
+// CHECK: ret ptr @h.default.1
+
+static int __attribute__((target_clones("default,avx"))) s(int x) { return x; }
+static int s(int);
+static int __attribute__((target_clones("default,avx"))) s(int);
+int use_s(int x) { return s(x); }
+// CHECK: define {{.*}}i32 @_Z5use_si(
+// CHECK: call noundef i32 @_ZL1si(
+// CHECK: define internal ptr @_ZL1si.resolver() #[[ATTR_RESOLVER]] {
+// CHECK: ret ptr @_ZL1si.avx.0
+// CHECK-NOT: ret ptr @_ZL1si.avx.0
+// CHECK: ret ptr @_ZL1si.default.1
+
+int __attribute__((target_clones("default,avx"))) d(int);
+int d(int);
+int __attribute__((target_clones("default,avx"))) d(int);
+int d(int x) { return x; }
+int d(int);
+// CHECK: define {{.*}}i32 @_Z1di.default.1(
+// CHECK: define {{.*}}i32 @_Z1di.avx.0(
+// CHECK: define weak_odr ptr @_Z1di.resolver() #[[ATTR_RESOLVER]] comdat
+// CHECK: ret ptr @_Z1di.avx.0
+// CHECK-NOT: ret ptr @_Z1di.avx.0
+// CHECK: ret ptr @_Z1di.default.1
+
+// The internal function's versions are emitted at the end of the module.
+// CHECK: define internal {{.*}}i32 @_ZL1si.default.1(
+// CHECK: define internal {{.*}}i32 @_ZL1si.avx.0(
+
+// CHECK: attributes #[[ATTR_RESOLVER]] = { disable_sanitizer_instrumentation }
diff --git a/clang/test/Sema/attr-target-clones.c 
b/clang/test/Sema/attr-target-clones.c
index 7ff8a02bf53321..918f1dc1340ad4 100644
--- a/clang/test/Sema/attr-target-clones.c
+++ b/clang/test/Sema/attr-target-clones.c
@@ -39,6 +39,24 @@ int __attribute__((target_clones("sse4.2", "default"))) 
redecl7(void);
 // expected-note@-2 {{previous declaration is here}}
 int __attribute__((target("sse4.2"))) redecl7(void) { return 1; }
 
+// GH149372
+int __attribute__((target_clones("sse4.2", "default"))) redecl8(void) { return 
1; }
+int redecl8(void);
+int __attribute__((target_clones("sse4.2", "default"))) redecl8(void);
+
+int __attribute__((target_clones("sse4.2", "default"))) redecl9(void);
+int redecl9(void);
+int __attribute__((target_clones("sse4.2", "default"))) redecl9(void);
+int redecl9(void);
+int __attribute__((target_clones("sse4.2", "default"))) redecl9(void) { return 
1; }
+int redecl9(void);
+
+int __attribute__((target_clones("sse4.2", "default"))) redecl10(void) { 
return 1; }
+int redecl10(void);
+// expected-error@+2 {{'target_clones' attribute does not match previous 
declaration}}
+// expected-note@-2 {{previous declaration is here}}
+int __attribute__((target_clones("arch=atom", "default"))) redecl10(void);
+
 int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
 // expected-error@+2 {{multiversioning attributes cannot be combined}}
 // expected-note@-2 {{previous declaration is here}}
diff --git a/clang/test/SemaCXX/attr-target-clones.cpp 
b/clang/test/SemaCXX/attr-target-clones.cpp
index 68c9a4ff48ed9e..8952beeb47127a 100644
--- a/clang/test/SemaCXX/attr-target-clones.cpp
+++ b/clang/test/SemaCXX/attr-target-clones.cpp
@@ -9,3 +9,34 @@ void uses_lambda() {
   auto x = []()__attribute__((target_clones("sse4.2", "arch=ivybridge", 
"default"))) {};
   x();
 }
+
+// GH149372
+int __attribute__((target_clones("default,avx"))) redecl(int x) { return x; }
+int redecl(int);
+int __attribute__((target_clones("default,avx"))) redecl(int);
+
+int __attribute__((target_clones("default,avx"))) redecl2(int x) { return x; }
+int redecl2(int);
+// expected-error@+2 {{'target_clones' attribute does not match previous 
declaration}}
+// expected-note@-2 {{previous declaration is here}}
+int __attribute__((target_clones("default,sse4.2"))) redecl2(int);
+
+namespace ns {
+int __attribute__((target_clones("default,avx"))) redecl3(int x) { return x; }
+int redecl3(int);
+int __attribute__((target_clones("default,avx"))) redecl3(int);
+}
+
+extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int x) { 
return x; }
+extern "C" int redecl4(int);
+extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int);
+
+static int __attribute__((target_clones("default,avx"))) redecl5(int x) { 
return x; }
+static int redecl5(int);
+static int __attribute__((target_clones("default,avx"))) redecl5(int);
+
+int __attribute__((target_clones("default,avx"))) redecl6(int x) { return x; }
+int redecl6(int);
+int __attribute__((target_clones("default,avx"))) redecl6(int);
+int __attribute__((target_clones("default,avx"))) redecl6(long x) { return x; }
+int redecl6(long);

>From 2e5076caee15dc7ca8af3323e232683b7f1e6124 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Tue, 3 Nov 2026 08:35:52 +0530
Subject: [PATCH 2/2] [clang][test] Keep only the reported `target_clones`
 redeclaration pattern

---
 .../CodeGenCXX/attr-target-clones-redecl.cpp  | 90 -------------------
 clang/test/Sema/attr-target-clones.c          | 18 ----
 clang/test/SemaCXX/attr-target-clones.cpp     | 31 -------
 3 files changed, 139 deletions(-)
 delete mode 100644 clang/test/CodeGenCXX/attr-target-clones-redecl.cpp

diff --git a/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp 
b/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp
deleted file mode 100644
index c72beb1e11ccb9..00000000000000
--- a/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -emit-llvm-only %s
-
-// GH149372: redeclarations must not duplicate the versions in the resolver.
-
-// CHECK: @_Z1ci.ifunc = weak_odr alias i32 (i32), ptr @_Z1ci
-// CHECK: @_Z1fi.ifunc = weak_odr alias i32 (i32), ptr @_Z1fi
-// CHECK: @_ZN2ns1gEi.ifunc = weak_odr alias i32 (i32), ptr @_ZN2ns1gEi
-// CHECK: @h.ifunc = weak_odr alias i32 (i32), ptr @h
-// CHECK: @_ZL1si.ifunc = internal alias i32 (i32), ptr @_ZL1si
-// CHECK: @_Z1di.ifunc = weak_odr alias i32 (i32), ptr @_Z1di
-// CHECK: @_Z1ci = weak_odr ifunc i32 (i32), ptr @_Z1ci.resolver
-// CHECK: @_Z1fi = weak_odr ifunc i32 (i32), ptr @_Z1fi.resolver
-// CHECK: @_ZN2ns1gEi = weak_odr ifunc i32 (i32), ptr @_ZN2ns1gEi.resolver
-// CHECK: @h = weak_odr ifunc i32 (i32), ptr @h.resolver
-// CHECK: @_ZL1si = internal ifunc i32 (i32), ptr @_ZL1si.resolver
-// CHECK: @_Z1di = weak_odr ifunc i32 (i32), ptr @_Z1di.resolver
-
-int __attribute__((target_clones("default,avx"))) c(int x) { return x; }
-// CHECK: define {{.*}}i32 @_Z1ci.default.1(
-// CHECK: define {{.*}}i32 @_Z1ci.avx.0(
-// CHECK: define weak_odr ptr @_Z1ci.resolver() #[[ATTR_RESOLVER:[0-9]+]] 
comdat
-// CHECK: ret ptr @_Z1ci.avx.0
-// CHECK: ret ptr @_Z1ci.default.1
-
-enum { VALUE = 3 };
-
-extern int glob_x;
-
-int __attribute__((target_clones("default,avx"))) f(int x) { return x + glob_x 
+ VALUE; }
-
-int f(int);
-int __attribute__((target_clones("default,avx"))) f(int);
-// CHECK: define {{.*}}i32 @_Z1fi.default.1(
-// CHECK: define {{.*}}i32 @_Z1fi.avx.0(
-// CHECK: define weak_odr ptr @_Z1fi.resolver() #[[ATTR_RESOLVER]] comdat
-// CHECK: ret ptr @_Z1fi.avx.0
-// CHECK-NOT: ret ptr @_Z1fi.avx.0
-// CHECK: ret ptr @_Z1fi.default.1
-
-namespace ns {
-int __attribute__((target_clones("default,avx"))) g(int x) { return x; }
-int g(int);
-int __attribute__((target_clones("default,avx"))) g(int);
-}
-// CHECK: define {{.*}}i32 @_ZN2ns1gEi.default.1(
-// CHECK: define {{.*}}i32 @_ZN2ns1gEi.avx.0(
-// CHECK: define weak_odr ptr @_ZN2ns1gEi.resolver() #[[ATTR_RESOLVER]] comdat
-// CHECK: ret ptr @_ZN2ns1gEi.avx.0
-// CHECK-NOT: ret ptr @_ZN2ns1gEi.avx.0
-// CHECK: ret ptr @_ZN2ns1gEi.default.1
-
-extern "C" int __attribute__((target_clones("default,avx"))) h(int x) { return 
x; }
-extern "C" int h(int);
-extern "C" int __attribute__((target_clones("default,avx"))) h(int);
-// CHECK: define {{.*}}i32 @h.default.1(
-// CHECK: define {{.*}}i32 @h.avx.0(
-// CHECK: define weak_odr ptr @h.resolver() #[[ATTR_RESOLVER]] comdat
-// CHECK: ret ptr @h.avx.0
-// CHECK-NOT: ret ptr @h.avx.0
-// CHECK: ret ptr @h.default.1
-
-static int __attribute__((target_clones("default,avx"))) s(int x) { return x; }
-static int s(int);
-static int __attribute__((target_clones("default,avx"))) s(int);
-int use_s(int x) { return s(x); }
-// CHECK: define {{.*}}i32 @_Z5use_si(
-// CHECK: call noundef i32 @_ZL1si(
-// CHECK: define internal ptr @_ZL1si.resolver() #[[ATTR_RESOLVER]] {
-// CHECK: ret ptr @_ZL1si.avx.0
-// CHECK-NOT: ret ptr @_ZL1si.avx.0
-// CHECK: ret ptr @_ZL1si.default.1
-
-int __attribute__((target_clones("default,avx"))) d(int);
-int d(int);
-int __attribute__((target_clones("default,avx"))) d(int);
-int d(int x) { return x; }
-int d(int);
-// CHECK: define {{.*}}i32 @_Z1di.default.1(
-// CHECK: define {{.*}}i32 @_Z1di.avx.0(
-// CHECK: define weak_odr ptr @_Z1di.resolver() #[[ATTR_RESOLVER]] comdat
-// CHECK: ret ptr @_Z1di.avx.0
-// CHECK-NOT: ret ptr @_Z1di.avx.0
-// CHECK: ret ptr @_Z1di.default.1
-
-// The internal function's versions are emitted at the end of the module.
-// CHECK: define internal {{.*}}i32 @_ZL1si.default.1(
-// CHECK: define internal {{.*}}i32 @_ZL1si.avx.0(
-
-// CHECK: attributes #[[ATTR_RESOLVER]] = { disable_sanitizer_instrumentation }
diff --git a/clang/test/Sema/attr-target-clones.c 
b/clang/test/Sema/attr-target-clones.c
index 918f1dc1340ad4..7ff8a02bf53321 100644
--- a/clang/test/Sema/attr-target-clones.c
+++ b/clang/test/Sema/attr-target-clones.c
@@ -39,24 +39,6 @@ int __attribute__((target_clones("sse4.2", "default"))) 
redecl7(void);
 // expected-note@-2 {{previous declaration is here}}
 int __attribute__((target("sse4.2"))) redecl7(void) { return 1; }
 
-// GH149372
-int __attribute__((target_clones("sse4.2", "default"))) redecl8(void) { return 
1; }
-int redecl8(void);
-int __attribute__((target_clones("sse4.2", "default"))) redecl8(void);
-
-int __attribute__((target_clones("sse4.2", "default"))) redecl9(void);
-int redecl9(void);
-int __attribute__((target_clones("sse4.2", "default"))) redecl9(void);
-int redecl9(void);
-int __attribute__((target_clones("sse4.2", "default"))) redecl9(void) { return 
1; }
-int redecl9(void);
-
-int __attribute__((target_clones("sse4.2", "default"))) redecl10(void) { 
return 1; }
-int redecl10(void);
-// expected-error@+2 {{'target_clones' attribute does not match previous 
declaration}}
-// expected-note@-2 {{previous declaration is here}}
-int __attribute__((target_clones("arch=atom", "default"))) redecl10(void);
-
 int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
 // expected-error@+2 {{multiversioning attributes cannot be combined}}
 // expected-note@-2 {{previous declaration is here}}
diff --git a/clang/test/SemaCXX/attr-target-clones.cpp 
b/clang/test/SemaCXX/attr-target-clones.cpp
index 8952beeb47127a..68c9a4ff48ed9e 100644
--- a/clang/test/SemaCXX/attr-target-clones.cpp
+++ b/clang/test/SemaCXX/attr-target-clones.cpp
@@ -9,34 +9,3 @@ void uses_lambda() {
   auto x = []()__attribute__((target_clones("sse4.2", "arch=ivybridge", 
"default"))) {};
   x();
 }
-
-// GH149372
-int __attribute__((target_clones("default,avx"))) redecl(int x) { return x; }
-int redecl(int);
-int __attribute__((target_clones("default,avx"))) redecl(int);
-
-int __attribute__((target_clones("default,avx"))) redecl2(int x) { return x; }
-int redecl2(int);
-// expected-error@+2 {{'target_clones' attribute does not match previous 
declaration}}
-// expected-note@-2 {{previous declaration is here}}
-int __attribute__((target_clones("default,sse4.2"))) redecl2(int);
-
-namespace ns {
-int __attribute__((target_clones("default,avx"))) redecl3(int x) { return x; }
-int redecl3(int);
-int __attribute__((target_clones("default,avx"))) redecl3(int);
-}
-
-extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int x) { 
return x; }
-extern "C" int redecl4(int);
-extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int);
-
-static int __attribute__((target_clones("default,avx"))) redecl5(int x) { 
return x; }
-static int redecl5(int);
-static int __attribute__((target_clones("default,avx"))) redecl5(int);
-
-int __attribute__((target_clones("default,avx"))) redecl6(int x) { return x; }
-int redecl6(int);
-int __attribute__((target_clones("default,avx"))) redecl6(int);
-int __attribute__((target_clones("default,avx"))) redecl6(long x) { return x; }
-int redecl6(long);

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

Reply via email to