george.burgess.iv updated this revision to Diff 102850.
george.burgess.iv marked 3 inline comments as done.
george.burgess.iv added a comment.

Addressed all feedback


https://reviews.llvm.org/D32332

Files:
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/SemaDecl.cpp
  test/CodeGen/mangle-ms.c
  test/CodeGen/mangle.c
  test/CodeGenCXX/mangle-ms.cpp
  test/PCH/attrs.c
  test/Sema/overloadable.c

Index: test/Sema/overloadable.c
===================================================================
--- test/Sema/overloadable.c
+++ test/Sema/overloadable.c
@@ -3,12 +3,15 @@
 int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute only applies to functions}}
 void params(void) __attribute__((overloadable(12))); // expected-error {{'overloadable' attribute takes no arguments}}
 
-int *f(int) __attribute__((overloadable)); // expected-note 2{{previous overload of function is here}}
-float *f(float); // expected-error{{overloaded function 'f' must have the 'overloadable' attribute}}
+int *f(int) __attribute__((overloadable)); // expected-note{{previous overload of function is here}}
+float *f(float);
 int *f(int); // expected-error{{redeclaration of 'f' must have the 'overloadable' attribute}} \
              // expected-note{{previous declaration is here}}
 double *f(double) __attribute__((overloadable)); // okay, new
 
+// Ensure we don't complain about overloadable on implicitly declared functions.
+int isdigit(int) __attribute__((overloadable));
+
 void test_f(int iv, float fv, double dv) {
   int *ip = f(iv);
   float *fp = f(fv);
@@ -71,19 +74,19 @@
   f1();
 }
 
-void before_local_1(int) __attribute__((overloadable)); // expected-note {{here}}
+void before_local_1(int) __attribute__((overloadable));
 void before_local_2(int); // expected-note {{here}}
 void before_local_3(int) __attribute__((overloadable));
 void local() {
-  void before_local_1(char); // expected-error {{must have the 'overloadable' attribute}}
-  void before_local_2(char) __attribute__((overloadable)); // expected-error {{conflicting types}}
+  void before_local_1(char);
+  void before_local_2(char); // expected-error {{conflicting types}}
   void before_local_3(char) __attribute__((overloadable));
-  void after_local_1(char); // expected-note {{here}}
-  void after_local_2(char) __attribute__((overloadable)); // expected-note {{here}}
+  void after_local_1(char);
+  void after_local_2(char) __attribute__((overloadable));
   void after_local_3(char) __attribute__((overloadable));
 }
-void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
-void after_local_2(int); // expected-error {{must have the 'overloadable' attribute}}
+void after_local_1(int) __attribute__((overloadable));
+void after_local_2(int);
 void after_local_3(int) __attribute__((overloadable));
 
 // Make sure we allow C-specific conversions in C.
@@ -106,8 +109,8 @@
   void foo(char *c) __attribute__((overloadable));
   void (*ptr1)(void *) = &foo;
   void (*ptr2)(char *) = &foo;
-  void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@105{{candidate function}} expected-note@106{{candidate function}}
-  void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type '<overloaded function type>'}} expected-note@105{{candidate function}} expected-note@106{{candidate function}}
+  void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
+  void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type '<overloaded function type>'}} expected-note@-5{{candidate function}} expected-note@-4{{candidate function}}
 
   void (*specific1)(int *) = (void (*)(void *))&foo; // expected-warning{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type 'void (*)(void *)'}}
   void *specific2 = (void (*)(void *))&foo;
@@ -117,8 +120,8 @@
   void disabled(char *c) __attribute__((overloadable, enable_if(1, "The function name lies.")));
   // To be clear, these should all point to the last overload of 'disabled'
   void (*dptr1)(char *c) = &disabled;
