I've also added another test.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
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.
gcc/cp/ChangeLog:
PR c++/95789
* call.c (convert_like_real): Do the normal processing for
conversion that are bad_p. Return the IMPLICIT_CONV_EXPR
instead of EXPR if we're processing a bad_p conversion in
a template.
gcc/testsuite/ChangeLog:
PR c++/95789
* g++.dg/conversion/ref4.C: New test.
* g++.dg/conversion/ref5.C: New test.
---
gcc/cp/call.c | 47 +++++++++++++++-----------
gcc/testsuite/g++.dg/conversion/ref4.C | 22 ++++++++++++
gcc/testsuite/g++.dg/conversion/ref5.C | 14 ++++++++
3 files changed, 64 insertions(+), 19 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/conversion/ref4.C
create mode 100644 gcc/testsuite/g++.dg/conversion/ref5.C
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 5341a572980..65565fc90a8 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7400,12 +7400,19 @@ convert_like_real (conversion *convs, tree expr, tree
fn, int argnum,
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 (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);
+ conv_expr = build1 (IMPLICIT_CONV_EXPR, totype, 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. */
}
switch (convs->kind)
@@ -7465,7 +7472,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
TARGET_EXPR_LIST_INIT_P (expr) = true;
TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
}
- return expr;
+ return conv_expr ? conv_expr : expr;
}
/* We don't know here whether EXPR is being used as an lvalue or
@@ -7488,7 +7495,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
TARGET_EXPR_LIST_INIT_P (expr) = true;
}
- return expr;
+ return conv_expr ? conv_expr : expr;
}
case ck_identity:
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
@@ -7513,7 +7520,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
continue to warn about uses of EXPR as an integer, rather than as a
pointer. */
expr = build_int_cst (totype, 0);
- return expr;
+ return conv_expr ? conv_expr : expr;
case ck_ambig:
/* We leave bad_p off ck_ambig because overload resolution considers
it valid, it just fails when we try to perform it. So we need to
@@ -7585,7 +7592,8 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
field = next_initializable_field (DECL_CHAIN (field));
CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
tree new_ctor = build_constructor (totype, vec);
- return get_target_expr_sfinae (new_ctor, complain);
+ return (conv_expr ? conv_expr
+ : get_target_expr_sfinae (new_ctor, complain));
}
case ck_aggr:
@@ -7598,14 +7606,14 @@ convert_like_real (conversion *convs, tree expr, tree
fn, int argnum,
imag = perform_implicit_conversion (TREE_TYPE (totype),
imag, complain);
expr = build2 (COMPLEX_EXPR, totype, real, imag);
- return expr;
+ return conv_expr ? conv_expr : expr;
}
expr = reshape_init (totype, expr, complain);
expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
complain);
if (expr != error_mark_node)
TARGET_EXPR_LIST_INIT_P (expr) = true;
- return expr;
+ return conv_expr ? conv_expr : expr;
default:
break;
@@ -7634,19 +7642,19 @@ convert_like_real (conversion *convs, tree expr, tree
fn, int argnum,
}
if (! MAYBE_CLASS_TYPE_P (totype))
- return expr;
+ return conv_expr ? conv_expr : expr;
/* Don't introduce copies when passing arguments along to the inherited
constructor. */
if (current_function_decl
&& flag_new_inheriting_ctors
&& DECL_INHERITED_CTOR (current_function_decl))
- return expr;
+ return conv_expr ? conv_expr : expr;
if (TREE_CODE (expr) == TARGET_EXPR
&& TARGET_EXPR_LIST_INIT_P (expr))
/* Copy-list-initialization doesn't actually involve a copy. */
- return expr;
+ return conv_expr ? conv_expr : expr;
/* Fall through. */
case ck_base:
@@ -7657,7 +7665,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
/* Build an expression for `*((base*) &expr)'. */
expr = convert_to_base (expr, totype,
!c_cast_p, /*nonnull=*/true, complain);
- return expr;
+ return conv_expr ? conv_expr : expr;
}
/* Copy-initialization where the cv-unqualified version of the source
@@ -7686,7 +7694,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
}
- return build_cplus_new (totype, expr, complain);
+ return conv_expr ? conv_expr : build_cplus_new (totype, expr, complain);
case ck_ref_bind:
{
@@ -7821,16 +7829,16 @@ convert_like_real (conversion *convs, tree expr, tree
fn, int argnum,
expr = cp_convert (build_pointer_type (TREE_TYPE (ref_type)),
expr, complain);
/* Convert the pointer to the desired reference type. */
- return build_nop (ref_type, expr);
+ return conv_expr ? conv_expr : build_nop (ref_type, expr);
}
case ck_lvalue:
- return decay_conversion (expr, complain);
+ return conv_expr ? conv_expr : decay_conversion (expr, complain);
case ck_fnptr:
/* ??? Should the address of a transaction-safe pointer point to the TM
clone, and this conversion look up the primary function? */
- return build_nop (totype, expr);
+ return conv_expr ? conv_expr : build_nop (totype, expr);
case ck_qual:
/* Warn about deprecated conversion if appropriate. */
@@ -7845,11 +7853,12 @@ convert_like_real (conversion *convs, tree expr, tree
fn, int argnum,
if (convs->base_p)
expr = convert_to_base (expr, totype, !c_cast_p,
/*nonnull=*/false, complain);
- return build_nop (totype, expr);
+ return conv_expr ? conv_expr : build_nop (totype, expr);
case ck_pmem:
- return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
+ expr = convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
c_cast_p, complain);
+ return conv_expr ? conv_expr : expr;
default:
break;
@@ -7866,7 +7875,7 @@ convert_like_real (conversion *convs, tree expr, tree fn,
int argnum,
else
expr = cp_convert (totype, expr, complain);
- return expr;
+ return conv_expr ? conv_expr : expr;
}
/* ARG is being passed to a varargs function. Perform any conversions
diff --git a/gcc/testsuite/g++.dg/conversion/ref4.C
b/gcc/testsuite/g++.dg/conversion/ref4.C
new file mode 100644
index 00000000000..464a4cf6c0f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref4.C
@@ -0,0 +1,22 @@
+// 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();
+}
diff --git a/gcc/testsuite/g++.dg/conversion/ref5.C
b/gcc/testsuite/g++.dg/conversion/ref5.C
new file mode 100644
index 00000000000..0042acd0670
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref5.C
@@ -0,0 +1,14 @@
+// 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);
+}
base-commit: 760df6d296b8fc59796f42dca5eb14012fbfa28b