george.burgess.iv updated this revision to Diff 97698.
george.burgess.iv added a comment.

We now require `transparently_overloadable` on all redeclarations. Allowing 
mixed `transparently_overloadable` and `overloadable` coming soon.


https://reviews.llvm.org/D32332

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/Sema/SemaDecl.cpp
  test/CodeGen/mangle-ms.c
  test/CodeGen/mangle.c
  test/CodeGenCXX/mangle-ms.cpp
  test/Sema/overloadable.c

Index: test/Sema/overloadable.c
===================================================================
--- test/Sema/overloadable.c
+++ test/Sema/overloadable.c
@@ -3,6 +3,9 @@
 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 var2 __attribute__((transparently_overloadable)); // expected-error{{'transparently_overloadable' attribute only applies to functions}}
+void params2(void) __attribute__((transparently_overloadable(12))); // expected-error {{'transparently_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); // expected-error{{redeclaration of 'f' must have the 'overloadable' attribute}} \
@@ -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,6 +151,65 @@
   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}}
+
+void transparent_overloadable() {
+  void to_foo0(int); // expected-note{{previous declaration}}
+  void to_foo0(double) __attribute__((overloadable)); // expected-error{{conflicting types}}
+
+  void to_foo1(int) __attribute__((overloadable)); // expected-note 2{{previous overload of function}}
+  void to_foo1(double); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo1(int); // expected-error{{must have the 'overloadable' attribute}}
+
+  void to_foo2(int) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+  void to_foo2(double) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}}
+  void to_foo2(int); // expected-error{{must have the 'overloadable' attribute}}
+  void to_foo2(double); // expected-error{{must have the 'transparently_overloadable' attribute}}
+  void to_foo2(int); // expected-error{{must have the 'overloadable' attribute}}
+
+  void to_foo3(int) __attribute__((transparently_overloadable));
+  void to_foo3(double) __attribute__((overloadable)); // expected-note{{previous overload}}
+  void to_foo3(int) __attribute__((transparently_overloadable));
+  void to_foo3(double); // expected-error{{must have the 'overloadable' attribute}}
+
+  void to_foo4(int);
+  void to_foo4(int) __attribute__((transparently_overloadable));
+  void to_foo4(double) __attribute__((overloadable));
+
+  void to_foo5(int) __attribute__((overloadable)); // expected-note {{previous overload}}
+  void to_foo5(int) __attribute__((transparently_overloadable)); // expected-error{{mismatched transparency}}
+
+  void to_foo6(int);
+  void to_foo6(int) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}}
+  void to_foo6(double) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}}
+
+  void to_foo7(int);
+  void to_foo7(int) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}}
+  void to_foo7(float) __attribute__((overloadable));
+  void to_foo7(double) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}}
+
+  void to_foo8(int) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}}
+  void to_foo8(float) __attribute__((overloadable));
+  void to_foo8(double) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}}
+
+  void to_foo9(int) __attribute__((enable_if(1, ""), overloadable)); // expected-note{{previous overload}}
+  void to_foo9(int) __attribute__((enable_if(1, ""), transparently_overloadable)); // expected-error{{mismatched transparency}}
+
+  void to_foo10(int) __attribute__((enable_if(1, ""), transparently_overloadable)); // expected-note{{previous transparent}}
+  void to_foo10(int) __attribute__((enable_if(1, ""), overloadable)); // expected-error{{mismatched transparency}}
+
+  void to_foo11(char *__attribute__((pass_object_size(0)))) __attribute__((enable_if(1, ""), transparently_overloadable)); // expected-note{{previous transparent}}
+  void to_foo11(char *__attribute__((pass_object_size(0)))) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}}
+
+  void to_foo12(char *) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}}
+  void to_foo12(char *__attribute__((pass_object_size(0)))) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}}
 }
Index: test/CodeGenCXX/mangle-ms.cpp
===================================================================
--- test/CodeGenCXX/mangle-ms.cpp
+++ test/CodeGenCXX/mangle-ms.cpp
@@ -399,6 +399,9 @@
 extern "C" void __attribute__((overloadable)) overloaded_fn() {}
 // CHECK-DAG: @"\01?overloaded_fn@@$$J0YAXXZ"
 
