Author: Alexandros Lamprineas Date: 2024-07-04T20:04:11+01:00 New Revision: d1c911ffe48eef23817d11c900dec30e0e3b5ae4
URL: https://github.com/llvm/llvm-project/commit/d1c911ffe48eef23817d11c900dec30e0e3b5ae4 DIFF: https://github.com/llvm/llvm-project/commit/d1c911ffe48eef23817d11c900dec30e0e3b5ae4.diff LOG: [clang][FMV] Do not omit explicit default target_version attribute. (#96628) Fixes a crash and cleans up some dead code. namespace Foo { int bar(); __attribute((target_version("default"))) int bar() { return 0; } __attribute((target_version("mops"))) int bar() { return 1; } } $ clang++ --target=aarch64-linux-gnu --rtlib=compiler-rt fmv.cpp None multiversion type isn't valid here UNREACHABLE executed at clang/lib/CodeGen/CodeGenModule.cpp:1840! ... getMangledNameImpl clang::CodeGen::CodeGenModule::getMangledName clang::CodeGen::CodeGenModule::EmitGlobal Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/test/CodeGen/attr-target-version.c clang/test/CodeGenCXX/fmv-namespace.cpp clang/test/Sema/attr-target-version.c Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0dbc819f6223a..fb3a5d25c635c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4533,8 +4533,7 @@ class Sema final : public SemaBase { bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); /// Check Target Version attrs - bool checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, - StringRef &Str, bool &isDefault); + bool checkTargetVersionAttr(SourceLocation Loc, Decl *D, StringRef Str); bool checkTargetClonesAttrString( SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 262a2547e23fd..b3bfdacb01790 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11201,6 +11201,10 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) { // otherwise it is treated as a normal function. if (TA && !TA->isDefaultVersion()) return false; + // The target_version attribute only causes Multiversioning if this + // declaration is NOT the default version. + if (TVA && TVA->isDefaultVersion()) + return false; if ((TA || TVA) && CheckMultiVersionValue(S, FD)) { FD->setInvalidDecl(); @@ -11234,18 +11238,16 @@ static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) { if (MVKindTo == MultiVersionKind::None && (MVKindFrom == MultiVersionKind::TargetVersion || - MVKindFrom == MultiVersionKind::TargetClones)) { - To->setIsMultiVersion(); + MVKindFrom == MultiVersionKind::TargetClones)) To->addAttr(TargetVersionAttr::CreateImplicit( To->getASTContext(), "default", To->getSourceRange())); - } } -static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, - FunctionDecl *NewFD, - bool &Redeclaration, - NamedDecl *&OldDecl, - LookupResult &Previous) { +static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, + FunctionDecl *NewFD, + bool &Redeclaration, + NamedDecl *&OldDecl, + LookupResult &Previous) { assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion"); // The definitions should be allowed in any order. If we have discovered @@ -11256,13 +11258,16 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, const auto *NewTA = NewFD->getAttr<TargetAttr>(); const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>(); const auto *OldTA = OldFD->getAttr<TargetAttr>(); - const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>(); + // If the old decl is NOT MultiVersioned yet, and we don't cause that // to change, this is a simple redeclaration. - if ((NewTA && !NewTA->isDefaultVersion() && - (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) || - (NewTVA && !NewTVA->isDefaultVersion() && - (!OldTVA || OldTVA->getName() == NewTVA->getName()))) + if (NewTA && !NewTA->isDefaultVersion() && + (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) + return false; + + // The target_version attribute only causes Multiversioning if this + // declaration is NOT the default version. + if (NewTVA && NewTVA->isDefaultVersion()) return false; // Otherwise, this decl causes MultiVersioning. @@ -11279,8 +11284,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, } // If this is 'default', permit the forward declaration. - if ((NewTA && NewTA->isDefaultVersion() && !OldTA) || - (NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) { + if (NewTA && NewTA->isDefaultVersion() && !OldTA) { Redeclaration = true; OldDecl = OldFD; OldFD->setIsMultiVersion(); @@ -11312,22 +11316,6 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, } } - if (NewTVA) { - llvm::SmallVector<StringRef, 8> Feats; - OldTVA->getFeatures(Feats); - llvm::sort(Feats); - llvm::SmallVector<StringRef, 8> NewFeats; - NewTVA->getFeatures(NewFeats); - llvm::sort(NewFeats); - - if (Feats == NewFeats) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; - } - } - for (const auto *FD : OldFD->redecls()) { const auto *CurTA = FD->getAttr<TargetAttr>(); const auto *CurTVA = FD->getAttr<TargetVersionAttr>(); @@ -11683,24 +11671,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, FunctionDecl *OldFD = OldDecl->getAsFunction(); - if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) { - if (NewTVA || !OldFD->getAttr<TargetVersionAttr>()) - return false; - if (!NewFD->getType()->getAs<FunctionProtoType>()) { - // Multiversion declaration doesn't have prototype. - S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto); - NewFD->setInvalidDecl(); - } else { - // No "target_version" attribute is equivalent to "default" attribute. - NewFD->addAttr(TargetVersionAttr::CreateImplicit( - S.Context, "default", NewFD->getSourceRange())); - NewFD->setIsMultiVersion(); - OldFD->setIsMultiVersion(); - OldDecl = OldFD; - Redeclaration = true; - } - return true; - } + if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) + return false; // Multiversioned redeclarations aren't allowed to omit the attribute, except // for target_clones and target_version. @@ -11717,8 +11689,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, switch (MVKind) { case MultiVersionKind::Target: case MultiVersionKind::TargetVersion: - return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration, - OldDecl, Previous); + return CheckDeclarationCausesMultiVersioning( + S, OldFD, NewFD, Redeclaration, OldDecl, Previous); case MultiVersionKind::TargetClones: if (OldFD->isUsed(false)) { NewFD->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 6edf1fa3cc59d..2f16d0f76dbd9 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3010,12 +3010,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { } bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, - StringRef &AttrStr, bool &isDefault) { + StringRef AttrStr) { enum FirstParam { Unsupported }; enum SecondParam { None }; enum ThirdParam { Target, TargetClones, TargetVersion }; - if (AttrStr.trim() == "default") - isDefault = true; llvm::SmallVector<StringRef, 8> Features; AttrStr.split(Features, "+"); for (auto &CurFeature : Features) { @@ -3035,16 +3033,12 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; - bool isDefault = false; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || - S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault)) + S.checkTargetVersionAttr(LiteralLoc, D, Str)) return; - // Do not create default only target_version attribute - if (!isDefault) { - TargetVersionAttr *NewAttr = - ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); - D->addAttr(NewAttr); - } + TargetVersionAttr *NewAttr = + ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); + D->addAttr(NewAttr); } static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { diff --git a/clang/test/CodeGen/attr-target-version.c b/clang/test/CodeGen/attr-target-version.c index 024aafffca629..4edfc5408fae7 100644 --- a/clang/test/CodeGen/attr-target-version.c +++ b/clang/test/CodeGen/attr-target-version.c @@ -428,13 +428,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: define {{[^@]+}}@fmv_default -// CHECK-SAME: () #[[ATTR11]] { -// CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 111 -// -// -// CHECK: Function Attrs: noinline nounwind optnone // CHECK-LABEL: define {{[^@]+}}@fmv_c._Mssbs // CHECK-SAME: () #[[ATTR11]] { // CHECK-NEXT: entry: @@ -637,22 +630,18 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: define {{[^@]+}}@recur +// CHECK-LABEL: define {{[^@]+}}@fmv_default // CHECK-SAME: () #[[ATTR11]] { // CHECK-NEXT: entry: -// CHECK-NEXT: call void @reca() -// CHECK-NEXT: ret void +// CHECK-NEXT: ret i32 111 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: define {{[^@]+}}@main +// CHECK-LABEL: define {{[^@]+}}@recur // CHECK-SAME: () #[[ATTR11]] { // CHECK-NEXT: entry: -// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 -// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 -// CHECK-NEXT: call void @recur() -// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo() -// CHECK-NEXT: ret i32 [[CALL]] +// CHECK-NEXT: call void @reca() +// CHECK-NEXT: ret void // // // CHECK: Function Attrs: noinline nounwind optnone @@ -818,6 +807,17 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@main +// CHECK-SAME: () #[[ATTR11]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: call void @recur() +// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone // CHECK-LABEL: define {{[^@]+}}@fmv_inline._Mf64mmMpmullMsha1 // CHECK-SAME: () #[[ATTR22:[0-9]+]] { // CHECK-NEXT: entry: @@ -1020,20 +1020,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default -// CHECK-NOFMV-SAME: () #[[ATTR0]] { -// CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: ret i32 111 -// -// -// CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c -// CHECK-NOFMV-SAME: () #[[ATTR0]] { -// CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: ret void -// -// -// CHECK-NOFMV: Function Attrs: noinline nounwind optnone // CHECK-NOFMV-LABEL: define {{[^@]+}}@goo // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: @@ -1053,22 +1039,25 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur +// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: call void @reca() // CHECK-NOFMV-NEXT: ret void // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@main +// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 -// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4 -// CHECK-NOFMV-NEXT: call void @recur() -// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo() -// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// CHECK-NOFMV-NEXT: ret i32 111 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: call void @reca() +// CHECK-NOFMV-NEXT: ret void // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone @@ -1089,31 +1078,42 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def +// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: // CHECK-NOFMV-NEXT: ret i32 1 // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def +// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: ret i32 1 +// CHECK-NOFMV-NEXT: ret i32 0 // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def +// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: // CHECK-NOFMV-NEXT: ret i32 0 // // // CHECK-NOFMV: Function Attrs: noinline nounwind optnone -// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls +// CHECK-NOFMV-LABEL: define {{[^@]+}}@main // CHECK-NOFMV-SAME: () #[[ATTR0]] { // CHECK-NOFMV-NEXT: entry: -// CHECK-NOFMV-NEXT: ret i32 0 +// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NOFMV-NEXT: call void @recur() +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 1 // //. // CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+flagm,+fp-armv8,+fp16fml,+fullfp16,+neon,+rand,-v9.5a" } diff --git a/clang/test/CodeGenCXX/fmv-namespace.cpp b/clang/test/CodeGenCXX/fmv-namespace.cpp index 193f01db4c5d3..abfff1a74f86a 100644 --- a/clang/test/CodeGenCXX/fmv-namespace.cpp +++ b/clang/test/CodeGenCXX/fmv-namespace.cpp @@ -17,25 +17,26 @@ int __attribute((target_version("sve"))) foo() { return 2; } int baz() { return OtherName::foo(); } +namespace Foo { +int bar(); +__attribute((target_version("default"))) int bar() { return 0; } +__attribute((target_version("mops"))) int bar() { return 1; } +} + //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } // CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver // CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver +// CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver //. -// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default( -// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret i32 0 -// -// // CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve( -// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: ret i32 1 // // // CHECK-LABEL: define dso_local noundef i32 @_Z3barv( -// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv() // CHECK-NEXT: ret i32 [[CALL]] @@ -56,13 +57,13 @@ int baz() { return OtherName::foo(); } // // // CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve( -// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: ret i32 2 // // // CHECK-LABEL: define dso_local noundef i32 @_Z3bazv( -// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-SAME: ) #[[ATTR1]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv() // CHECK-NEXT: ret i32 [[CALL]] @@ -81,10 +82,43 @@ int baz() { return OtherName::foo(); } // CHECK: [[RESOLVER_ELSE]]: // CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv.default // +// +// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i32 0 +// +// +// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv._Mmops( +// CHECK-SAME: ) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i32 0 +// +// +// CHECK-LABEL: define weak_odr ptr @_ZN3Foo3barEv.resolver() comdat { +// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] +// CHECK-NEXT: call void @__init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 576460752303423488 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 576460752303423488 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] +// CHECK: [[RESOLVER_RETURN]]: +// CHECK-NEXT: ret ptr @_ZN3Foo3barEv._Mmops +// CHECK: [[RESOLVER_ELSE]]: +// CHECK-NEXT: ret ptr @_ZN3Foo3barEv.default +// //. -// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } -// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" } -// CHECK: attributes #[[ATTR2:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" } +// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mops" } +// CHECK: attributes #[[ATTR3:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" } //. // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} // CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} diff --git a/clang/test/Sema/attr-target-version.c b/clang/test/Sema/attr-target-version.c index cd5be459456eb..88a927a58f991 100644 --- a/clang/test/Sema/attr-target-version.c +++ b/clang/test/Sema/attr-target-version.c @@ -104,6 +104,11 @@ int __attribute__((aarch64_vector_pcs, target_version("sha3"))) combine(void) { int __attribute__((target_version("fp+aes+pmull+rcpc"))) unspec_args() { return -1; } // expected-error@-1 {{multiversioned function must have a prototype}} -// expected-error@+1 {{multiversioned function must have a prototype}} int __attribute__((target_version("default"))) unspec_args() { return 0; } int cargs() { return unspec_args(); } + +int unspec_args_implicit_default_first(); +// expected-error@-1 {{multiversioned function must have a prototype}} +// expected-note@+1 {{function multiversioning caused by this declaration}} +int __attribute__((target_version("aes"))) unspec_args_implicit_default_first() { return -1; } +int __attribute__((target_version("default"))) unspec_args_implicit_default_first() { return 0; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits