Consider:

template<typename T> T declval();

int& r1 = declval<int&&>();
int&& r2 = declval<int&>();
int& r3 = declval<const int&>();


This produces three quite different errors:


refs.cc:3:25: error: invalid initialization of non-const reference of type 
'int&' from an rvalue of type 'int'
int& r1 = declval<int&&>();
          ~~~~~~~~~~~~~~^~
refs.cc:4:25: error: cannot bind 'int' lvalue to 'int&&'
int&& r2 = declval<int&>();
           ~~~~~~~~~~~~~^~
refs.cc:5:30: error: binding 'const int' to reference of type 'int&' discards 
qualifiers
int& r3 = declval<const int&>();
          ~~~~~~~~~~~~~~~~~~~^~


The first one uses the order to/from, but the other two are from/to.

The first and second are saying the same thing (wrong value category)
but very differently.

The first and third mention references but the second doesn't.

The standard talks about binding a reference to something, but the
second and third diagnostics talk about binding something to a
reference (and the first doesn't mention binding at all).

The first diagnostic is specific to lvalue references (it wouldn't be
invalid if it was binding a non-const _rvalue_ reference to an
rvalue), but doesn't use the word "lvalue".

(FWIW Clang and EDG both have their own inconsistencies for the same
example, but that shouldn't stop us trying to improve.)


IMHO the first should use the words "bind" and "lvalue reference":

refs.cc:3:25: error: cannot bind non-const lvalue reference of type 'int&' to 
an rvalue of type 'int'
int& r1 = declval<int&&>();
          ~~~~~~~~~~~~~~^~

The second should use the phrasing "bind ref to value" instead of
"bind value to ref", and mention "rvalue reference":

refs.cc:4:25: error: cannot bind rvalue reference of type 'int&&' to an lvalue 
of type 'int'
int&& r2 = declval<int&>();
           ~~~~~~~~~~~~~^~

The third should use the same phrasing (but doesn't need to mention
lvalue/rvalue because the problem is related to cv-qualifiers not
value categories):

refs.cc:5:30: error: binding reference of type 'int&' to 'const int' discards 
qualifiers
int& r3 = declval<const int&>();
          ~~~~~~~~~~~~~~~~~~~^~


I've only considered trivial examples here, is there some reason to
prefer to current diagnostics for more complex cases?

The attached patch makes that change, but there are probably lots of
tests that would need updating which I haven't done until I know if
the change is worthwhile.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 802c325..918661a 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6710,15 +6710,15 @@ convert_like_real (conversion *convs, tree expr, tree 
fn, int argnum,
            tree extype = TREE_TYPE (expr);
            if (TYPE_REF_IS_RVALUE (ref_type)
                && lvalue_p (expr))
-             error_at (loc, "cannot bind %qT lvalue to %qT",
-                       extype, totype);
+             error_at (loc, "cannot bind rvalue reference of type %qT to "
+                        "lvalue of type %qT", totype, extype);
            else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
                     && !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
-             error_at (loc, "invalid initialization of non-const reference of "
-                       "type %qT from an rvalue of type %qT", totype, extype);
+             error_at (loc, "cannot bind non-const lvalue reference of "
+                       "type %qT to an rvalue of type %qT", totype, extype);
            else if (!reference_compatible_p (TREE_TYPE (totype), extype))
-             error_at (loc, "binding %qT to reference of type %qT "
-                       "discards qualifiers", extype, totype);
+             error_at (loc, "binding reference of type %qT to %qT "
+                       "discards qualifiers", totype, extype);
            else
              gcc_unreachable ();
            maybe_print_user_conv_context (convs);

Reply via email to