diff mbox series

c++: Error recovery with errenous DECL_INITIAL [PR94475]

Message ID 20200415194427.1815190-1-ppalka@redhat.com
State New
Headers show
Series c++: Error recovery with errenous DECL_INITIAL [PR94475] | expand

Commit Message

Patrick Palka April 15, 2020, 7:44 p.m. UTC
Here we're ICE'ing in do_narrow during error-recovery, because ocp_convert
returns error_mark_node after it attempts to reduce a const decl to its
erroneous DECL_INITIAL via scalar_constant_value, and we later pass this
error_mark_node to fold_build2 which isn't prepared to handle error_mark_nodes.

We could fix this ICE in do_narrow by checking if ocp_convert returns
error_mark_node, but for the sake of consistency and for better error recovery
it seems it'd be better if ocp_convert didn't care that a const decl's
initializer is erroneous and would instead proceed as if the decl was not const,
which is the approach that this patch takes.

Passes 'make check-c++', does this look OK to commit after full bootstrap and
regtest?

gcc/cp/ChangeLog:

	PR c++/94475
	* cvt.c (ocp_convert): If the result of scalar_constant_value is
	erroneous, discard it and carry on with the original expression.

gcc/testsuite/ChangeLog:

	PR c++/94475
	* g++.dg/conversion/err-recover2.C: New test.
	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
---
 gcc/cp/cvt.c                                   |  6 +++---
 gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
 gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
 gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
 4 files changed, 15 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C

Comments

Patrick Palka April 15, 2020, 8:43 p.m. UTC | #1
Oops, consider the typo in the subject line fixed.  Also ...

On Wed, 15 Apr 2020, Patrick Palka wrote:

> Here we're ICE'ing in do_narrow during error-recovery, because ocp_convert
> returns error_mark_node after it attempts to reduce a const decl to its
> erroneous DECL_INITIAL via scalar_constant_value, and we later pass this
> error_mark_node to fold_build2 which isn't prepared to handle error_mark_nodes.
> 
> We could fix this ICE in do_narrow by checking if ocp_convert returns
> error_mark_node, but for the sake of consistency and for better error recovery
> it seems it'd be better if ocp_convert didn't care that a const decl's
> initializer is erroneous and would instead proceed as if the decl was not const,
> which is the approach that this patch takes.
> 
> Passes 'make check-c++', does this look OK to commit after full bootstrap and
> regtest?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/94475
> 	* cvt.c (ocp_convert): If the result of scalar_constant_value is
> 	erroneous, discard it and carry on with the original expression.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94475
> 	* g++.dg/conversion/err-recover2.C: New test.
> 	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
> 	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
> ---
>  gcc/cp/cvt.c                                   |  6 +++---
>  gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
>  gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
>  gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
>  4 files changed, 15 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C
> 
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index a3b80968b33..b94231a6d08 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -723,10 +723,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>    if (!CLASS_TYPE_P (type))
>      {
>        e = mark_rvalue_use (e);
> -      e = scalar_constant_value (e);
> +      tree v = scalar_constant_value (e);
> +      if (!error_operand_p (v))
> +	e = v;
>      }
> -  if (error_operand_p (e))
> -    return error_mark_node;

Removing this error_operand_p check might make an error_mark_node slip
through and get processed by the rest of ocp_convert, if the call to
mark_rvalue_use above returns error_mark_node.

In light of that, please consider this patch instead which restores that
error_operand_p check:

-- >8 --

Subject: [PATCH] c++: Error recovery with erroneous DECL_INITIAL [PR94475]

gcc/cp/ChangeLog:

	PR c++/94475
	* cvt.c (ocp_convert): If the result of scalar_constant_value is
	erroneous, ignore it and use the original expression.

gcc/testsuite/ChangeLog:

	PR c++/94475
	* g++.dg/conversion/err-recover2.C: New test.
	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
---
 gcc/cp/cvt.c                                   |  4 +++-
 gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
 gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
 gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
 4 files changed, 15 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index a3b80968b33..656e7fd3ec0 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -723,7 +723,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
   if (!CLASS_TYPE_P (type))
     {
       e = mark_rvalue_use (e);
-      e = scalar_constant_value (e);
+      tree v = scalar_constant_value (e);
+      if (!error_operand_p (v))
+	e = v;
     }
   if (error_operand_p (e))
     return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/conversion/err-recover2.C b/gcc/testsuite/g++.dg/conversion/err-recover2.C
