[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