diff options
-rw-r--r-- | clang/include/clang/Basic/AttrDocs.td | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 33 | ||||
-rw-r--r-- | clang/test/CodeGen/overloadable.c | 20 | ||||
-rw-r--r-- | clang/test/SemaCXX/overload-call.cpp | 11 |
4 files changed, 66 insertions, 7 deletions
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 3b439594bb0..804a33431cb 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 183fdf4272e..10aa9977459 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/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/clang/test/CodeGen/overloadable.c b/clang/test/CodeGen/overloadable.c index d9769c21f11..2ec6fe445e7 100644 --- a/clang/test/CodeGen/overloadable.c +++ b/clang/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/clang/test/SemaCXX/overload-call.cpp b/clang/test/SemaCXX/overload-call.cpp index 7eaf98b601c..3a01bf24b31 100644 --- a/clang/test/SemaCXX/overload-call.cpp +++ b/clang/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 +} |