new file mode 100644
index 00000000000..437e1a919ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/err-recover2.C
@@ -0,0 +1,10 @@
+// PR c++/94475
+// { dg-do compile }
+
+unsigned char
+sr ()
+{
+  const unsigned char xz = EI; // { dg-error "not declared" }
+
+  return xz - (xz >> 1);
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr84138.C b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
index 5c48b9b164a..00352306a56 100644
--- a/gcc/testsuite/g++.dg/diagnostic/pr84138.C
+++ b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
@@ -5,4 +5,4 @@ foo()
 {
   const int i = 0 = 0; // { dg-error "lvalue required as left operand" }
   return 1 ? 0 : (char)i;
-} // { dg-warning "control reaches" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
index 237ba84d526..4d2688157fc 100644
--- a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
+++ b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
@@ -5,4 +5,4 @@ bool foo (char c)
 {
   const int i = 0 = 0; // { dg-error "lvalue" }
   return c = i;
-} // { dg-warning "control reaches" }
+}
Jason Merrill April 16, 2020, 12:16 a.m. UTC | #2
On 4/15/20 4:43 PM, Patrick Palka wrote:
> Oops, consider the typo in the subject line fixed.  Also ...
> 
> On Wed, 15 Apr 2020, Patrick Palka wrote:
> 
>> Here we're ICE'ing in do_narrow during error-recovery, because ocp_convert
>> returns error_mark_node after it attempts to reduce a const decl to its
>> erroneous DECL_INITIAL via scalar_constant_value, and we later pass this
>> error_mark_node to fold_build2 which isn't prepared to handle error_mark_nodes.
>>
>> We could fix this ICE in do_narrow by checking if ocp_convert returns
>> error_mark_node, but for the sake of consistency and for better error recovery
>> it seems it'd be better if ocp_convert didn't care that a const decl's
>> initializer is erroneous and would instead proceed as if the decl was not const,
>> which is the approach that this patch takes.
>>
>> Passes 'make check-c++', does this look OK to commit after full bootstrap and
>> regtest?
>>
>> gcc/cp/ChangeLog:
>>
>> 	PR c++/94475
>> 	* cvt.c (ocp_convert): If the result of scalar_constant_value is
>> 	erroneous, discard it and carry on with the original expression.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	PR c++/94475
>> 	* g++.dg/conversion/err-recover2.C: New test.
>> 	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
>> 	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
>> ---
>>   gcc/cp/cvt.c                                   |  6 +++---
>>   gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
>>   gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
>>   gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
>>   4 files changed, 15 insertions(+), 5 deletions(-)
>>   create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C
>>
>> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
>> index a3b80968b33..b94231a6d08 100644
>> --- a/gcc/cp/cvt.c
>> +++ b/gcc/cp/cvt.c
>> @@ -723,10 +723,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>>     if (!CLASS_TYPE_P (type))
>>       {
>>         e = mark_rvalue_use (e);
>> -      e = scalar_constant_value (e);
>> +      tree v = scalar_constant_value (e);
>> +      if (!error_operand_p (v))
>> +	e = v;
>>       }
>> -  if (error_operand_p (e))
>> -    return error_mark_node;
> 
> Removing this error_operand_p check might make an error_mark_node slip
> through and get processed by the rest of ocp_convert, if the call to
> mark_rvalue_use above returns error_mark_node.
> 
> In light of that, please consider this patch instead which restores that
> error_operand_p check:

OK.  I wonder if we want to drop the call to scalar_constant_value 
entirely in GCC 11, and expect that the expression will be folded 
properly later.

