Skip to content

Commit 4459564

Browse files
authored
[clang][Sema] Handle target_clones redeclarations that omit the attribute (#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
1 parent 40fb2ca commit 4459564

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,8 @@ Bug Fixes in This Version
491491
- Accept empty enumerations in MSVC-compatible C mode. (#GH114402)
492492
- Fix a bug leading to incorrect code generation with complex number compound assignment and bitfield values, which also caused a crash with UBsan. (#GH166798)
493493
- Fixed false-positive shadow diagnostics for lambdas in explicit object member functions. (#GH163731)
494+
- Fix an assertion failure when a ``target_clones`` attribute is only on the
495+
forward declaration of a multiversioned function. (#GH165517) (#GH129483)
494496

495497
Bug Fixes to Compiler Builtins
496498
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaDecl.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11996,6 +11996,16 @@ static bool CheckMultiVersionAdditionalDecl(
1199611996
}
1199711997
}
1199811998

11999+
// Redeclarations of a target_clones function may omit the attribute, in which
12000+
// case it will be inherited during declaration merging.
12001+
if (NewMVKind == MultiVersionKind::None &&
12002+
OldMVKind == MultiVersionKind::TargetClones) {
12003+
NewFD->setIsMultiVersion();
12004+
Redeclaration = true;
12005+
OldDecl = OldFD;
12006+
return false;
12007+
}
12008+
1199912009
// Else, this is simply a non-redecl case. Checking the 'value' is only
1200012010
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
1200112011
// handled in the attribute adding step.
@@ -12119,8 +12129,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
1211912129
}
1212012130

1212112131
// At this point, we have a multiversion function decl (in OldFD) AND an
12122-
// appropriate attribute in the current function decl. Resolve that these are
12123-
// still compatible with previous declarations.
12132+
// appropriate attribute in the current function decl (unless it's allowed to
12133+
// omit the attribute). Resolve that these are still compatible with previous
12134+
// declarations.
1212412135
return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, NewCPUDisp,
1212512136
NewCPUSpec, NewClones, Redeclaration,
1212612137
OldDecl, Previous);

clang/test/CodeGen/attr-target-clones.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,35 @@ void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
125125
// WINDOWS: musttail call void @unused.arch_ivybridge.0
126126
// WINDOWS: musttail call void @unused.default.1
127127

128+
int __attribute__((target_clones("sse4.2, default"))) inherited(void);
129+
int inherited(void) { return 0; }
130+
// LINUX: define {{.*}}i32 @inherited.sse4.2.0()
131+
// LINUX: define {{.*}}i32 @inherited.default.1()
132+
// LINUX: define weak_odr ptr @inherited.resolver() #[[ATTR_RESOLVER]] comdat
133+
// LINUX: ret ptr @inherited.sse4.2.0
134+
// LINUX: ret ptr @inherited.default.1
135+
136+
// DARWIN: define {{.*}}i32 @inherited.sse4.2.0()
137+
// DARWIN: define {{.*}}i32 @inherited.default.1()
138+
// DARWIN: define weak_odr ptr @inherited.resolver() #[[ATTR_RESOLVER]] {
139+
// DARWIN: ret ptr @inherited.sse4.2.0
140+
// DARWIN: ret ptr @inherited.default.1
141+
142+
// WINDOWS: define dso_local i32 @inherited.sse4.2.0()
143+
// WINDOWS: define dso_local i32 @inherited.default.1()
144+
// WINDOWS: define weak_odr dso_local i32 @inherited() #[[ATTR_RESOLVER]] comdat
145+
// WINDOWS: musttail call i32 @inherited.sse4.2.0
146+
// WINDOWS: musttail call i32 @inherited.default.1
147+
148+
int test_inherited(void) {
149+
// LINUX: define {{.*}}i32 @test_inherited() #[[DEF:[0-9]+]]
150+
// DARWIN: define {{.*}}i32 @test_inherited() #[[DEF:[0-9]+]]
151+
// WINDOWS: define dso_local i32 @test_inherited() #[[DEF:[0-9]+]]
152+
return inherited();
153+
// LINUX: call i32 @inherited()
154+
// DARWIN: call i32 @inherited()
155+
// WINDOWS: call i32 @inherited()
156+
}
128157

129158
inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
130159
foo_inline(void) { return 0; }

clang/test/Sema/attr-target-clones.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ int __attribute__((target_clones("sse4.2", "arch=atom", "default"))) redecl4(voi
2828
int __attribute__((target_clones("sse4.2", "arch=sandybridge", "default")))
2929
redecl4(void) { return 1; }
3030

31+
int __attribute__((target_clones("sse4.2", "default"))) redecl5(void);
32+
int redecl5(void) { return 1; }
33+
34+
int redecl6(void);
35+
int __attribute__((target_clones("sse4.2", "default"))) redecl6(void) { return 1; }
36+
37+
int __attribute__((target_clones("sse4.2", "default"))) redecl7(void);
38+
// expected-error@+2 {{multiversioning attributes cannot be combined}}
39+
// expected-note@-2 {{previous declaration is here}}
40+
int __attribute__((target("sse4.2"))) redecl7(void) { return 1; }
41+
3142
int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
3243
// expected-error@+2 {{multiversioning attributes cannot be combined}}
3344
// expected-note@-2 {{previous declaration is here}}
@@ -87,6 +98,8 @@ int useage(void) {
8798
int __attribute__((target_clones("sse4.2", "default"))) mv_after_use(void) { return 1; }
8899

89100
void bad_overload1(void) __attribute__((target_clones("mmx", "sse4.2", "default")));
101+
// expected-error@+2 {{conflicting types for 'bad_overload1'}}
102+
// expected-note@-2 {{previous declaration is here}}
90103
void bad_overload1(int p) {}
91104

92105
void bad_overload2(int p) {}

0 commit comments

Comments
 (0)