george.burgess.iv updated this revision to Diff 99851.
george.burgess.iv added a comment.
Remove the `transparent_overloadable` attribute entirely.
This approach presents one problem that I didn't see until I implemented it:
I'd like to have something to detect that this feature exists. The quick fix
seems to be "readd `transparently_overloadable`, make it equivalent to not
having the attribute at all, and be happy," but that feels really icky (as does
adding a special `__has_enhanced_overloadable` or whatever macro just for this).
Do we have a standard way of saying "does clang support an enhanced version of
attribute X"? If not, I'm happy to put together a patch so people can query for
that in a somewhat uniform way. This would let users write something like
`__has_attribute_enhancement(overloadable, unmarked_overloads)`, and would be
more broadly useful if we decide to ever add features to another attribute in
the future (`diagnose_if` comes to mind if I can ever find time to get back to
it...).
Apologies for the lag; life is busy. :)
https://reviews.llvm.org/D32332
Files:
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
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,8 +3,8 @@
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
@@ -71,19 +71,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 +106,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 +117,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 +131,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 +148,64 @@
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 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);
+ void to_foo2(double) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+ void to_foo2(int) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+ void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+ void to_foo2(int); // expected-error{{must have the 'overloadable' attribute}}
+ void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+ void to_foo2(int); // expected-error{{must have the 'overloadable' attribute}}
+
+ 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_foo7(int) __attribute__((enable_if(1, "")));
+ void to_foo7(int) __attribute__((enable_if(1, ""), overloadable));
+
+ void to_foo8(char *__attribute__((pass_object_size(0)))) __attribute__((enable_if(1, "")));
+ void to_foo8(char *__attribute__((pass_object_size(0)))) __attribute__((overloadable));
}
// 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
@@ -1326,15 +1326,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.
@@ -2932,6 +2934,30 @@
New->dropAttr<InternalLinkageAttr>();
}
+ if (!getLangOpts().CPlusPlus) {
+ const NamedDecl *MostRecentOld = Old->getMostRecentDecl();
+ if (MostRecentOld->hasAttr<OverloadableAttr>() &&
+ !New->hasAttr<OverloadableAttr>()) {
+ Diag(New->getLocation(), diag::err_attribute_overloadable_missing)
+ << true << New;
+
+ auto DiagnoseOldIter =
+ llvm::find_if(MostRecentOld->redecls(), [](const Decl *D) {
+ const auto *Ovl = D->getAttr<OverloadableAttr>();
+ return Ovl && !Ovl->isImplicit();
+ });
+
+ assert(DiagnoseOldIter != MostRecentOld->redecls_end() &&
+ "Shouldn't be implicitly adding overloadable attrs without the "
+ "user adding one.");
+ Diag((*DiagnoseOldIter)->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << true;
+
+ New->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
+ }
+
// 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.
@@ -5546,9 +5572,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();
}
@@ -7146,9 +7175,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;
}
}
@@ -9156,6 +9188,7 @@
bool MergeTypeWithPrevious = !getLangOpts().CPlusPlus &&
!Previous.isShadowed();
+ bool MayNeedOverloadableChecks = false;
bool Redeclaration = false;
NamedDecl *OldDecl = nullptr;
@@ -9166,66 +9199,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)) {
- case Ovl_Match:
+ /*NewIsUsingDecl=*/false)) {
+ case Sema::Ovl_Match:
+ case Sema::Ovl_NonFunction:
Redeclaration = true;
break;
- case Ovl_NonFunction:
- Redeclaration = true;
- break;
-
- case Ovl_Overload:
+ case Sema::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;
+ }
}
}
@@ -9316,6 +9357,33 @@
NewFD->setAccess(OldDecl->getAccess());
}
}
+ } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks &&
+ !NewFD->getAttr<OverloadableAttr>()) {
+ assert((Previous.empty() ||
+ llvm::any_of(Previous,
+ [](const NamedDecl *ND) {
+ return ND->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;
+
+ // Don't add an implicit overloadable attribute here; it's unclear what
+ // the user was trying to do, and adding an implicit overloadable attr can
+ // make our diagnostics more confusing than just leaving the decl alone.
+ }
}
// Semantic checking for this function declaration (in isolation).
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
@@ -3282,12 +3282,14 @@
InGroup<ObjCInvalidIBOutletProperty>;
def err_attribute_overloadable_missing : Error<
- "%select{overloaded function|redeclaration of}0 %1 must have the "
- "'overloadable' attribute">;
+ "redeclaration of %1 must have 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,6 +651,24 @@
linkage specification, it's name *will* be mangled in the same way as it
would in C.
+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.
+ }
+
Query for this feature with ``__has_extension(attribute_overloadable)``.
}];
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits