diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3cadd986b8ae4..0e803ee028ce9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11208,8 +11208,8 @@ def err_multiversion_mismatched_attrs "%0 %select{is missing|has different arguments}1">; def err_multiversion_diff : Error< "multiversioned function declaration has a different %select{calling convention" - "|return type|constexpr specification|inline specification|storage class|" - "linkage}0">; + "|return type|constexpr specification|inline specification|linkage|" + "language linkage}0">; def err_multiversion_doesnt_support : Error< "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not " "yet support %select{function templates|virtual functions|" diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 13389ebdd72f6..79080098026c6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10322,8 +10322,8 @@ bool Sema::areMultiversionVariantFunctionsCompatible( ReturnType = 1, ConstexprSpec = 2, InlineSpec = 3, - StorageClass = 4, - Linkage = 5, + Linkage = 4, + LanguageLinkage = 5, }; if (NoProtoDiagID.getDiagID() != 0 && OldFD && @@ -10397,11 +10397,11 @@ bool Sema::areMultiversionVariantFunctionsCompatible( if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec; - if (OldFD->getStorageClass() != NewFD->getStorageClass()) - return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass; + if (OldFD->getFormalLinkage() != NewFD->getFormalLinkage()) + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC()) - return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << LanguageLinkage; if (CheckEquivalentExceptionSpec( OldFD->getType()->getAs(), OldFD->getLocation(), diff --git a/clang/test/SemaCXX/attr-cpuspecific.cpp b/clang/test/SemaCXX/attr-cpuspecific.cpp index 861711b463837..fe46358166546 100644 --- a/clang/test/SemaCXX/attr-cpuspecific.cpp +++ b/clang/test/SemaCXX/attr-cpuspecific.cpp @@ -34,9 +34,19 @@ int __attribute__((cpu_specific(sandybridge))) foo2(void); constexpr int __attribute__((cpu_specific(ivybridge))) foo2(void); static int __attribute__((cpu_specific(sandybridge))) bar(void); -//expected-error@+1 {{multiversioned function declaration has a different storage class}} +//expected-error@+1 {{multiversioned function declaration has a different linkage}} int __attribute__((cpu_dispatch(ivybridge))) bar(void) {} +// OK +extern int __attribute__((cpu_specific(sandybridge))) bar2(void); +int __attribute__((cpu_dispatch(ivybridge))) bar2(void) {} + +namespace { +int __attribute__((cpu_specific(sandybridge))) bar3(void); +static int __attribute__((cpu_dispatch(ivybridge))) bar3(void) {} +} + + inline int __attribute__((cpu_specific(sandybridge))) baz(void); //expected-error@+1 {{multiversioned function declaration has a different inline specification}} int __attribute__((cpu_specific(ivybridge))) baz(void) {return 1;} @@ -74,7 +84,7 @@ struct S { extern "C" { int __attribute__((cpu_specific(atom))) diff_mangle(void) { return 0; } } -//expected-error@+1 {{multiversioned function declaration has a different linkage}} +//expected-error@+1 {{multiversioned function declaration has a different language linkage}} int __attribute__((cpu_specific(sandybridge))) diff_mangle(void) { return 0; } __attribute__((cpu_specific(atom))) void DiffDecl(); diff --git a/clang/test/SemaCXX/attr-target-mv.cpp b/clang/test/SemaCXX/attr-target-mv.cpp index 5ef1d398d2d8f..5b2f0fc825f39 100644 --- a/clang/test/SemaCXX/attr-target-mv.cpp +++ b/clang/test/SemaCXX/attr-target-mv.cpp @@ -27,17 +27,26 @@ int __attribute__((target("default"))) foo2(void) { return 2; } static int __attribute__((target("sse4.2"))) bar(void) { return 0; } static int __attribute__((target("arch=sandybridge"))) bar(void); -//expected-error@+1 {{multiversioned function declaration has a different storage class}} +//expected-error@+1 {{multiversioned function declaration has a different linkage}} int __attribute__((target("arch=ivybridge"))) bar(void) {return 1;} static int __attribute__((target("default"))) bar(void) { return 2; } int __attribute__((target("sse4.2"))) bar2(void) { return 0; } -//expected-error@+1 {{multiversioned function declaration has a different storage class}} +//expected-error@+1 {{multiversioned function declaration has a different linkage}} static int __attribute__((target("arch=sandybridge"))) bar2(void); int __attribute__((target("arch=ivybridge"))) bar2(void) {return 1;} int __attribute__((target("default"))) bar2(void) { return 2; } +// no diagnostic, since this doesn't change the linkage. +int __attribute__((target("sse4.2"))) bar3(void) { return 0; } +extern int __attribute__((target("arch=sandybridge"))) bar2(void); + +namespace { +int __attribute__((target("sse4.2"))) bar4(void) { return 0; } +static int __attribute__((target("arch=sandybridge"))) bar4(void); +} + inline int __attribute__((target("sse4.2"))) baz(void) { return 0; } inline int __attribute__((target("arch=sandybridge"))) baz(void); //expected-error@+1 {{multiversioned function declaration has a different inline specification}} @@ -102,7 +111,7 @@ struct S { extern "C" { int __attribute__((target("sse4.2"))) diff_mangle(void) { return 0; } } -//expected-error@+1 {{multiversioned function declaration has a different linkage}} +//expected-error@+1 {{multiversioned function declaration has a different language linkage}} int __attribute__((target("arch=sandybridge"))) diff_mangle(void) { return 0; } // expected-error@+1 {{multiversioned functions do not yet support deduced return types}}