diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1460,27 +1460,38 @@ assert(CurContext && "Popped translation unit!"); } -/// Determine whether we allow overloading of the function -/// PrevDecl with another declaration. +/// Determine whether overloading is allowed for a new function +/// declaration considering prior declarations of the same name. /// /// This routine determines whether overloading is possible, not -/// whether some new function is actually an overload. It will return -/// true in C++ (where we can always provide overloads) or, as an -/// extension, in C when the previous function is already an -/// overloaded function declaration or has the "overloadable" -/// attribute. -static bool AllowOverloadingOfFunction(LookupResult &Previous, +/// whether a new declaration actually overloads a previous one. +/// It will return true in C++ (where overloads are alway permitted) +/// or, as a C extension, when either the new declaration or a +/// previous one is declared with the 'overloadable' attribute. +static bool AllowOverloadingOfFunction(const LookupResult &Previous, ASTContext &Context, const FunctionDecl *New) { - if (Context.getLangOpts().CPlusPlus) + if (Context.getLangOpts().CPlusPlus || New->hasAttr()) return true; - if (Previous.getResultKind() == LookupResult::FoundOverloaded) - return true; + // Multiversion function declarations are not overloads in the + // usual sense of that term, but lookup will report that an + // overload set was found if more than one multiversion function + // declaration is present for the same name. It is therefore + // inadequate to assume that some prior declaration(s) had + // the overloadable attribute; checking is required. Since one + // declaration is permitted to omit the attribute, it is necessary + // to check at least two; hence the 'any_of' check below. Note that + // the overloadable attribute is implicitly added to declarations + // that were required to have it but did not. + if (Previous.getResultKind() == LookupResult::FoundOverloaded) { + return llvm::any_of(Previous, [](const NamedDecl *ND) { + return ND->hasAttr(); + }); + } else if (Previous.getResultKind() == LookupResult::Found) + return Previous.getFoundDecl()->hasAttr(); - return Previous.getResultKind() == LookupResult::Found && - (Previous.getFoundDecl()->hasAttr() || - New->hasAttr()); + return false; } /// Add this decl to the scope shadowed decl chains. @@ -10706,13 +10717,17 @@ bool UseMemberUsingDeclRules = S.CurContext->isRecord() && !NewFD->getFriendObjectKind(); + bool MayNeedOverloadableChecks = + AllowOverloadingOfFunction(Previous, S.Context, NewFD); + // Next, check ALL non-overloads to see if this is a redeclaration of a // previous member of the MultiVersion set. for (NamedDecl *ND : Previous) { FunctionDecl *CurFD = ND->getAsFunction(); if (!CurFD) continue; - if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) + if (MayNeedOverloadableChecks && + S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; switch (NewMVType) { diff --git a/clang/test/Sema/attr-cpuspecific.c b/clang/test/Sema/attr-cpuspecific.c --- a/clang/test/Sema/attr-cpuspecific.c +++ b/clang/test/Sema/attr-cpuspecific.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -Wno-strict-prototypes -fsyntax-only -verify %s -Wnonnull -// XFAIL: asserts void __attribute__((cpu_specific(ivybridge))) no_default(void); void __attribute__((cpu_specific(sandybridge))) no_default(void); @@ -120,13 +119,9 @@ void __attribute__((cpu_specific(atom), nothrow, nonnull(1))) addtl_attrs(int*); -// FIXME: Declaration of a non-overloadable function when more than one -// FIXME: multiversion function declarations are present results in an -// FIXME: assertion failure. int __attribute__((cpu_specific(atom))) bad_overload1(void); int __attribute__((cpu_specific(ivybridge))) bad_overload1(void); -// expected-error@+2 {{at most one overload for a given name may lack the 'overloadable' attribute}} -// expected-note@-2 {{previous unmarked overload of function is here}} +// expected-error@+1 {{function declaration is missing 'cpu_specific' or 'cpu_dispatch' attribute in a multiversioned function}} int bad_overload1(int); int bad_overload2(int); @@ -135,13 +130,9 @@ int __attribute__((cpu_specific(atom))) bad_overload2(void); int __attribute__((cpu_specific(ivybridge))) bad_overload2(void); -// FIXME: Declaration of a non-overloadable function when more than one -// FIXME: multiversion function declarations are present results in an -// FIXME: assertion failure. int __attribute__((cpu_dispatch(generic))) bad_overload3(void); int __attribute__((cpu_specific(ivybridge))) bad_overload3(void); -// expected-error@+2 {{at most one overload for a given name may lack the 'overloadable' attribute}} -// expected-note@-2 {{previous unmarked overload of function is here}} +// expected-error@+1 {{function declaration is missing 'cpu_specific' or 'cpu_dispatch' attribute in a multiversioned function}} int bad_overload3(int); int bad_overload4(int); diff --git a/clang/test/Sema/attr-target-clones.c b/clang/test/Sema/attr-target-clones.c --- a/clang/test/Sema/attr-target-clones.c +++ b/clang/test/Sema/attr-target-clones.c @@ -90,9 +90,13 @@ void bad_overload1(int p) {} void bad_overload2(int p) {} +// expected-error@+2 {{conflicting types for 'bad_overload2'}} +// expected-note@-2 {{previous definition is here}} void bad_overload2(void) __attribute__((target_clones("mmx", "sse4.2", "default"))); void bad_overload3(void) __attribute__((target_clones("mmx", "sse4.2", "default"))); +// expected-error@+2 {{conflicting types for 'bad_overload3'}} +// expected-note@-2 {{previous declaration is here}} void bad_overload3(int) __attribute__((target_clones("mmx", "sse4.2", "default"))); void good_overload1(void) __attribute__((target_clones("mmx", "sse4.2", "default"))); diff --git a/clang/test/Sema/attr-target-mv.c b/clang/test/Sema/attr-target-mv.c --- a/clang/test/Sema/attr-target-mv.c +++ b/clang/test/Sema/attr-target-mv.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -Wno-strict-prototypes -fsyntax-only -verify %s -// XFAIL: asserts void __attribute__((target("sse4.2"))) no_default(void); void __attribute__((target("arch=sandybridge"))) no_default(void); @@ -109,13 +108,9 @@ void __attribute__((target("sse4.2"))) addtl_attrs6(int*); void __attribute__((target("arch=sandybridge"), nothrow, used, nonnull)) addtl_attrs6(int*); -// FIXME: Declaration of a non-overloadable function when more than one -// FIXME: multiversion function declarations are present results in an -// FIXME: assertion failure. int __attribute__((target("sse4.2"))) bad_overload1(void); int __attribute__((target("arch=sandybridge"))) bad_overload1(void); -// expected-error@+2 {{at most one overload for a given name may lack the 'overloadable' attribute}} -// expected-note@-2 {{previous unmarked overload of function is here}} +// expected-error@+1 {{function declaration is missing 'target' attribute in a multiversioned function}} int bad_overload1(int); int bad_overload2(int);