diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 3b439594bb00181f2b4cf3b668a21c9d37ada26b..804a33431cb97029ef97a93f9fa95d04a0547c61 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -470,10 +470,11 @@ semantics: * A conversion from type ``T`` to a value of type ``U`` is permitted if ``T`` and ``U`` are compatible types. This conversion is given "conversion" rank. -* A conversion from a pointer of type ``T*`` to a pointer of type ``U*``, where - ``T`` and ``U`` are incompatible, is allowed, but is ranked below all other - types of conversions. Please note: ``U`` lacking qualifiers that are present - on ``T`` is sufficient for ``T`` and ``U`` to be incompatible. +* If no viable candidates are otherwise available, we allow a conversion from a + pointer of type ``T*`` to a pointer of type ``U*``, where ``T`` and ``U`` are + incompatible. This conversion is ranked below all other types of conversions. + Please note: ``U`` lacking qualifiers that are present on ``T`` is sufficient + for ``T`` and ``U`` to be incompatible. The declaration of ``overloadable`` functions is restricted to function declarations and definitions. Most importantly, if any function with a given diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 183fdf4272edad9daaae5ff508d3b6637b3d330f..10aa997745951dd2e7e7479e0a904c3763e305cc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -8600,13 +8600,40 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument) StartArg = 1; + auto IsIllFormedConversion = [&](const ImplicitConversionSequence &ICS) { + // We don't allow incompatible pointer conversions in C++. + if (!S.getLangOpts().CPlusPlus) + return ICS.isStandard() && + ICS.Standard.Second == ICK_Incompatible_Pointer_Conversion; + + // The only ill-formed conversion we allow in C++ is the string literal to + // char* conversion, which is only considered ill-formed after C++11. + return S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings && + hasDeprecatedStringLiteralToCharPtrConversion(ICS); + }; + + // Define functions that don't require ill-formed conversions for a given + // argument to be better candidates than functions that do. + unsigned NumArgs = Cand1.NumConversions; + assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch"); + bool HasBetterConversion = false; + for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { + bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]); + bool Cand2Bad = IsIllFormedConversion(Cand2.Conversions[ArgIdx]); + if (Cand1Bad != Cand2Bad) { + if (Cand1Bad) + return false; + HasBetterConversion = true; + } + } + + if (HasBetterConversion) + return true; + // C++ [over.match.best]p1: // A viable function F1 is defined to be a better function than another // viable function F2 if for all arguments i, ICSi(F1) is not a worse // conversion sequence than ICSi(F2), and then... - unsigned NumArgs = Cand1.NumConversions; - assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch"); - bool HasBetterConversion = false; for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { switch (CompareImplicitConversionSequences(S, Loc, Cand1.Conversions[ArgIdx], diff --git a/test/CodeGen/overloadable.c b/test/CodeGen/overloadable.c index d9769c21f11a5b64e10105b970cc56de1d9e146d..2ec6fe445e7a66cbd5c422b14fd09d5adda5df49 100644 --- a/test/CodeGen/overloadable.c +++ b/test/CodeGen/overloadable.c @@ -74,3 +74,23 @@ void bar() { // CHECK: call void @_Z7ovl_barPc ovl_bar(ucharbuf); } + +// CHECK-LABEL: define void @baz +void ovl_baz(int *, int) __attribute__((overloadable)); +void ovl_baz(unsigned int *, unsigned int) __attribute__((overloadable)); +void ovl_baz2(int, int *) __attribute__((overloadable)); +void ovl_baz2(unsigned int, unsigned int *) __attribute__((overloadable)); +void baz() { + unsigned int j; + // Initial rules for incompatible pointer conversions made this overload + // ambiguous. + // CHECK: call void @_Z7ovl_bazPjj + ovl_baz(&j, 0); + // CHECK: call void @_Z7ovl_bazPjj + ovl_baz(&j, 0u); + + // CHECK: call void @_Z8ovl_baz2jPj + ovl_baz2(0, &j); + // CHECK: call void @_Z8ovl_baz2jPj + ovl_baz2(0u, &j); +} diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index 7eaf98b601c181ef1ac4a8de5bc12d05b082be26..3a01bf24b31afd78f325d8deea881076313bdb4b 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -647,3 +647,14 @@ namespace PR20218 { g(y); // expected-error {{ambiguous}} } } + +namespace StringLiteralToCharAmbiguity { + void f(char *, int); + void f(const char *, unsigned); + void g() { f("foo", 0); } +#if __cplusplus <= 199711L + // expected-error@-2 {{call to 'f' is ambiguous}} + // expected-note@-5 {{candidate function}} + // expected-note@-5 {{candidate function}} +#endif +}