-  void (*dptr2)(void *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@115{{candidate function made ineligible by enable_if}} expected-note@116{{candidate function made ineligible by enable_if}} expected-note@117{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
-  void (*dptr3)(int *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@115{{candidate function made ineligible by enable_if}} expected-note@116{{candidate function made ineligible by enable_if}} expected-note@117{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
+  void (*dptr2)(void *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function made ineligible by enable_if}} expected-note@-3{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
+  void (*dptr3)(int *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@-6{{candidate function made ineligible by enable_if}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
 
   void *specific_disabled = &disabled;
 }
@@ -131,14 +134,14 @@
   void foo(char *c) __attribute__((overloadable));
   void foo(short *c) __attribute__((overloadable));
   foo(charbuf);
-  foo(ucharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@131{{candidate function}} expected-note@132{{candidate function}}
-  foo(intbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@131{{candidate function}} expected-note@132{{candidate function}}
+  foo(ucharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-3{{candidate function}} expected-note@-2{{candidate function}}
+  foo(intbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
 
   void bar(unsigned char *c) __attribute__((overloadable));
   void bar(signed char *c) __attribute__((overloadable));
-  bar(charbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@137{{candidate function}} expected-note@138{{candidate function}}
+  bar(charbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@-2{{candidate function}} expected-note@-1{{candidate function}}
   bar(ucharbuf);
-  bar(intbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@137{{candidate function}} expected-note@138{{candidate function}}
+  bar(intbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
 }
 
 void dropping_qualifiers_is_incompatible() {
@@ -148,8 +151,89 @@
   void foo(char *c) __attribute__((overloadable));
   void foo(const volatile unsigned char *c) __attribute__((overloadable));
 
-  foo(ccharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
-  foo(vcharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
+  foo(ccharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-3{{candidate function}} expected-note@-2{{candidate function}}
+  foo(vcharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
+}
+
+void overloadable_with_global() {
+  void wg_foo(void) __attribute__((overloadable)); // expected-note{{previous}}
+  void wg_foo(int) __attribute__((overloadable));
+}
+
+int wg_foo; // expected-error{{redefinition of 'wg_foo' as different kind of symbol}}
+
+#if !__has_feature(overloadable_unmarked)
+#error "We should have unmarked overload support"
+#endif
+
+void unmarked_overloadable() {
+  void to_foo0(int);
+  void to_foo0(double) __attribute__((overloadable)); // expected-note{{previous overload}}
+  void to_foo0(int);
+  void to_foo0(double); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo0(int);
+
+  void to_foo1(int) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+  void to_foo1(double);
+  void to_foo1(int); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo1(double);
+  void to_foo1(int); // expected-error{{must have the 'overloadable' attribute}}
+
+  void to_foo2(int); // expected-note{{previous unmarked overload}}
+  void to_foo2(double) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+  void to_foo2(int) __attribute__((overloadable)); // expected-error {{must not have the 'overloadable' attribute}}
+  void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo2(int);
+  void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo2(int);
+
+  void to_foo3(int);
+  void to_foo3(double) __attribute__((overloadable)); // expected-note{{previous overload}}
+  void to_foo3(int);
+  void to_foo3(double); // expected-error{{must have the 'overloadable' attribute}}
+
+  void to_foo4(int) __attribute__((overloadable)); // expected-note{{previous overload}}
+  void to_foo4(int); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo4(double) __attribute__((overloadable));
+
+  void to_foo5(int);
+  void to_foo5(int); // expected-note 3{{previous unmarked overload}}
+  void to_foo5(float) __attribute__((overloadable));
+  void to_foo5(double); // expected-error{{at most one 'overloadable' function for a given name may lack the 'overloadable' attribute}}
+  void to_foo5(float) __attribute__((overloadable));
+  void to_foo5(short); // expected-error{{at most one 'overloadable' function for a given name may lack the 'overloadable' attribute}}
+  void to_foo5(long); // expected-error{{at most one 'overloadable' function for a given name may lack the 'overloadable' attribute}}
+  void to_foo5(double) __attribute__((overloadable));
+
+  void to_foo6(int) __attribute__((enable_if(1, ""), overloadable)); // expected-note{{previous overload}}
+  void to_foo6(int) __attribute__((enable_if(1, ""))); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo6(int) __attribute__((enable_if(1, ""), overloadable));
+
+  void to_foo7(int) __attribute__((enable_if(1, ""))); // expected-note{{previous unmarked overload}}
+  void to_foo7(int) __attribute__((enable_if(1, ""), overloadable)); // expected-error{{must not have the 'overloadable' attribute}}
+  void to_foo7(int) __attribute__((enable_if(1, "")));
+
+  void to_foo8(char *__attribute__((pass_object_size(0))))
+    __attribute__((enable_if(1, "")));
+  void to_foo8(char *__attribute__((pass_object_size(0))))
+    __attribute__((overloadable));
+
+  void to_foo9(int); // expected-note{{previous unmarked overload}}
+  // FIXME: It would be nice if we did better with the "previous unmarked
+  // overload" diag.
+  void to_foo9(int) __attribute__((overloadable)); // expected-error{{must not have the 'overloadable' attribute}} expected-note{{previous declaration}} expected-note{{previous unmarked overload}}
+  void to_foo9(float); // expected-error{{conflicting types for 'to_foo9'}}
+  void to_foo9(float) __attribute__((overloadable));
+  void to_foo9(double); // expected-error{{at most one 'overloadable' function for a given name may lack the 'overloadable' attribute}}
+  void to_foo9(double) __attribute__((overloadable));
+
+  void to_foo10(int) __attribute__((overloadable));
+  void to_foo10(double); // expected-note{{previous unmarked overload}}
+  // no "note: previous redecl" if no previous decl has `overloadable`
+  // spelled out
+  void to_foo10(float); // expected-error{{at most one 'overloadable' function for a given name may lack the 'overloadable' attribute}}
+  void to_foo10(float); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo10(float); // expected-error{{must have the 'overloadable' attribute}}
 }
 
 // Bug: we used to treat `__typeof__(foo)` as though it was `__typeof__(&foo)`
Index: test/PCH/attrs.c
===================================================================
--- test/PCH/attrs.c
+++ test/PCH/attrs.c
@@ -13,8 +13,9 @@
 
 #else
 
+float f(float);
 double f(double); // expected-error{{overloadable}}
-                  // expected-note@11{{previous overload}}
+                  // expected-note@-2{{previous unmarked overload}}
 void h() { g(0); }
 
 #endif
Index: test/CodeGenCXX/mangle-ms.cpp
===================================================================
--- test/CodeGenCXX/mangle-ms.cpp
+++ test/CodeGenCXX/mangle-ms.cpp
@@ -399,6 +399,13 @@
 extern "C" void __attribute__((overloadable)) overloaded_fn() {}
 // CHECK-DAG: @"\01?overloaded_fn@@$$J0YAXXZ"
 
+extern "C" void overloaded_fn2() {}
+// CHECK-DAG: @overloaded_fn2
+//
+extern "C" void __attribute__((overloadable)) overloaded_fn3();
+extern "C" void overloaded_fn3() {}
+// CHECK-DAG: @overloaded_fn3
+
 namespace UnnamedType {
 struct S {
   typedef struct {} *T1[1];
Index: test/CodeGen/mangle.c
===================================================================
--- test/CodeGen/mangle.c
+++ test/CodeGen/mangle.c
@@ -9,6 +9,10 @@
 // CHECK: @_Z2f0l
 void __attribute__((__overloadable__)) f0(long b) {}
 
+// Unless it's unmarked.
+// CHECK: @f0
+void f0(float b) {}
+
 // CHECK: @bar
 
 // These should get merged.
Index: test/CodeGen/mangle-ms.c
===================================================================
--- test/CodeGen/mangle-ms.c
+++ test/CodeGen/mangle-ms.c
@@ -2,3 +2,12 @@
 
 // CHECK: define void @"\01?f@@$$J0YAXP6AX@Z@Z"
 __attribute__((overloadable)) void f(void (*x)()) {}
+
+// CHECK: define void @f
+void f(void (*x)(int)) {}
+
+// CHECK: define void @g
+void g(void (*x)(int)) {}
+
+// CHECK: define void @"\01?g@@$$J0YAXP6AX@Z@Z"
+__attribute__((overloadable)) void g(void (*x)()) {}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -1327,15 +1327,17 @@
 /// overloaded function declaration or has the "overloadable"
 /// attribute.
 static bool AllowOverloadingOfFunction(LookupResult &Previous,
-                                       ASTContext &Context) {
+                                       ASTContext &Context,
+                                       const FunctionDecl *New) {
   if (Context.getLangOpts().CPlusPlus)
     return true;
 
   if (Previous.getResultKind() == LookupResult::FoundOverloaded)
     return true;
 
-  return (Previous.getResultKind() == LookupResult::Found
-          && Previous.getFoundDecl()->hasAttr<OverloadableAttr>());
+  return Previous.getResultKind() == LookupResult::Found &&
+         (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
+          New->hasAttr<OverloadableAttr>());
 }
 
 /// Add this decl to the scope shadowed decl chains.
@@ -2933,6 +2935,44 @@
     New->dropAttr<InternalLinkageAttr>();
   }
 
+  if (!getLangOpts().CPlusPlus) {
+    const NamedDecl *MostRecentOld = Old->getMostRecentDecl();
+    bool OldOvl = MostRecentOld->hasAttr<OverloadableAttr>();
+    if (OldOvl != New->hasAttr<OverloadableAttr>() &&
+        !MostRecentOld->isImplicit()) {
+      Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch)
+        << New << OldOvl;
+
+      // Try our best to find a decl that actually has (or lacks) the
+      // overloadable attribute for the note. In most cases (e.g. programs with
+      // only one broken declaration/definition), this won't matter.
+      //
+      // FIXME: We could do this if we juggled some extra state in
+      // OverloadableAttr, rather than just removing it.
+      const Decl *DiagOld = MostRecentOld;
+      if (OldOvl) {
+        auto OldIter =
+            llvm::find_if(MostRecentOld->redecls(), [](const Decl *D) {
+              const auto *A = D->getAttr<OverloadableAttr>();
+              return A && !A->isImplicit();
+            });
+        // If we've implicitly added *all* of the overloadable attrs to this
+        // chain, emitting a "previous redecl" note is pointless.
+        DiagOld = OldIter == MostRecentOld->redecls_end() ? nullptr : *OldIter;
+      }
+
+      if (DiagOld)
+        Diag(DiagOld->getLocation(),
+             diag::note_attribute_overloadable_prev_overload)
+          << OldOvl;
+
+      if (OldOvl)
+        New->addAttr(OverloadableAttr::CreateImplicit(Context));
+      else
+        New->dropAttr<OverloadableAttr>();
+    }
+  }
+
   // If a function is first declared with a calling convention, but is later
   // declared or defined without one, all following decls assume the calling
   // convention of the first.
@@ -5540,9 +5580,12 @@
   Context.getExternCContextDecl()->makeDeclVisibleInContext(ND);
 }
 
-NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
-  // FIXME: We can have multiple results via __attribute__((overloadable)).
+NamedDecl *
+Sema::findLocallyScopedExternCDecl(DeclarationName Name,
+                                   SmallVectorImpl<NamedDecl *> *AllResults) {
   auto Result = Context.getExternCContextDecl()->lookup(Name);
+  if (AllResults)
+    AllResults->append(Result.begin(), Result.end());
   return Result.empty() ? nullptr : *Result.begin();
 }
 
@@ -7143,9 +7186,12 @@
     // variable declared in function scope. We don't need this in C++, because
     // we find local extern decls in the surrounding file-scope DeclContext.
     if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
-      if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
+      SmallVector<NamedDecl *, 4> Prevs;
+      if (S.findLocallyScopedExternCDecl(ND->getDeclName(), &Prevs)) {
         Previous.clear();
-        Previous.addDecl(Prev);
+        for (NamedDecl *ND : Prevs)
+          Previous.addDecl(ND);
+        Previous.resolveKind();
         return true;
       }
     }
@@ -9155,6 +9201,7 @@
   bool MergeTypeWithPrevious = !getLangOpts().CPlusPlus &&
                                !Previous.isShadowed();
 
+  bool MayNeedOverloadableChecks = false;
   bool Redeclaration = false;
   NamedDecl *OldDecl = nullptr;
 
@@ -9165,66 +9212,74 @@
     // a declaration that requires merging. If it's an overload,
     // there's no more work to do here; we'll just add the new
     // function to the scope.
-    if (!AllowOverloadingOfFunction(Previous, Context)) {
+    if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) {
       NamedDecl *Candidate = Previous.getRepresentativeDecl();
       if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) {
         Redeclaration = true;
         OldDecl = Candidate;
       }
     } else {
+      MayNeedOverloadableChecks = true;
       switch (CheckOverload(S, NewFD, Previous, OldDecl,
-                            /*NewIsUsingDecl*/ false)) {
+                            /*NewIsUsingDecl=*/false)) {
       case Ovl_Match:
-        Redeclaration = true;
-        break;
-
       case Ovl_NonFunction:
         Redeclaration = true;
         break;
 
       case Ovl_Overload:
         Redeclaration = false;
         break;
       }
-
-      if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
-        // If a function name is overloadable in C, then every function
-        // with that name must be marked "overloadable".
-        Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
-          << Redeclaration << NewFD;
-        NamedDecl *OverloadedDecl =
-            Redeclaration ? OldDecl : Previous.getRepresentativeDecl();
-        Diag(OverloadedDecl->getLocation(),
-             diag::note_attribute_overloadable_prev_overload);
-        NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
-      }
     }
   }
 
   // Check for a previous extern "C" declaration with this name.
   if (!Redeclaration &&
-      checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
-    if (!Previous.empty()) {
-      // This is an extern "C" declaration with the same name as a previous
-      // declaration, and thus redeclares that entity...
-      Redeclaration = true;
-      OldDecl = Previous.getFoundDecl();
-      MergeTypeWithPrevious = false;
-
-      // ... except in the presence of __attribute__((overloadable)).
-      if (OldDecl->hasAttr<OverloadableAttr>()) {
-        if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
-          Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
-            << Redeclaration << NewFD;
-          Diag(Previous.getFoundDecl()->getLocation(),
-               diag::note_attribute_overloadable_prev_overload);
-          NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
-        }
-        if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
-          Redeclaration = false;
-          OldDecl = nullptr;
-        }
-      }
+      checkForConflictWithNonVisibleExternC(*this, NewFD, Previous) &&
+      !Previous.empty()) {
+    // This is an extern "C" declaration with the same name as a previous
+    // declaration, and thus redeclares that entity, unless the overloadable
+    // attribute is present.
+    MergeTypeWithPrevious = false;
+    Redeclaration = true;
+
+    switch (CheckOverload(S, NewFD, Previous, OldDecl,
+                          /*NewIsUsingDecl=*/false)) {
+    case Ovl_Match:
+      // We're not guaranteed to be handed the most recent decl, and
+      // __attribute__((overloadable)) depends somewhat on source order.
+      OldDecl = OldDecl->getMostRecentDecl();
+      break;
+
+    case Ovl_NonFunction:
+      break;
+
+    case Ovl_Overload: {
+      // Otherwise, we should be in Ovl_NonFunction. This matters because we
+      // don't want to hide diags for finding NonFunctions if we find an
+      // overloadable function.
+      assert(llvm::all_of(
+          Previous, [](const NamedDecl *ND) { return isa<FunctionDecl>(ND); }));
+
+      bool FoundOverloadableAttr = false;
+      if (!getLangOpts().CPlusPlus) {
+        MayNeedOverloadableChecks = true;
+        FoundOverloadableAttr =
+            NewFD->hasAttr<OverloadableAttr>() ||
+            llvm::any_of(Previous, [](const NamedDecl *ND) {
+              return ND->getMostRecentDecl()->hasAttr<OverloadableAttr>();
+            });
+      }
+
+      Redeclaration = !FoundOverloadableAttr;
+      // If we didn't find an exact match and none of the overloads have the
+      // overloadable attribute, we can't do much more than picking an arbitrary
+      // decl for diags.
+      if (Redeclaration)
+        OldDecl = Previous.getRepresentativeDecl();
+      break;
+    }
     }
   }
 
@@ -9315,6 +9370,32 @@
           NewFD->setAccess(OldDecl->getAccess());
       }
     }
+  } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks &&
+             !NewFD->getAttr<OverloadableAttr>()) {
+    assert((Previous.empty() ||
+            llvm::any_of(
+                Previous,
+                [](const NamedDecl *ND) {
+                  return ND->getMostRecentDecl()->hasAttr<OverloadableAttr>();
+                })) &&
+           "Non-redecls shouldn't happen without overloadable present");
+
+    auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) {
+      const auto *FD = dyn_cast<FunctionDecl>(ND);
+      return FD && !FD->getMostRecentDecl()->hasAttr<OverloadableAttr>();
+    });
+
+    if (OtherUnmarkedIter != Previous.end()) {
+      const auto *OtherUnmarked =
+          cast<FunctionDecl>((*OtherUnmarkedIter)->getMostRecentDecl());
+      Diag(NewFD->getLocation(),
+           diag::err_attribute_overloadable_multiple_unmarked_overloads);
+      Diag(OtherUnmarked->getLocation(),
+           diag::note_attribute_overloadable_prev_overload)
+          << false;
+
+      NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
+    }
   }
 
   // Semantic checking for this function declaration (in isolation).
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1133,6 +1133,7 @@
       .Case("enumerator_attributes", true)
       .Case("nullability", true)
       .Case("nullability_on_arrays", true)
+      .Case("overloadable_unmarked", true)
       .Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory))
       .Case("thread_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Thread))
       .Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow))
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -528,7 +528,10 @@
   llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars;
 
   /// \brief Look for a locally scoped extern "C" declaration by the given name.