+extern "C" void __attribute__((transparently_overloadable)) overloaded_fn2() {}
+// CHECK-DAG: @overloaded_fn2
+
 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 transparent.
+// CHECK: @f0
+void __attribute__((__transparently_overloadable__)) 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,6 @@
 
 // CHECK: define void @"\01?f@@$$J0YAXP6AX@Z@Z"
 __attribute__((overloadable)) void f(void (*x)()) {}
+
+// CHECK: define void @f
+__attribute__((transparently_overloadable)) void f(void (*x)(int)) {}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2806,6 +2806,38 @@
   return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq);
 }
 
+// Finds an overload to use in a diagnostic that says "previous overload was
+// here." This is a bit complicated, since sometimes we're looking at an
+// overload set, and other times we're only looking at a redecl chain.
+//
+// Ideally, we'd like to point to overloads with the actual overloadable
+// attribute on them, rather than one that gets implicitly added.
+static const NamedDecl *findDeclWithOverloadableAttr(
+    llvm::PointerUnion<const NamedDecl *, const LookupResult *> DiagInfo) {
+  auto GetRedeclWithOverloadable =
+      [](const NamedDecl *Base) -> const NamedDecl * {
+    for (const Decl *ND : Base->redecls())
+      if (auto *Ovl = ND->getAttr<OverloadableAttr>())
+        if (!Ovl->isImplicit())
+          return cast<NamedDecl>(ND);
+    return nullptr;
+  };
+
+  if (const auto *Base = DiagInfo.dyn_cast<const NamedDecl *>()) {
+    if (const NamedDecl *Redecl = GetRedeclWithOverloadable(Base))
+      return Redecl;
+    // Possible in ill-formed programs.
+    return Base;
+  }
+
+  const auto *Lookup = DiagInfo.get<const LookupResult *>();
+  for (const NamedDecl *Base : *Lookup)
+    if (const NamedDecl *Redecl = GetRedeclWithOverloadable(Base))
+      return Redecl;
+
+  return Lookup->getRepresentativeDecl();
+}
+
 /// MergeFunctionDecl - We just parsed a function 'New' from
 /// declarator D which has the same name and scope as a previous
 /// declaration 'Old'.  Figure out how to resolve this situation,
@@ -2880,6 +2912,24 @@
     New->dropAttr<InternalLinkageAttr>();
   }
 
+  if (!getLangOpts().CPlusPlus) {
+    const NamedDecl *MostRecentOld = Old->getMostRecentDecl();
+    if (const auto *OldOvl = MostRecentOld->getAttr<OverloadableAttr>()) {
+      // All redecls of a function with the overloadable attribute must have an
+      // overloadable attribute (even if it's implicit).
+      const auto *NewOvl = New->getAttr<OverloadableAttr>();
+      if (NewOvl->isTransparent() != OldOvl->isTransparent()) {
+        assert(!NewOvl->isImplicit() &&
+               "We generated an overloadable attr with bad transparency?");
+        Diag(NewOvl->getLocation(),
+             diag::err_attribute_overloadable_mismatched_transparency);
+        Diag(findDeclWithOverloadableAttr({MostRecentOld})->getLocation(),
+             diag::note_attribute_overloadable_prev_overload)
+            << OldOvl->isTransparent();
+      }
+    }
+  }
+
   // 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.
@@ -5432,9 +5482,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();
 }
 
@@ -7017,9 +7070,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;
       }
     }
@@ -8995,6 +9051,27 @@
            D->getFriendObjectKind() != Decl::FOK_None);
 }
 
