From 0d3317e0a2e0adb57ce8d075ebdcb41a3f939805 Mon Sep 17 00:00:00 2001 From: Kaelyn Uhrain Date: Tue, 19 Jun 2012 00:37:47 +0000 Subject: [PATCH] Improve the error message when a function overload candidate is rejected because it expects a reference and receives a non-l-value. For example, given: int foo(int &); template void b() { foo(x); } clang will now print "expects an l-value for 1st argument" instead of "no known conversion from 'int' to 'int &' for 1st argument". The change in wording (and associated code to detect the case) was prompted by comment #5 in PR3104, and should be the last bit of work needed for the bug. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158691 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 11 ++++++++ lib/Sema/SemaOverload.cpp | 25 +++++++++++++++---- .../dcl.init.ref/p5-cxx03-extra-copy.cpp | 2 +- test/Misc/integer-literal-printing.cpp | 4 +-- test/SemaCXX/user-defined-conversions.cpp | 2 +- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a07f00697b..6381221015 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2163,6 +2163,17 @@ def note_ovl_candidate_bad_arc_conv : Note<"candidate " "constructor (inherited)}0%1" " not viable: cannot implicitly convert argument of type %2 to %3 for " "%select{%ordinal5 argument|object argument}4 under ARC">; +def note_ovl_candidate_bad_lvalue : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: expects an l-value for " + "%select{%ordinal3 argument|object argument}2">; def note_ovl_candidate_bad_addrspace : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f73c5c1f35..6e62af5bfe 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -8153,12 +8153,27 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { FromIface->isSuperClassOf(ToIface)) BaseToDerivedConversion = 2; } else if (const ReferenceType *ToRefTy = ToTy->getAs()) { - if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) && - !FromTy->isIncompleteType() && - !ToRefTy->getPointeeType()->isIncompleteType() && - S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) - BaseToDerivedConversion = 3; + if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) && + !FromTy->isIncompleteType() && + !ToRefTy->getPointeeType()->isIncompleteType() && + S.IsDerivedFrom(ToRefTy->getPointeeType(), FromTy)) { + BaseToDerivedConversion = 3; + } else if (ToTy->isLValueReferenceType() && !FromExpr->isLValue() && + ToTy.getNonReferenceType().getCanonicalType() == + FromTy.getNonReferenceType().getCanonicalType()) { + QualType T1 = ToTy.getCanonicalType(); + QualType T2 = ToTy.getNonReferenceType(); + QualType T3 = T2.getUnqualifiedType(); + QualType T4 = FromTy.getCanonicalType(); + (void)T1; (void)T2; (void)T3; (void)T4; + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_lvalue) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << (unsigned) isObjectArgument << I + 1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; } + } if (BaseToDerivedConversion) { S.Diag(Fn->getLocation(), diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp index d58a12953e..4ba75efebb 100644 --- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp @@ -22,7 +22,7 @@ struct X3 { X3(); private: - X3(X3&); // expected-note{{candidate constructor not viable: no known conversion from 'X3' to 'X3 &' for 1st argument}} + X3(X3&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} }; // Check for instantiation of default arguments diff --git a/test/Misc/integer-literal-printing.cpp b/test/Misc/integer-literal-printing.cpp index d751730d95..4085d606d2 100644 --- a/test/Misc/integer-literal-printing.cpp +++ b/test/Misc/integer-literal-printing.cpp @@ -2,10 +2,10 @@ // PR11179 template class Type1 {}; -template void Function1(Type1& x) {} // expected-note{{candidate function [with T = -42] not viable: no known conversion from 'Type1<-42>' to 'Type1<-42> &' for 1st argument;}} +template void Function1(Type1& x) {} // expected-note{{candidate function [with T = -42] not viable: expects an l-value for 1st argument}} template class Type2 {}; -template void Function2(Type2& x) {} // expected-note{{candidate function [with T = 42] not viable: no known conversion from 'Type2<42>' to 'Type2<42> &' for 1st argument;}} +template void Function2(Type2& x) {} // expected-note{{candidate function [with T = 42] not viable: expects an l-value for 1st argument}} void Function() { Function1(Type1<-42>()); // expected-error{{no matching function for call to 'Function1'}} diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp index 43ec5a3d4a..284a310692 100644 --- a/test/SemaCXX/user-defined-conversions.cpp +++ b/test/SemaCXX/user-defined-conversions.cpp @@ -69,7 +69,7 @@ void test_conversion(ConvertibleToBase ctb, ConvertibleToDerived ctd, } struct X1 { - X1(X1&); // expected-note{{candidate constructor not viable: no known conversion from 'X1' to 'X1 &' for 1st argument}} + X1(X1&); // expected-note{{candidate constructor not viable: expects an l-value for 1st argument}} }; struct X2 { -- 2.40.0