Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3189,7 +3189,12 @@ "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 " "not viable: cannot convert argument of incomplete type " - "%diff{$ to $|to parameter type}2,3">; + "%diff{$ to $|to parameter type}2,3 for " + "%select{%ordinal5 argument|object argument}4" + "%select{|; dereference the argument with *|" + "; take the address of the argument with &|" + "; remove *|" + "; remove &}6">; def note_ovl_candidate_bad_list_argument : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -9104,10 +9104,13 @@ if (const PointerType *PTy = TempFromTy->getAs()) TempFromTy = PTy->getPointeeType(); if (TempFromTy->isIncompleteType()) { + // Emit the generic diagnostic and, optionally, add the hints to it. S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + << FromTy << ToTy << (unsigned) isObjectArgument << I+1 + << (unsigned) (Cand->Fix.Kind); + MaybeEmitInheritedConstructorNote(S, Fn); return; } Index: test/Parser/cxx-reference.cpp =================================================================== --- test/Parser/cxx-reference.cpp +++ test/Parser/cxx-reference.cpp @@ -24,3 +24,29 @@ #if __cplusplus <= 199711L // expected-warning@-2 {{rvalue references are a C++11 extension}} #endif + +namespace PointerVsReferenceSuggestion{ + class A; + + void f0(A *a); // expected-note {{candidate function not viable: cannot convert argument of incomplete type 'PointerVsReferenceSuggestion::A' to 'PointerVsReferenceSuggestion::A *' for 1st argument; take the address of the argument with &}} + void f1(A &a) { + f0(a); // expected-error {{no matching function for call to 'f0'}} + } + + void f2(A &a); // expected-note {{candidate function not viable: cannot convert argument of incomplete type 'PointerVsReferenceSuggestion::A *' to 'PointerVsReferenceSuggestion::A &' for 1st argument; dereference the argument with *}} + void f3(A *a) { + f2(a); // expected-error {{no matching function for call to 'f2'}} + } + + class B {}; + + void f4(B *b); // expected-note {{candidate function not viable: no known conversion from 'PointerVsReferenceSuggestion::B' to 'PointerVsReferenceSuggestion::B *' for 1st argument; take the address of the argument with &}} + void f5(B &b) { + f4(b); // expected-error {{no matching function for call to 'f4'}} + } + + void f6(B &b); // expected-note {{candidate function not viable: no known conversion from 'PointerVsReferenceSuggestion::B *' to 'PointerVsReferenceSuggestion::B &' for 1st argument; dereference the argument with *}} + void f7(B *b) { + f6(b); // expected-error {{no matching function for call to 'f6'}} + } +}