From 9ea8f7e6c53fa6b6fbfab811578ec0e16153707f Mon Sep 17 00:00:00 2001
From: Kaelyn Uhrain <rikka@google.com>
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<int x> 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.

llvm-svn: 158691
---
 .../clang/Basic/DiagnosticSemaKinds.td        | 11 ++++++++
 clang/lib/Sema/SemaOverload.cpp               | 25 +++++++++++++++----
 .../dcl.init.ref/p5-cxx03-extra-copy.cpp      |  2 +-
 clang/test/Misc/integer-literal-printing.cpp  |  4 +--
 .../test/SemaCXX/user-defined-conversions.cpp |  2 +-
 5 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a07f00697b81..638122101525 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f73c5c1f35d5..6e62af5bfe40 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/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<ReferenceType>()) {
-      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/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
index d58a12953e0d..4ba75efebbb3 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
+++ b/clang/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/clang/test/Misc/integer-literal-printing.cpp b/clang/test/Misc/integer-literal-printing.cpp
index d751730d95f6..4085d606d2ad 100644
--- a/clang/test/Misc/integer-literal-printing.cpp
+++ b/clang/test/Misc/integer-literal-printing.cpp
@@ -2,10 +2,10 @@
 
 // PR11179
 template <short T> class Type1 {};
-template <short T> void Function1(Type1<T>& x) {} // expected-note{{candidate function [with T = -42] not viable: no known conversion from 'Type1<-42>' to 'Type1<-42> &' for 1st argument;}}
+template <short T> void Function1(Type1<T>& x) {} // expected-note{{candidate function [with T = -42] not viable: expects an l-value for 1st argument}}
 
 template <unsigned short T> class Type2 {};
-template <unsigned short T> void Function2(Type2<T>& x) {} // expected-note{{candidate function [with T = 42] not viable: no known conversion from 'Type2<42>' to 'Type2<42> &' for 1st argument;}}
+template <unsigned short T> void Function2(Type2<T>& 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/clang/test/SemaCXX/user-defined-conversions.cpp b/clang/test/SemaCXX/user-defined-conversions.cpp
index 43ec5a3d4ab9..284a31069288 100644
--- a/clang/test/SemaCXX/user-defined-conversions.cpp
+++ b/clang/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 {
-- 
GitLab