-  NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);
+  ///
+  /// If AllResults is not null, any results we find will be appended to it.
+  NamedDecl *findLocallyScopedExternCDecl(
+      DeclarationName Name, SmallVectorImpl<NamedDecl *> *AllResults = nullptr);
 
   typedef LazyVector<VarDecl *, ExternalSemaSource,
                      &ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3284,13 +3284,15 @@
   "IBOutletCollection properties should be copy/strong and not assign">,
   InGroup<ObjCInvalidIBOutletProperty>;
   
-def err_attribute_overloadable_missing : Error<
-  "%select{overloaded function|redeclaration of}0 %1 must have the "
-  "'overloadable' attribute">;
+def err_attribute_overloadable_mismatch : Error<
+  "redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">;
 def note_attribute_overloadable_prev_overload : Note<
-  "previous overload of function is here">;
+  "previous %select{unmarked |}0overload of function is here">;
 def err_attribute_overloadable_no_prototype : Error<
   "'overloadable' function %0 must have a prototype">;
+def err_attribute_overloadable_multiple_unmarked_overloads : Error<
+  "at most one 'overloadable' function for a given name may lack the "
+  "'overloadable' attribute">;
 def warn_ns_attribute_wrong_return_type : Warning<
   "%0 attribute only applies to %select{functions|methods|properties}1 that "
   "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -651,7 +651,28 @@
   linkage specification, it's name *will* be mangled in the same way as it
   would in C.
 
-Query for this feature with ``__has_extension(attribute_overloadable)``.
+For the purpose of backwards compatibility, at most one function with the same
+name as other ``overloadable`` functions may omit the ``overloadable``
+attribute. In this case, the function without the ``overloadable`` attribute
+will not have its name mangled.
+
+For example:
+
+.. code-block:: c
+
+  // Notes with mangled names assume Itanium mangling.
+  int f(int);
+  int f(double) __attribute__((overloadable));
+  void foo() {
+    f(5); // Emits a call to f (not _Z1fi, as it would with an overload that
+          // was marked with overloadable).
+    f(1.0); // Emits a call to _Z1fd.
+  }
+
+Support for unmarked overloads is not present in some versions of clang. You may
+query for it using ``__has_feature(overloadable_unmarked)``.
+
+Query for this attribute with ``__has_attribute(overloadable)``.
   }];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to