+static void fixMissingOverloadableAttr(
+    Sema &S, FunctionDecl *FixOn, bool Redeclaration,
+    bool IsTransparentOverload,
+    llvm::PointerUnion<const NamedDecl *, const LookupResult *> DiagInfo) {
+  assert(!S.getLangOpts().CPlusPlus &&
+         "We don't care about overloadable in C++");
+
+  const NamedDecl *OldDecl = findDeclWithOverloadableAttr(DiagInfo);
+
+  S.Diag(FixOn->getLocation(), diag::err_attribute_overloadable_missing)
+      << Redeclaration << FixOn << IsTransparentOverload;
+  S.Diag(OldDecl->getLocation(),
+         diag::note_attribute_overloadable_prev_overload)
+      << IsTransparentOverload;
+
+  FixOn->addAttr(OverloadableAttr::CreateImplicit(
+      S.Context, IsTransparentOverload
+                     ? OverloadableAttr::GNU_transparently_overloadable
+                     : OverloadableAttr::GNU_overloadable));
+}
+
 /// \brief Perform semantic checking of a new function declaration.
 ///
 /// Performs semantic analysis of the new function declaration
@@ -9042,58 +9119,98 @@
       }
     } else {
       switch (CheckOverload(S, NewFD, Previous, OldDecl,
-                            /*NewIsUsingDecl*/ false)) {
-      case Ovl_Match:
-        Redeclaration = true;
-        break;
-
-      case Ovl_NonFunction:
+                            /*NewIsUsingDecl=*/false)) {
+      case Sema::Ovl_Match:
+      case Sema::Ovl_NonFunction:
         Redeclaration = true;
         break;
 
-      case Ovl_Overload:
+      case Sema::Ovl_Overload:
         Redeclaration = false;
         break;
       }
 
+      // Transparency is checked later.
       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));
+        bool IsTransparentOverload = false;
+        if (Redeclaration)
+          if (const auto *OldOvl = OldDecl->getAttr<OverloadableAttr>())
+            IsTransparentOverload = OldOvl->isTransparent();
+
+        llvm::PointerUnion<const NamedDecl *, const LookupResult *> DiagInfo;
+        if (Redeclaration)
+          DiagInfo = OldDecl;
+        else
+          DiagInfo = &Previous;
+        fixMissingOverloadableAttr(*this, NewFD, Redeclaration,
+                                   IsTransparentOverload, DiagInfo);
       }
     }
   }
 
   // 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));
+      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:
+      if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
+        // We only get the first declaration of local extern decls (redecls
+        // are hidden). Since the overloadable attribute only needs to be
+        // applied to all functions with the same name *after* the first
+        // declaration it was on, we need to check the most recent decl.
+        NamedDecl *NewestRedecl = OldDecl->getMostRecentDecl();
+        if (const auto *OldOvl = NewestRedecl->getAttr<OverloadableAttr>()) {
+          OldDecl = NewestRedecl;
+          fixMissingOverloadableAttr(
+              *this, NewFD, /*Redeclaration=*/true,
+              /*IsTransparentOverload=*/OldOvl->isTransparent(),
+              {NewestRedecl});
         }
-        if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
-          Redeclaration = false;
-          OldDecl = nullptr;
+      }
+      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) {
+        for (const NamedDecl *InitialND : Previous) {
+          const auto *ND = cast<NamedDecl>(InitialND->getMostRecentDecl());
+          const auto *OldOvl = ND->getAttr<OverloadableAttr>();
+          if (!OldOvl)
+            continue;
+
+          FoundOverloadableAttr = true;
+          if (!NewFD->hasAttr<OverloadableAttr>()) {
+            fixMissingOverloadableAttr(*this, NewFD, /*Redeclaration=*/false,
+                                       /*IsTransparentOverload=*/false, {ND});
+          }
+          break;
         }
       }
+
+      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;
     }
   }
 
@@ -9182,6 +9299,26 @@
           NewFD->setAccess(OldDecl->getAccess());
       }
     }
