summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/AttrDocs.td9
-rw-r--r--clang/lib/Sema/SemaOverload.cpp33
-rw-r--r--clang/test/CodeGen/overloadable.c20
-rw-r--r--clang/test/SemaCXX/overload-call.cpp11
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
+}
OpenPOWER on IntegriCloud