Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1563,8 +1563,21 @@ } def Overloadable : Attr { - let Spellings = [GNU<"overloadable">]; + let Spellings = [GNU<"overloadable">, GNU<"transparently_overloadable">]; let Subjects = SubjectList<[Function], ErrorDiag>; + let Accessors = [Accessor<"isSpelledTransparent", + [GNU<"transparently_overloadable">]>]; + // ForcedTransparency is only used so we can provide better diagnostics in the + // case of an ill-formed program. + let Args = [BoolArgument<"ForcedTransparency", /*opt=*/0, /*fake=*/1>]; + let AdditionalMembers = [{ + void forceTransparency() { forcedTransparency = true; } + + bool isTransparent() const { + return forcedTransparency || isSpelledTransparent(); + } + }]; + let Documentation = [OverloadableDocs]; } Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -651,6 +651,60 @@ 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``. + +For example: + +.. 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)); + +When clang sees a redeclaration of a function tagged with +``transparently_overloadable``, but prior declarations are tagged with +``overloadable``, clang will emit a warning and act as though prior declarations +were marked with ``transparently_overloadable``. Beware: this behavior can cause +subtle bugs, since it allows code like the following: + +.. code-block:: c + + // foo.h + int g(int) __attribute__((overloadable)); + int g(double) __attribute__((overloadable)); + void bar(void); + void baz(void); + + // foo.c + // Warning: g(int) is not declared transparent above, but is here. + int g(int) __attribute__((transparently_overloadable)); + void bar() { + g(1); // Emits a call to g (not _Z1gi) + g(1.); // Emits a call to _Z1gf + } + + // bar.c + // Warning: g(double) is not declared transparent above, but is here. + int g(double) __attribute__((transparently_overloadable)); + void bar() { + g(1); // Emits a call to _Z1gi + g(1.); // Emits a call to g (not _Z1gf) + } + Query for this feature with ``__has_extension(attribute_overloadable)``. }]; } Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -334,6 +334,7 @@ def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; +def OverloadChangesTransparency : DiagGroup<"overload-changes-transparency">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; def Packed : DiagGroup<"packed">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3280,11 +3280,19 @@ 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 warn_attribute_overloadable_mismatched_transparency : Warning< + "mismatched transparency on redeclaration of an 'overloadable' function">, + InGroup>; +def err_attribute_overloadable_mismatched_transparency : Error< + "mismatched transparency on redeclaration of a 'transparently_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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -528,7 +528,10 @@ llvm::SmallPtrSet 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 *AllResults = nullptr); typedef LazyVector Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -579,9 +579,10 @@ const FunctionDecl *FD = dyn_cast(D); if (FD) { LanguageLinkage L = FD->getLanguageLinkage(); - // Overloadable functions need mangling. - if (FD->hasAttr()) - return true; + // Non-transparent overloadable functions need mangling. + if (const auto *A = FD->getAttr()) + if (!A->isTransparent()) + return true; // "main" is not mangled. if (FD->isMain()) 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(D)) { LanguageLinkage L = FD->getLanguageLinkage(); - // Overloadable functions need mangling. - if (FD->hasAttr()) - return true; + // Non-transparent overloadable functions need mangling. + if (const auto *A = FD->getAttr()) + 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/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2806,6 +2806,40 @@ 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 DiagInfo, + bool SpelledTransparent = false) { + auto GetRedeclWithOverloadable = + [&](const NamedDecl *Base) -> const NamedDecl * { + for (const Decl *ND : Base->redecls()) + if (const auto *Ovl = ND->getAttr()) + if (!Ovl->isImplicit() && + (!SpelledTransparent || Ovl->isSpelledTransparent())) + return cast(ND); + return nullptr; + }; + + if (const auto *Base = DiagInfo.dyn_cast()) { + if (const NamedDecl *Redecl = GetRedeclWithOverloadable(Base)) + return Redecl; + // Possible in ill-formed programs. + return Base; + } + + const auto *Lookup = DiagInfo.get(); + 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 +2914,36 @@ New->dropAttr(); } + if (!getLangOpts().CPlusPlus) { + const NamedDecl *MostRecentOld = Old->getMostRecentDecl(); + if (const auto *OldOvl = MostRecentOld->getAttr()) { + auto *NewOvl = New->getAttr(); + assert(NewOvl && "Later redecl should always have an overloadable attr!"); + if (NewOvl->isTransparent() != OldOvl->isTransparent()) { + assert(!NewOvl->isImplicit() && + "We generated an overloadable attr with bad transparency?"); + + bool TransitionToTransparent = NewOvl->isTransparent(); + // Assume the user's intent was to make New a transparent overload. We + // can catch more issues later if we pretend this was spelled + // "transparent". + if (!TransitionToTransparent) + NewOvl->forceTransparency(); + + Diag(NewOvl->getLocation(), + TransitionToTransparent + ? diag::warn_attribute_overloadable_mismatched_transparency + : diag::err_attribute_overloadable_mismatched_transparency); + + const NamedDecl *Other = findDeclWithOverloadableAttr( + {MostRecentOld}, /*SpelledTransparent=*/OldOvl->isTransparent()); + Diag(Other->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. @@ -5433,9 +5497,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 *AllResults) { auto Result = Context.getExternCContextDecl()->lookup(Name); + if (AllResults) + AllResults->append(Result.begin(), Result.end()); return Result.empty() ? nullptr : *Result.begin(); } @@ -7030,9 +7097,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 Prevs; + if (S.findLocallyScopedExternCDecl(ND->getDeclName(), &Prevs)) { Previous.clear(); - Previous.addDecl(Prev); + for (NamedDecl *ND : Prevs) + Previous.addDecl(ND); + Previous.resolveKind(); return true; } } @@ -9009,6 +9079,75 @@ D->getFriendObjectKind() != Decl::FOK_None); } +static void fixMissingOverloadableAttr( + Sema &S, FunctionDecl *FixOn, bool Redeclaration, + bool IsTransparentOverload, + llvm::PointerUnion 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)); +} + +// Given a new FunctionDecl (and, if it's a redecl, the previous decl), ensure +// that the transparency of the new FunctionDecl is sane. If not, this will emit +// diagnostics. +static void checkPotentialNewTransparentOverload(Sema &S, + const FunctionDecl *NewFD, + const NamedDecl *OldDecl, + const LookupResult &Previous) { + assert(!S.getLangOpts().CPlusPlus && + "We don't care about overloadable in C++"); + + const auto *NewOvl = NewFD->getAttr(); + // Use isSpelledTransparent so that we don't complain about vanilla + // `overloadable` functions. + if (!NewOvl || !NewOvl->isSpelledTransparent()) + return; + + // If the transparency hasn't changed, we can skip this (...which is necessary + // in some ill-formed programs, so we don't bombard the user with N diags when + // one would do just as well). + if (OldDecl) + if (const auto *OldOvl = OldDecl->getAttr()) + if (OldOvl->isTransparent()) + return; + + auto Transparent = llvm::find_if(Previous, [&](const NamedDecl *ND) { + if (ND == OldDecl) + return false; + + if (const auto *FD = dyn_cast(ND)) + if (const auto *Ovl = + FD->getMostRecentDecl()->getAttr()) + return Ovl->isTransparent(); + return false; + }); + + if (Transparent == Previous.end()) + return; + + const NamedDecl *Prev = (*Transparent)->getMostRecentDecl(); + const NamedDecl *ComplainAt = + findDeclWithOverloadableAttr({Prev}, /*SpelledTransparent=*/true); + S.Diag(NewOvl->getLocation(), + diag::err_attribute_overloadable_too_many_transparent_overloads); + S.Diag(ComplainAt->getLocation(), + diag::note_attribute_overloadable_prev_overload) + << true; +} + /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -9043,6 +9182,10 @@ // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. + // + // Note that we need to preserve the invariant in non-C++ that, if a previous + // declaration or overload of this function has an OverloadableAttr, this + // declaration has one as well. if (!Previous.empty()) { // Determine whether NewFD is an overload of PrevDecl or // a declaration that requires merging. If it's an overload, @@ -9056,58 +9199,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; } + // Consistent transparency is checked later. if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { - // 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()) + IsTransparentOverload = OldOvl->isTransparent(); + + llvm::PointerUnion 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()) { - if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { - 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()) { + // 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()) { + OldDecl = NewestRedecl; + fixMissingOverloadableAttr( + *this, NewFD, /*Redeclaration=*/true, + /*IsTransparentOverload=*/OldOvl->isTransparent(), + {NewestRedecl}); } - if (IsOverload(NewFD, cast(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(ND); })); + + bool FoundOverloadableAttr = false; + if (!getLangOpts().CPlusPlus) { + for (const NamedDecl *InitialND : Previous) { + const auto *ND = cast(InitialND->getMostRecentDecl()); + const auto *OldOvl = ND->getAttr(); + if (!OldOvl) + continue; + + FoundOverloadableAttr = true; + if (!NewFD->hasAttr()) { + 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; } } @@ -9157,6 +9340,9 @@ return Redeclaration; } + if (!getLangOpts().CPlusPlus) + checkPotentialNewTransparentOverload(*this, NewFD, OldDecl, Previous); + Previous.clear(); Previous.addDecl(OldDecl); @@ -9196,7 +9382,9 @@ NewFD->setAccess(OldDecl->getAccess()); } } - } + } else if (!getLangOpts().CPlusPlus) + checkPotentialNewTransparentOverload(*this, NewFD, /*OldDecl=*/nullptr, + Previous); // Semantic checking for this function declaration (in isolation). Index: test/CodeGen/mangle-ms.c =================================================================== --- test/CodeGen/mangle-ms.c +++ test/CodeGen/mangle-ms.c @@ -2,3 +2,10 @@ // 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)) {} + +__attribute__((overloadable)) void g(void (*x)(int)); +// CHECK: define void @g +__attribute__((transparently_overloadable)) void g(void (*x)(int)) {} Index: test/CodeGen/mangle.c =================================================================== --- test/CodeGen/mangle.c +++ test/CodeGen/mangle.c @@ -9,6 +9,14 @@ // CHECK: @_Z2f0l void __attribute__((__overloadable__)) f0(long b) {} +// Unless it's transparent. +// CHECK: @f0 +void __attribute__((__transparently_overloadable__)) f0(float b) {} + +void __attribute__((__overloadable__)) f1(float b); +// CHECK: @f1 +void __attribute__((__transparently_overloadable__)) f1(float b) {} + // CHECK: @bar // These should get merged. 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 __attribute__((transparently_overloadable)) overloaded_fn2() {} +// CHECK-DAG: @overloaded_fn2 +// +extern "C" void __attribute__((overloadable)) overloaded_fn3(); +extern "C" void __attribute__((transparently_overloadable)) overloaded_fn3() {} +// CHECK-DAG: @overloaded_fn3 + namespace UnnamedType { struct S { typedef struct {} *T1[1]; 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 ''}} expected-note@105{{candidate function}} expected-note@106{{candidate function}} - void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible 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 ''}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}} + void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible 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 ''}} 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 ''}} 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 ''}} 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 ''}} 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,91 @@ 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-warning{{mismatched transparency}} expected-note{{previous transparent overload}} + void to_foo5(int) __attribute__((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-warning{{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}} + + void to_foo13(char *) __attribute__((overloadable)); // expected-note{{previous overload}} + void to_foo13(char *) __attribute__((transparently_overloadable)); // expected-warning{{mismatched transparency}} expected-note 3{{previous transparent overload}} + void to_foo13(char *) __attribute__((overloadable)); // expected-error{{mismatched transparency}} + void to_foo13(char *) __attribute__((overloadable)); // expected-error{{mismatched transparency}} + void to_foo13(int) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}} + + void to_foo14(char *) __attribute__((overloadable)); // expected-note{{previous overload}} + void to_foo14(int) __attribute__((transparently_overloadable)); // expected-note{{previous transparent overload}} + void to_foo14(char *) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}} expected-warning{{mismatched transparency}} + void to_foo14(int) __attribute__((transparently_overloadable)); + // Since we emit an error about the transparently_overloadable void(char *) + // overload above, it's reasonable to be quiet here. + void to_foo14(char *) __attribute__((transparently_overloadable)); + + void to_foo15(char *) __attribute__((overloadable)); // expected-note{{previous overload}} + void to_foo15(int) __attribute__((overloadable)); // expected-note{{previous overload}} + void to_foo15(char *) __attribute__((transparently_overloadable)); // expected-warning{{mismatched transparency}} expected-note{{previous transparent}} + void to_foo15(int) __attribute__((transparently_overloadable)); // expected-error{{only one 'overloadable' overload may be transparent}} expected-warning{{mismatched transparency}} + void to_foo15(char *) __attribute__((transparently_overloadable)); // expected-note{{previous transparent}} + void to_foo15(char *) __attribute__((overloadable)); // expected-error{{mismatched transparency}} + void to_foo15(char *) __attribute__((transparently_overloadable)); + } // Bug: we used to treat `__typeof__(foo)` as though it was `__typeof__(&foo)`