[clang] 8b6f1cb - [clang] Add missing diagnostics for invalid overloads of multiversion functions in C.
Tom Honermann via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 21 10:40:05 PDT 2022
Author: Tom Honermann
Date: 2022-03-21T13:39:43-04:00
New Revision: 8b6f1cbb21c58e255156aa32ac55530c807055a9
URL: https://github.com/llvm/llvm-project/commit/8b6f1cbb21c58e255156aa32ac55530c807055a9
DIFF: https://github.com/llvm/llvm-project/commit/8b6f1cbb21c58e255156aa32ac55530c807055a9.diff
LOG: [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
Added:
Modified:
clang/lib/Sema/SemaDecl.cpp
clang/test/Sema/attr-cpuspecific.c
clang/test/Sema/attr-target-clones.c
clang/test/Sema/attr-target-mv.c
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 68e3a7461deb1..385569b186393 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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) {
diff --git a/clang/test/Sema/attr-cpuspecific.c b/clang/test/Sema/attr-cpuspecific.c
index 572d4d71f0c0e..f3d46cf8f1801 100644
--- 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 @@ 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 at +2 {{at most one overload for a given name may lack the 'overloadable' attribute}}
-// expected-note at -2 {{previous unmarked overload of function is here}}
+// expected-error at +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 at +2 {{at most one overload for a given name may lack the 'overloadable' attribute}}
-// expected-note at -2 {{previous unmarked overload of function is here}}
+// expected-error at +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
index d4443e12db4ce..e9ddecad5727f 100644
--- a/clang/test/Sema/attr-target-clones.c
+++ b/clang/test/Sema/attr-target-clones.c
@@ -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 at +2 {{conflicting types for 'bad_overload2'}}
+// expected-note at -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 at +2 {{conflicting types for 'bad_overload3'}}
+// expected-note at -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
index e5792ba01d07b..b02b13079163b 100644
--- 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("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 at +2 {{at most one overload for a given name may lack the 'overloadable' attribute}}
-// expected-note at -2 {{previous unmarked overload of function is here}}
+// expected-error at +1 {{function declaration is missing 'target' attribute in a multiversioned function}}
int bad_overload1(int);
int bad_overload2(int);
More information about the cfe-commits
mailing list