On Tue, Mar 17, 2020 at 04:05:31PM -0400, Jason Merrill wrote: > On 3/16/20 10:01 PM, Marek Polacek wrote: > > On Mon, Mar 16, 2020 at 05:12:15PM -0400, Jason Merrill wrote: > > > On 3/16/20 10:57 AM, Marek Polacek wrote: > > > > Now that convert_like creates an IMPLICIT_CONV_EXPR when it converts > > > > something that involves a class in a template, we must be prepared to > > > > handle it. In this test, we have a class S and we're converting it > > > > to long int& using a user-defined conversion since we're performing > > > > -- on it. So cp_build_unary_op/POSTDECREMENT_EXPR calls > > > > build_expr_type_conversion which gets the IMPLICIT_CONV_EXPR. Before > > > > the convert_like change it got *S::operator long int &(&b) whose type > > > > is long int but now it gets IMPLICIT_CONV_EXPR<long int&>(b) whose type > > > > is a reference type. > > > > > > So you need to make sure that your IMPLICIT_CONV_EXPR gets > > > convert_from_reference'd at some point. > > > > Perhaps like the following? > > > > Bootstrapped/regtested on x86_64-linux, built Boost/cmcstl2. > > > > -- >8 -- > > Now that convert_like creates an IMPLICIT_CONV_EXPR when it converts > > something that involves a class in a template, we must be prepared to > > handle it. In this test, we have a class S and we're converting it > > to long int& using a user-defined conversion since we're performing > > -- on it. So cp_build_unary_op/POSTDECREMENT_EXPR calls > > build_expr_type_conversion which gets the IMPLICIT_CONV_EXPR. Before > > the convert_like change it got *S::operator long int &(&b) whose type > > is long int but now it gets IMPLICIT_CONV_EXPR<long int&>(b) whose type > > is a reference type. But the !MAYBE_CLASS_TYPE_P switch doesn't handle > > reference types and so we complain. > > > > Fixed by calling convert_from_reference on the result of convert_like. > > > > PR c++/94190 - wrong no post-decrement operator error in template. > > * call.c (build_new_op_1): Use convert_from_reference on the result > > of convert_like. > > The result of convert_like should already be dereferenced in this case. I > think convert_like should only return a bare reference for ck_ref_bind, > where we're explicitly requesting one.
I tried to adjust all the appropriate return ...; in convert_like to return convert_from_reference (...); and then remove unnecessary calls to convert_from_reference after a call to convert_like elsewhere in the codebase, but that fails very badly. But it seems we can use convert_from_reference in convert_like when returning the new IMPLICIT_CONV_EXPR, like this: Bootstrapped/regtested on x86_64-linux, ok for trunk? -- >8 -- Now that convert_like creates an IMPLICIT_CONV_EXPR when it converts something that involves a class in a template, we must be prepared to handle it. In this test, we have a class S and we're converting it to long int& using a user-defined conversion since we're performing -- on it. So cp_build_unary_op/POSTDECREMENT_EXPR calls build_expr_type_conversion which gets the IMPLICIT_CONV_EXPR. Before the convert_like change it got *S::operator long int &(&b) whose type is long int but now it gets IMPLICIT_CONV_EXPR<long int&>(b) whose type is a reference type. But the !MAYBE_CLASS_TYPE_P switch doesn't handle reference types and so we complain. Fixed by calling convert_from_reference on the result of convert_like. PR c++/94190 - wrong no post-decrement operator error in template. * call.c (convert_like_real): Use convert_from_reference on the result. * g++.dg/conversion/op7.C: New test. --- gcc/cp/call.c | 5 ++++- gcc/testsuite/g++.dg/conversion/op7.C | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/conversion/op7.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 65a3ea35dee..bae4b2c0f52 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7389,7 +7389,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, if (processing_template_decl && convs->kind != ck_identity && (CLASS_TYPE_P (totype) || CLASS_TYPE_P (TREE_TYPE (expr)))) - return build1 (IMPLICIT_CONV_EXPR, totype, expr); + { + expr = build1 (IMPLICIT_CONV_EXPR, totype, expr); + return convs->kind == ck_ref_bind ? expr : convert_from_reference (expr); + } switch (convs->kind) { diff --git a/gcc/testsuite/g++.dg/conversion/op7.C b/gcc/testsuite/g++.dg/conversion/op7.C new file mode 100644 index 00000000000..c6401d109b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/op7.C @@ -0,0 +1,22 @@ +// PR c++/94190 - wrong no post-decrement operator error in template. + +struct S { operator long & (); } b; + +template<int> void +foo () +{ + b--; + ++b; + --b; + b++; + !b; + ~b; + +b; + -b; +} + +void +bar () +{ + foo<0> (); +} base-commit: a3586eeb88414e77c7cccb69362b8d04562536b6 -- Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA