Commit 315b87f6 by Marek Polacek

c++: Make convert_like complain about bad ck_ref_bind again [PR95789]

convert_like issues errors about bad_p conversions at the beginning
of the function, but in the ck_ref_bind case, it only issues them
after we've called convert_like on the next conversion.

This doesn't work as expected since r10-7096 because when we see
a conversion from/to class type in a template, we return early, thereby
missing the error, and a bad_p conversion goes by undetected.  That
made the attached test to compile even though it should not.

I had thought that I could just move the ck_ref_bind/bad_p errors
above to the rest of them, but that regressed diagnostics because
expr then wasn't converted yet by the nested convert_like_real call.

So, for bad_p conversions, do the normal processing, but still return
the IMPLICIT_CONV_EXPR to avoid introducing trees that the template
processing can't handle well.  This I achieved by adding a wrapper
function.

gcc/cp/ChangeLog:

	PR c++/95789
	PR c++/96104
	PR c++/96179
	* call.c (convert_like_real_1): Renamed from convert_like_real.
	(convert_like_real): New wrapper for convert_like_real_1.

gcc/testsuite/ChangeLog:

	PR c++/95789
	PR c++/96104
	PR c++/96179
	* g++.dg/conversion/ref4.C: New test.
	* g++.dg/conversion/ref5.C: New test.
	* g++.dg/conversion/ref6.C: New test.

(cherry picked from commit 8e64d182850560dbedfabb88aac90d4fc6155067)
parent a1c022d1
......@@ -171,6 +171,8 @@ static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
/*c_cast_p=*/false, (COMPLAIN))
static tree convert_like_real (conversion *, tree, tree, int, bool,
bool, tsubst_flags_t);
static tree convert_like_real_1 (conversion *, tree, tree, int, bool,
bool, tsubst_flags_t);
static void op_error (const op_location_t &, enum tree_code, enum tree_code,
tree, tree, tree, bool);
static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
......@@ -7283,6 +7285,39 @@ maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
"are only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
}
/* Wrapper for convert_like_real_1 that handles creating IMPLICIT_CONV_EXPR. */
static tree
convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
bool issue_conversion_warnings,
bool c_cast_p, tsubst_flags_t complain)
{
/* Creating &TARGET_EXPR<> in a template breaks when substituting,
and creating a CALL_EXPR in a template breaks in finish_call_expr
so use an IMPLICIT_CONV_EXPR for this conversion. We would have
created such codes e.g. when calling a user-defined conversion
function. */
tree conv_expr = NULL_TREE;
if (processing_template_decl
&& convs->kind != ck_identity
&& (CLASS_TYPE_P (convs->type) || CLASS_TYPE_P (TREE_TYPE (expr))))
{
conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr);
if (convs->kind != ck_ref_bind)
conv_expr = convert_from_reference (conv_expr);
if (!convs->bad_p)
return conv_expr;
/* Do the normal processing to give the bad_p errors. But we still
need to return the IMPLICIT_CONV_EXPR, unless we're returning
error_mark_node. */
}
expr = convert_like_real_1 (convs, expr, fn, argnum,
issue_conversion_warnings, c_cast_p, complain);
if (expr == error_mark_node)
return error_mark_node;
return conv_expr ? conv_expr : expr;
}
/* Perform the conversions in CONVS on the expression EXPR. FN and
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when
......@@ -7294,7 +7329,7 @@ maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
conversions to inaccessible bases are permitted. */
static tree
convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
convert_like_real_1 (conversion *convs, tree expr, tree fn, int argnum,
bool issue_conversion_warnings,
bool c_cast_p, tsubst_flags_t complain)
{
......@@ -7397,19 +7432,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (issue_conversion_warnings && (complain & tf_warning))
conversion_null_warnings (totype, expr, fn, argnum);
/* Creating &TARGET_EXPR<> in a template breaks when substituting,
and creating a CALL_EXPR in a template breaks in finish_call_expr
so use an IMPLICIT_CONV_EXPR for this conversion. We would have
created such codes e.g. when calling a user-defined conversion
function. */
if (processing_template_decl
&& convs->kind != ck_identity
&& (CLASS_TYPE_P (totype) || CLASS_TYPE_P (TREE_TYPE (expr))))
{
expr = build1 (IMPLICIT_CONV_EXPR, totype, expr);
return convs->kind == ck_ref_bind ? expr : convert_from_reference (expr);
}
switch (convs->kind)
{
case ck_user:
......
// PR c++/95789
// { dg-do compile { target c++11 } }
struct B {
int n;
};
template <typename T>
struct A {
B& get() const { return f; } // { dg-error "binding reference" }
B f;
};
int main() {
A<int> a;
a.f = {};
a.get().n = 10;
if (a.f.n != 0)
__builtin_abort();
}
// PR c++/96104
template <typename T> void fn(T &);
class E {};
struct F {
template <typename T> void mfn(T t) { t, fn(E()); } // { dg-error "cannot bind non-const lvalue reference" }
};
int
main()
{
E e;
F f;
f.mfn(e);
}
// PR c++/96179
// { dg-do compile { target c++11 } }
template<typename T> struct vector
{
void push_back(T) { }
};
struct dummy{
int a;
};
void Modify_Dummy(dummy &d){
d.a=1;
}
template <bool bla=true> void Templated_Function(){
vector<dummy> A;
A.push_back(Modify_Dummy(dummy{0})); // { dg-error "cannot bind non-const lvalue reference" }
}
int main(){
Templated_Function();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment