mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-12 09:41:26 +00:00
[clang] Add missing diagnostics for invalid overloads of multiversion functions in C.
Previously, an attempt to declare an overload of a multiversion function in C was not properly diagnosed. In some cases, diagnostics were simply missing. In other cases the following assertion failure occured... ``` Assertion `(Previous.empty() || llvm::any_of(Previous, [](const NamedDecl *ND) { return ND->hasAttr(); })) && "Non-redecls shouldn't happen without overloadable present"' failed. ``` ... or the following diagnostic was spuriously issued. ``` error: at most one overload for a given name may lack the 'overloadable' attribute ``` The diagnostics issued in some cases could be improved. When the function type of a redeclaration does not match the prior declaration, it would be preferable to diagnose the type mismatch before diagnosing mismatched attributes. Diagnostics are also missing for some cases. Reviewed By: erichkeane Differential Revision: https://reviews.llvm.org/D121959
This commit is contained in:
parent
42e4c5b261
commit
8b6f1cbb21
@ -1460,27 +1460,38 @@ void Sema::ActOnExitFunctionContext() {
|
||||
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.
|
||||
@ -10705,13 +10716,17 @@ static bool CheckMultiVersionAdditionalDecl(
|
||||
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) {
|
||||
|
@ -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 @@ int __attribute__((cpu_dispatch(pentium_iii, pentium_iii_no_xmm_regs))) dupe_p3(
|
||||
|
||||
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 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);
|
||||
|
@ -90,9 +90,13 @@ void bad_overload1(void) __attribute__((target_clones("mmx", "sse4.2", "default"
|
||||
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")));
|
||||
|
@ -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("arch=sandybridge"))) addtl_attrs5(int*);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user