diff mbox series

c++: Fix wrong no post-decrement operator error in template [PR94190]

Message ID 20200316145739.2476758-1-polacek@redhat.com
State New
Headers show
Series c++: Fix wrong no post-decrement operator error in template [PR94190] | expand

Commit Message

Li, Pan2 via Gcc-patches March 16, 2020, 2:57 p.m. UTC
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.  Thus, use non_reference, which is
used in the function when looking for the best conversion candidate.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

	PR c++/94190 - wrong no post-decrement operator error in template.
	* cvt.c (build_expr_type_conversion): Use non_reference.

	* g++.dg/conversion/op7.C: New test.
---
 gcc/cp/cvt.c                          |  2 +-
 gcc/testsuite/g++.dg/conversion/op7.C | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/op7.C


base-commit: 5a3c42b227bbe9e7acb5335088d2255262311bd8

Comments

Li, Pan2 via Gcc-patches March 16, 2020, 9:12 p.m. UTC | #1
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.

Jason
Li, Pan2 via Gcc-patches March 17, 2020, 2:01 a.m. UTC | #2
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.

	* g++.dg/conversion/op7.C: New test.
---
 gcc/cp/call.c                         |  3 +++
 gcc/testsuite/g++.dg/conversion/op7.C | 22 ++++++++++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/conversion/op7.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1715acc0ec3..d8b28573b95 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6426,6 +6426,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
 	    {
 	      conv = strip_standard_conversion (conv);
 	      arg1 = convert_like (conv, arg1, complain);
+	      arg1 = convert_from_reference (arg1);
 	    }
 
 	  if (arg2)
@@ -6435,6 +6436,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
 		{
 		  conv = strip_standard_conversion (conv);
 		  arg2 = convert_like (conv, arg2, complain);
+		  arg2 = convert_from_reference (arg2);
 		}
 	    }
 
@@ -6445,6 +6447,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
 		{
 		  conv = strip_standard_conversion (conv);
 		  arg3 = convert_like (conv, arg3, complain);
+		  arg3 = convert_from_reference (arg3);
 		}
 	    }
 	}
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: 2691ffe6dbaffb704593dd6220178c28848b3855
Li, Pan2 via Gcc-patches March 17, 2020, 8:05 p.m. UTC | #3
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.

> 	* g++.dg/conversion/op7.C: New test.
> ---
>   gcc/cp/call.c                         |  3 +++
>   gcc/testsuite/g++.dg/conversion/op7.C | 22 ++++++++++++++++++++++
>   2 files changed, 25 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/conversion/op7.C
> 
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 1715acc0ec3..d8b28573b95 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -6426,6 +6426,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
>   	    {
>   	      conv = strip_standard_conversion (conv);
>   	      arg1 = convert_like (conv, arg1, complain);
> +	      arg1 = convert_from_reference (arg1);
>   	    }
>   
>   	  if (arg2)
> @@ -6435,6 +6436,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
>   		{
>   		  conv = strip_standard_conversion (conv);
>   		  arg2 = convert_like (conv, arg2, complain);
> +		  arg2 = convert_from_reference (arg2);
>   		}
>   	    }
>   
> @@ -6445,6 +6447,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
>   		{
>   		  conv = strip_standard_conversion (conv);
>   		  arg3 = convert_like (conv, arg3, complain);
> +		  arg3 = convert_from_reference (arg3);
>   		}
>   	    }
>   	}
> 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: 2691ffe6dbaffb704593dd6220178c28848b3855
>
Li, Pan2 via Gcc-patches March 23, 2020, 3:06 p.m. UTC | #4
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
Li, Pan2 via Gcc-patches March 24, 2020, 10:31 p.m. UTC | #5
On 3/23/20 11:06 AM, Marek Polacek wrote:
> 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?

OK.

> -- >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
>
diff mbox series

Patch

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 22a72c08c45..0c285ed4fe9 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1732,7 +1732,7 @@  build_type_conversion (tree xtype, tree expr)
 tree
 build_expr_type_conversion (int desires, tree expr, bool complain)
 {
-  tree basetype = TREE_TYPE (expr);
+  tree basetype = non_reference (TREE_TYPE (expr));
   tree conv = NULL_TREE;
   tree winner = NULL_TREE;
 
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> ();
+}