diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 439e47b209b2f..b12e4539dc3a6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -491,6 +491,8 @@ Bug Fixes in This Version - Accept empty enumerations in MSVC-compatible C mode. (#GH114402) - Fix a bug leading to incorrect code generation with complex number compound assignment and bitfield values, which also caused a crash with UBsan. (#GH166798) - Fixed false-positive shadow diagnostics for lambdas in explicit object member functions. (#GH163731) +- Fix an assertion failure when a ``target_clones`` attribute is only on the + forward declaration of a multiversioned function. (#GH165517) (#GH129483) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) {}