> -- >8 --
> 
> Subject: [PATCH] c++: Error recovery with erroneous DECL_INITIAL [PR94475]
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/94475
> 	* cvt.c (ocp_convert): If the result of scalar_constant_value is
> 	erroneous, ignore it and use the original expression.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94475
> 	* g++.dg/conversion/err-recover2.C: New test.
> 	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
> 	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
> ---
>   gcc/cp/cvt.c                                   |  4 +++-
>   gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
>   gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
>   gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
>   4 files changed, 15 insertions(+), 3 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C
> 
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index a3b80968b33..656e7fd3ec0 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -723,7 +723,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>     if (!CLASS_TYPE_P (type))
>       {
>         e = mark_rvalue_use (e);
> -      e = scalar_constant_value (e);
> +      tree v = scalar_constant_value (e);
> +      if (!error_operand_p (v))
> +	e = v;
>       }
>     if (error_operand_p (e))
>       return error_mark_node;
> diff --git a/gcc/testsuite/g++.dg/conversion/err-recover2.C b/gcc/testsuite/g++.dg/conversion/err-recover2.C
> new file mode 100644
> index 00000000000..437e1a919ea
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/conversion/err-recover2.C
> @@ -0,0 +1,10 @@
> +// PR c++/94475
> +// { dg-do compile }
> +
> +unsigned char
> +sr ()
> +{
> +  const unsigned char xz = EI; // { dg-error "not declared" }
> +
> +  return xz - (xz >> 1);
> +}
> diff --git a/gcc/testsuite/g++.dg/diagnostic/pr84138.C b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> index 5c48b9b164a..00352306a56 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> @@ -5,4 +5,4 @@ foo()
>   {
>     const int i = 0 = 0; // { dg-error "lvalue required as left operand" }
>     return 1 ? 0 : (char)i;
> -} // { dg-warning "control reaches" }
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> index 237ba84d526..4d2688157fc 100644
> --- a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> +++ b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> @@ -5,4 +5,4 @@ bool foo (char c)
>   {
>     const int i = 0 = 0; // { dg-error "lvalue" }
>     return c = i;
> -} // { dg-warning "control reaches" }
> +}
>
Patrick Palka April 16, 2020, 12:57 p.m. UTC | #3
On Wed, 15 Apr 2020, Jason Merrill wrote:

> On 4/15/20 4:43 PM, Patrick Palka wrote:
> > Oops, consider the typo in the subject line fixed.  Also ...
> > 
> > On Wed, 15 Apr 2020, Patrick Palka wrote:
> > 
> > > Here we're ICE'ing in do_narrow during error-recovery, because ocp_convert
> > > returns error_mark_node after it attempts to reduce a const decl to its
> > > erroneous DECL_INITIAL via scalar_constant_value, and we later pass this
> > > error_mark_node to fold_build2 which isn't prepared to handle
> > > error_mark_nodes.
> > > 
> > > We could fix this ICE in do_narrow by checking if ocp_convert returns
> > > error_mark_node, but for the sake of consistency and for better error
> > > recovery
> > > it seems it'd be better if ocp_convert didn't care that a const decl's
> > > initializer is erroneous and would instead proceed as if the decl was not
> > > const,
> > > which is the approach that this patch takes.
> > > 
> > > Passes 'make check-c++', does this look OK to commit after full bootstrap
> > > and
> > > regtest?
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	PR c++/94475
> > > 	* cvt.c (ocp_convert): If the result of scalar_constant_value is
> > > 	erroneous, discard it and carry on with the original expression.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	PR c++/94475
> > > 	* g++.dg/conversion/err-recover2.C: New test.
> > > 	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
> > > 	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
> > > ---
> > >   gcc/cp/cvt.c                                   |  6 +++---
> > >   gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
> > >   gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
> > >   gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
> > >   4 files changed, 15 insertions(+), 5 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C
> > > 
> > > diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> > > index a3b80968b33..b94231a6d08 100644
> > > --- a/gcc/cp/cvt.c
> > > +++ b/gcc/cp/cvt.c
> > > @@ -723,10 +723,10 @@ ocp_convert (tree type, tree expr, int convtype, int
> > > flags,
> > >     if (!CLASS_TYPE_P (type))
> > >       {
> > >         e = mark_rvalue_use (e);
> > > -      e = scalar_constant_value (e);
> > > +      tree v = scalar_constant_value (e);
> > > +      if (!error_operand_p (v))
> > > +	e = v;
> > >       }
> > > -  if (error_operand_p (e))
> > > -    return error_mark_node;
> > 
> > Removing this error_operand_p check might make an error_mark_node slip
> > through and get processed by the rest of ocp_convert, if the call to
> > mark_rvalue_use above returns error_mark_node.
> > 
> > In light of that, please consider this patch instead which restores that
> > error_operand_p check:
> 
> OK.  I wonder if we want to drop the call to scalar_constant_value entirely in
> GCC 11, and expect that the expression will be folded properly later.

That makes sense to me.  On its own, removing the call entirely causes a
few testsuite regressions, but I haven't looked into any of them yet.

> 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: Error recovery with erroneous DECL_INITIAL [PR94475]
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	PR c++/94475
> > 	* cvt.c (ocp_convert): If the result of scalar_constant_value is
> > 	erroneous, ignore it and use the original expression.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	PR c++/94475
> > 	* g++.dg/conversion/err-recover2.C: New test.
> > 	* g++.dg/diagnostic/pr84138.C: Remove now-bogus warning.
> > 	* g++.dg/warn/Wsign-compare-8.C: Remove now-bogus warning.
> > ---
> >   gcc/cp/cvt.c                                   |  4 +++-
> >   gcc/testsuite/g++.dg/conversion/err-recover2.C | 10 ++++++++++
> >   gcc/testsuite/g++.dg/diagnostic/pr84138.C      |  2 +-
> >   gcc/testsuite/g++.dg/warn/Wsign-compare-8.C    |  2 +-
> >   4 files changed, 15 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/conversion/err-recover2.C
> > 
> > diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> > index a3b80968b33..656e7fd3ec0 100644
> > --- a/gcc/cp/cvt.c
> > +++ b/gcc/cp/cvt.c
> > @@ -723,7 +723,9 @@ ocp_convert (tree type, tree expr, int convtype, int
> > flags,
> >     if (!CLASS_TYPE_P (type))
> >       {
> >         e = mark_rvalue_use (e);
> > -      e = scalar_constant_value (e);
> > +      tree v = scalar_constant_value (e);
> > +      if (!error_operand_p (v))
> > +	e = v;
> >       }
> >     if (error_operand_p (e))
> >       return error_mark_node;
> > diff --git a/gcc/testsuite/g++.dg/conversion/err-recover2.C
> > b/gcc/testsuite/g++.dg/conversion/err-recover2.C
> > new file mode 100644
> > index 00000000000..437e1a919ea
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/conversion/err-recover2.C
> > @@ -0,0 +1,10 @@
> > +// PR c++/94475
> > +// { dg-do compile }
> > +
> > +unsigned char
> > +sr ()
> > +{
> > +  const unsigned char xz = EI; // { dg-error "not declared" }
> > +
> > +  return xz - (xz >> 1);
> > +}
> > diff --git a/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> > b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> > index 5c48b9b164a..00352306a56 100644
> > --- a/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> > +++ b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
> > @@ -5,4 +5,4 @@ foo()
> >   {
> >     const int i = 0 = 0; // { dg-error "lvalue required as left operand" }
> >     return 1 ? 0 : (char)i;
> > -} // { dg-warning "control reaches" }
> > +}
> > diff --git a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> > b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> > index 237ba84d526..4d2688157fc 100644
> > --- a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> > +++ b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
> > @@ -5,4 +5,4 @@ bool foo (char c)
> >   {
> >     const int i = 0 = 0; // { dg-error "lvalue" }
> >     return c = i;
> > -} // { dg-warning "control reaches" }
> > +}
> > 
> 
>
diff mbox series

Patch

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index a3b80968b33..b94231a6d08 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -723,10 +723,10 @@  ocp_convert (tree type, tree expr, int convtype, int flags,
   if (!CLASS_TYPE_P (type))
     {
       e = mark_rvalue_use (e);
-      e = scalar_constant_value (e);
+      tree v = scalar_constant_value (e);
+      if (!error_operand_p (v))
+	e = v;
     }
-  if (error_operand_p (e))
-    return error_mark_node;
 
   if (NULLPTR_TYPE_P (type) && null_ptr_cst_p (e))
     {
diff --git a/gcc/testsuite/g++.dg/conversion/err-recover2.C b/gcc/testsuite/g++.dg/conversion/err-recover2.C
new file mode 100644
index 00000000000..437e1a919ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/err-recover2.C
@@ -0,0 +1,10 @@ 
+// PR c++/94475
+// { dg-do compile }
+
+unsigned char
+sr ()
+{
+  const unsigned char xz = EI; // { dg-error "not declared" }
+
+  return xz - (xz >> 1);
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr84138.C b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
index 5c48b9b164a..00352306a56 100644
--- a/gcc/testsuite/g++.dg/diagnostic/pr84138.C
+++ b/gcc/testsuite/g++.dg/diagnostic/pr84138.C
@@ -5,4 +5,4 @@  foo()
 {
   const int i = 0 = 0; // { dg-error "lvalue required as left operand" }
   return 1 ? 0 : (char)i;
-} // { dg-warning "control reaches" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
index 237ba84d526..4d2688157fc 100644
--- a/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
+++ b/gcc/testsuite/g++.dg/warn/Wsign-compare-8.C
@@ -5,4 +5,4 @@  bool foo (char c)
 {
   const int i = 0 = 0; // { dg-error "lvalue" }
   return c = i;
-} // { dg-warning "control reaches" }
+}