https://github.com/henrybw created
https://github.com/llvm/llvm-project/pull/169259
This patch adds a case to `CheckMultiVersionAdditionalDecl()` that detects
redeclarations of `target_clones` functions which omit the attribute, and makes
sure they are marked as redeclarations. It also updates the comment at the call
site of `CheckMultiVersionAdditionalDecl()` to reflect this.
Previously, `target_clones` multiversioned functions that omitted the attribute
from subsequent declarations would cause Clang to hit an `llvm_unreachable` and
crash. In the following example, the second declaration (the function
definition) should inherit the `target_clones` attribute from the first
declaration (the forward declaration):
```
__attribute__((target_clones("arch=atom", "default")))
void foo(void);
void foo(void) { /* ... */ }
```
However, `CheckMultiVersionAdditionalDecl()` was not recognizing the function
definition as a redeclaration of the forward declaration, which prevented
`Sema::MergeFunctionDecl()` from automatically inheriting the attribute.
A side effect of this fix is that Clang now catches redeclarations of
`target_clones` functions that have conflicting types, which previously caused
Clang to crash by hitting that same `llvm_unreachable`. The `bad_overload1`
case in `clang/test/Sema/attr-target-clones.c` has been updated to reflect this.
Fixes #165517
Fixes #129483
>From 0c9585cb448dcb2e0cd54b4071bbcc39ee0dc1df Mon Sep 17 00:00:00 2001
From: Henry Baba-Weiss <[email protected]>
Date: Sun, 23 Nov 2025 16:13:53 -0800
Subject: [PATCH] [clang][Sema] Handle target_clones redeclarations that omit
the attribute
This patch adds a case to `CheckMultiVersionAdditionalDecl()` that detects
redeclarations of `target_clones` functions which omit the attribute, and makes
sure they are marked as redeclarations. It also updates the comment at the call
site of `CheckMultiVersionAdditionalDecl()` to reflect this.
Previously, `target_clones` multiversioned functions that omitted the attribute
from subsequent declarations would cause Clang to hit an `llvm_unreachable` and
crash. In the following example, the second declaration (the function
definition) should inherit the `target_clones` attribute from the first
declaration (the forward declaration):
```
__attribute__((target_clones("arch=atom", "default")))
void foo(void);
void foo(void) { /* ... */ }
```
However, `CheckMultiVersionAdditionalDecl()` was not recognizing the function
definition as a redeclaration of the forward declaration, which prevented
`Sema::MergeFunctionDecl()` from automatically inheriting the attribute.
A side effect of this fix is that Clang now catches redeclarations of
`target_clones` functions that have conflicting types, which previously caused
Clang to crash by hitting that same `llvm_unreachable`. The `bad_overload1` case
in `clang/test/Sema/attr-target-clones.c` has been updated to reflect this.
Fixes #165517
Fixes #129483
---
clang/lib/Sema/SemaDecl.cpp | 15 +++++++++++--
clang/test/CodeGen/attr-target-clones.c | 29 +++++++++++++++++++++++++
clang/test/Sema/attr-target-clones.c | 13 +++++++++++
3 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b8ca2a376fde8..651437a6f4c30 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -11996,6 +11996,16 @@ static bool CheckMultiVersionAdditionalDecl(
}
}
+ // Redeclarations of a target_clones function may omit the attribute, in
which
+ // case it will be inherited during declaration merging.
+ if (NewMVKind == MultiVersionKind::None &&
+ OldMVKind == MultiVersionKind::TargetClones) {
+ NewFD->setIsMultiVersion();
+ Redeclaration = true;
+ OldDecl = OldFD;
+ return false;
+ }
+
// Else, this is simply a non-redecl case. Checking the 'value' is only
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
// handled in the attribute adding step.
@@ -12119,8 +12129,9 @@ static bool CheckMultiVersionFunction(Sema &S,
FunctionDecl *NewFD,
}
// At this point, we have a multiversion function decl (in OldFD) AND an
- // appropriate attribute in the current function decl. Resolve that these
are
- // still compatible with previous declarations.
+ // appropriate attribute in the current function decl (unless it's allowed to
+ // omit the attribute). Resolve that these are still compatible with
previous
+ // declarations.
return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, NewCPUDisp,
NewCPUSpec, NewClones, Redeclaration,
OldDecl, Previous);
diff --git a/clang/test/CodeGen/attr-target-clones.c
b/clang/test/CodeGen/attr-target-clones.c
index 295b25d6478eb..56db77c2b09a3 100644
--- a/clang/test/CodeGen/attr-target-clones.c
+++ b/clang/test/CodeGen/attr-target-clones.c
@@ -125,6 +125,35 @@ void __attribute__((target_clones("default,
arch=ivybridge"))) unused(void) {}
// WINDOWS: musttail call void @unused.arch_ivybridge.0
// WINDOWS: musttail call void @unused.default.1
+int __attribute__((target_clones("sse4.2, default"))) inherited(void);
+int inherited(void) { return 0; }
+// LINUX: define {{.*}}i32 @inherited.sse4.2.0()
+// LINUX: define {{.*}}i32 @inherited.default.1()
+// LINUX: define weak_odr ptr @inherited.resolver() #[[ATTR_RESOLVER]] comdat
+// LINUX: ret ptr @inherited.sse4.2.0
+// LINUX: ret ptr @inherited.default.1
+
+// DARWIN: define {{.*}}i32 @inherited.sse4.2.0()
+// DARWIN: define {{.*}}i32 @inherited.default.1()
+// DARWIN: define weak_odr ptr @inherited.resolver() #[[ATTR_RESOLVER]] {
+// DARWIN: ret ptr @inherited.sse4.2.0
+// DARWIN: ret ptr @inherited.default.1
+
+// WINDOWS: define dso_local i32 @inherited.sse4.2.0()
+// WINDOWS: define dso_local i32 @inherited.default.1()
+// WINDOWS: define weak_odr dso_local i32 @inherited() #[[ATTR_RESOLVER]]
comdat
+// WINDOWS: musttail call i32 @inherited.sse4.2.0
+// WINDOWS: musttail call i32 @inherited.default.1
+
+int test_inherited(void) {
+ // LINUX: define {{.*}}i32 @test_inherited() #[[DEF:[0-9]+]]
+ // DARWIN: define {{.*}}i32 @test_inherited() #[[DEF:[0-9]+]]
+ // WINDOWS: define dso_local i32 @test_inherited() #[[DEF:[0-9]+]]
+ return inherited();
+ // LINUX: call i32 @inherited()
+ // DARWIN: call i32 @inherited()
+ // WINDOWS: call i32 @inherited()
+}
inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
foo_inline(void) { return 0; }
diff --git a/clang/test/Sema/attr-target-clones.c
b/clang/test/Sema/attr-target-clones.c
index 4597ea54d02bf..40688772eeb96 100644
--- a/clang/test/Sema/attr-target-clones.c
+++ b/clang/test/Sema/attr-target-clones.c
@@ -28,6 +28,17 @@ int __attribute__((target_clones("sse4.2", "arch=atom",
"default"))) redecl4(voi
int __attribute__((target_clones("sse4.2", "arch=sandybridge", "default")))
redecl4(void) { return 1; }
+int __attribute__((target_clones("sse4.2", "default"))) redecl5(void);
+int redecl5(void) { return 1; }
+
+int redecl6(void);
+int __attribute__((target_clones("sse4.2", "default"))) redecl6(void) { return
1; }
+
+int __attribute__((target_clones("sse4.2", "default"))) redecl7(void);
+// expected-error@+2 {{multiversioning attributes cannot be combined}}
+// expected-note@-2 {{previous declaration is here}}
+int __attribute__((target("sse4.2"))) redecl7(void) { return 1; }
+
int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
// expected-error@+2 {{multiversioning attributes cannot be combined}}
// expected-note@-2 {{previous declaration is here}}
@@ -87,6 +98,8 @@ int useage(void) {
int __attribute__((target_clones("sse4.2", "default"))) mv_after_use(void) {
return 1; }
void bad_overload1(void) __attribute__((target_clones("mmx", "sse4.2",
"default")));
+// expected-error@+2 {{conflicting types for 'bad_overload1'}}
+// expected-note@-2 {{previous declaration is here}}
void bad_overload1(int p) {}
void bad_overload2(int p) {}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits