aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td9
-rw-r--r--lib/Sema/SemaOverload.cpp32
-rw-r--r--test/SemaCXX/overload-call.cpp6
-rw-r--r--test/SemaObjCXX/objc-pointer-conv.mm8
-rw-r--r--www/compatibility.html5
5 files changed, 58 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9771245fd6..dce5929f39 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1203,6 +1203,15 @@ def note_ovl_candidate_bad_cvr : Note<"candidate "
"%select{const|volatile|const and volatile|restrict|const and restrict|"
"volatile and restrict|const, volatile, and restrict}3 qualifier"
"%select{||s||s|s|s}3">;
+def note_ovl_candidate_bad_base_to_derived_ptr_conv : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)}0%1"
+ " not viable: cannot convert from base class pointer %2 to derived class "
+ "pointer %3 for %ordinal4 argument">;
+
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion of %0 to %1">;
def note_ovl_builtin_binary_candidate : Note<
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4f841b0651..6335cc1fcb 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -5485,6 +5485,38 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ // Diagnose base -> derived pointer conversions.
+ bool IsBaseToDerivedConversion = false;
+ if (const PointerType *FromPtrTy = FromTy->getAs<PointerType>()) {
+ if (const PointerType *ToPtrTy = ToTy->getAs<PointerType>()) {
+ if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
+ FromPtrTy->getPointeeType()) &&
+ !FromPtrTy->getPointeeType()->isIncompleteType() &&
+ !ToPtrTy->getPointeeType()->isIncompleteType() &&
+ S.IsDerivedFrom(ToPtrTy->getPointeeType(),
+ FromPtrTy->getPointeeType()))
+ IsBaseToDerivedConversion = true;
+ }
+ } else if (const ObjCObjectPointerType *FromPtrTy
+ = FromTy->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *ToPtrTy
+ = ToTy->getAs<ObjCObjectPointerType>())
+ if (const ObjCInterfaceDecl *FromIface = FromPtrTy->getInterfaceDecl())
+ if (const ObjCInterfaceDecl *ToIface = ToPtrTy->getInterfaceDecl())
+ if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
+ FromPtrTy->getPointeeType()) &&
+ FromIface->isSuperClassOf(ToIface))
+ IsBaseToDerivedConversion = true;
+ }
+ if (IsBaseToDerivedConversion) {
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_bad_base_to_derived_ptr_conv)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << I+1;
+ return;
+ }
+
// TODO: specialize more based on the kind of mismatch
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
<< (unsigned) FnKind << FnDesc
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 37974ef929..8d12c9bd41 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -219,6 +219,12 @@ void test_derived(B* b, B const* bc, C* c, const C* cc, void* v, D* d) {
char* d8 = derived3(d);
}
+void derived4(C*); // expected-note{{candidate function not viable: cannot convert from base class pointer 'A *' to derived class pointer 'C *' for 1st argument}}
+
+void test_base(A* a) {
+ derived4(a); // expected-error{{no matching function for call to 'derived4}}
+}
+
// Test overloading of references.
// (FIXME: tests binding to determine candidate sets, not overload
// resolution per se).
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index cc3264fcc4..d392ad48de 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -36,3 +36,11 @@ void foo(const I *p, I* sel) {
Func(p); // expected-error {{no matching function for call to 'Func'}}
}
+@interface DerivedFromI : I
+@end
+
+void accept_derived(DerivedFromI*); // expected-note{{candidate function not viable: cannot convert from base class pointer 'I *' to derived class pointer 'DerivedFromI *' for 1st argument}}
+
+void test_base_to_derived(I* i) {
+ accept_derived(i); // expected-error{{no matching function for call to 'accept_derived'}}
+}
diff --git a/www/compatibility.html b/www/compatibility.html
index 11f9f659a2..85133fbca2 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -590,8 +590,9 @@ void g(Base *base) {
downcast.mm:6:3: error: no matching function for call to 'f'
f(base);
^
-downcast.mm:4:6: note: candidate function not viable: no known conversion from
- 'Base *' to 'Derived *' for 1st argument
+downcast.mm:4:6: note: candidate function not viable: cannot convert from base
+ class pointer 'Base *' to derived class pointer 'Derived *' for 1st
+ argument
void f(Derived *);
^
</pre>