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<OverloadableAttr>())
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<OverloadableAttr>();
+ });
+ } else if (Previous.getResultKind() == LookupResult::Found)
+ return Previous.getFoundDecl()->hasAttr<OverloadableAttr>();
- return Previous.getResultKind() == LookupResult::Found &&
- (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
- New->hasAttr<OverloadableAttr>());
+ return false;
}
/// Add this decl to the scope shadowed decl chains.
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) {
// 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);
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);
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);
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")));
// 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);
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);