+  } else if (!getLangOpts().CPlusPlus) {
+    if (auto *NewOvl = NewFD->getAttr<OverloadableAttr>()) {
+      if (NewOvl->isTransparent()) {
+        auto Transparent = llvm::find_if(Previous, [](const NamedDecl *ND) {
+          if (auto *FD = dyn_cast<FunctionDecl>(ND))
+            if (auto *Ovl =
+                    FD->getMostRecentDecl()->getAttr<OverloadableAttr>())
+              return Ovl->isTransparent();
+          return false;
+        });
+
+        if (Transparent != Previous.end()) {
+          Diag(NewOvl->getLocation(),
+               diag::err_attribute_overloadable_too_many_transparent_overloads);
+          Diag(findDeclWithOverloadableAttr({*Transparent})->getLocation(),
+               diag::note_attribute_overloadable_prev_overload)
+              << true;
+        }
+      }
+    }
   }
 
   // Semantic checking for this function declaration (in isolation).
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -368,9 +368,10 @@
 bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     LanguageLinkage L = FD->getLanguageLinkage();
-    // Overloadable functions need mangling.
-    if (FD->hasAttr<OverloadableAttr>())
-      return true;
+    // Non-transparent overloadable functions need mangling.
+    if (auto *A = FD->getAttr<OverloadableAttr>())
+      if (!A->isTransparent())
+        return true;
 
     // The ABI expects that we would never mangle "typical" user-defined entry
     // points regardless of visibility or freestanding-ness.
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -579,9 +579,10 @@
   const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
   if (FD) {
     LanguageLinkage L = FD->getLanguageLinkage();
-    // Overloadable functions need mangling.
-    if (FD->hasAttr<OverloadableAttr>())
-      return true;
+    // Non-transparent overloadable functions need mangling.
+    if (auto *A = FD->getAttr<OverloadableAttr>())
+      if (!A->isTransparent())
+        return true;
 
     // "main" is not mangled.
     if (FD->isMain())
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
@@ -3277,11 +3277,15 @@
   
 def err_attribute_overloadable_missing : Error<
   "%select{overloaded function|redeclaration of}0 %1 must have the "
-  "'overloadable' attribute">;
+  "'%select{|transparently_}2overloadable' attribute">;
 def note_attribute_overloadable_prev_overload : Note<
-  "previous overload of function is here">;
+  "previous%select{| transparent}0 overload of function is here">;
 def err_attribute_overloadable_no_prototype : Error<
   "'overloadable' function %0 must have a prototype">;
+def err_attribute_overloadable_too_many_transparent_overloads : Error<
+  "only one 'overloadable' overload may be transparent">;
+def err_attribute_overloadable_mismatched_transparency : Error<
+  "mismatched transparency on redeclaration of an 'overloadable' function">;
 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,6 +651,30 @@
   linkage specification, it's name *will* be mangled in the same way as it
   would in C.
 
+For the purpose of backwards compatibility, overload sets may have at most one
+``overloadable`` function marked as transparent. Transparent overloads do not
+carry the requirement that the name be mangled. You can designate a transparent
+overload by using the ``transparently_overloadable`` attribute instead of
+``overloadable``.
+
+An example of all of this:
+
+.. code-block:: c
+
+  // Notes with mangled names assume Itanium mangling.
+  int f(int) __attribute__((transparently_overloadable));
+  int f(double) __attribute__((overloadable));
+  void foo() {
+    f(5); // Emits a call to f (not _Z1fi, as it would with an overload that
+          // wasn't marked as transparent).
+    f(1.0); // Emits a call to _Z1fd.
+  }
+
+  // Error: f already has a transparent overload
+  int f(float) __attribute__((transparently_overloadable));
+  // Error: f(int) is declared transparent above, but is not here.
+  int f(int) __attribute__((overloadable));
+
 Query for this feature with ``__has_extension(attribute_overloadable)``.
   }];
 }
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1532,8 +1532,10 @@
 }
 
 def Overloadable : Attr {
-  let Spellings = [GNU<"overloadable">];
+  let Spellings = [GNU<"overloadable">, GNU<"transparently_overloadable">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Accessors = [Accessor<"isTransparent",
+                     [GNU<"transparently_overloadable">]>];
   let Documentation = [OverloadableDocs];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to