Message ID | 20191108091451.GM4650@tucnak |
---|---|
State | New |
Headers | show |
Series | [C++] Fix error-recovery with constexpr dtor (PR c++/92414) | expand |
On 11/8/19 9:14 AM, Jakub Jelinek wrote: > Hi! > > We ICE on the following testcase, because DECL_INITIAL (decl) is > error_mark_node due to previously reported error and > cxx_eval_outermost_constant_expr is unhappy if ctx.ctor is not > a CONSTRUCTOR, but error_mark_node. > > If the initializer is invalid, it should have been diagnosed already and > there is no need to try to evaluate constexpr dtor on it. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2019-11-08 Jakub Jelinek <jakub@redhat.com> > > PR c++/92414 > * constexpr.c (cxx_constant_dtor): Don't call > cxx_eval_outermost_constant_expr if DECL_INITIAL is erroneous. Why add the error-checking here rather than in cxx_eval_outermost_constant_expr when we use DECL_INITIAL? > * g++.dg/cpp2a/constexpr-dtor4.C: New test. > > --- gcc/cp/constexpr.c.jj 2019-11-06 08:58:37.000000000 +0100 > +++ gcc/cp/constexpr.c 2019-11-07 22:13:58.395840756 +0100 > @@ -6024,7 +6024,8 @@ cxx_constant_value (tree t, tree decl) > void > cxx_constant_dtor (tree t, tree decl) > { > - cxx_eval_outermost_constant_expr (t, false, true, true, true, decl); > + if (!error_operand_p (DECL_INITIAL (decl))) > + cxx_eval_outermost_constant_expr (t, false, true, true, true, decl); > } > > /* Helper routine for fold_simple function. Either return simplified > --- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C.jj 2019-11-07 22:16:56.943181785 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C 2019-11-07 22:18:16.752993443 +0100 > @@ -0,0 +1,15 @@ > +// PR c++/92414 > +// { dg-do compile { target c++2a } } > + > +struct A { virtual void foo (); }; > + > +struct B : A { > + constexpr B (int); // { dg-warning "used but never defined" } > + constexpr ~B () { } > +}; > + > +struct D : B { > + constexpr D () : B (42) { } // { dg-error "used before its definition" } > +}; > + > +constexpr D d; // { dg-message "in 'constexpr' expansion of" } > > Jakub >
On Mon, Nov 18, 2019 at 02:38:51PM -0500, Jason Merrill wrote: > On 11/8/19 9:14 AM, Jakub Jelinek wrote: > > Hi! > > > > We ICE on the following testcase, because DECL_INITIAL (decl) is > > error_mark_node due to previously reported error and > > cxx_eval_outermost_constant_expr is unhappy if ctx.ctor is not > > a CONSTRUCTOR, but error_mark_node. > > > > If the initializer is invalid, it should have been diagnosed already and > > there is no need to try to evaluate constexpr dtor on it. > > > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > > > 2019-11-08 Jakub Jelinek <jakub@redhat.com> > > > > PR c++/92414 > > * constexpr.c (cxx_constant_dtor): Don't call > > cxx_eval_outermost_constant_expr if DECL_INITIAL is erroneous. > > Why add the error-checking here rather than in > cxx_eval_outermost_constant_expr when we use DECL_INITIAL? So like this? Also passed bootstrap/regtest on x86_64-linux and i686-linux: 2019-11-19 Jakub Jelinek <jakub@redhat.com> PR c++/92414 * constexpr.c (cxx_eval_outermost_constant_expr): If DECL_INITIAL on object is erroneous, return t without trying to evaluate a constexpr dtor. * g++.dg/cpp2a/constexpr-dtor4.C: New test. --- gcc/cp/constexpr.c.jj 2019-11-18 21:50:49.539233013 +0100 +++ gcc/cp/constexpr.c 2019-11-18 21:52:47.217475549 +0100 @@ -5834,6 +5834,8 @@ cxx_eval_outermost_constant_expr (tree t gcc_assert (object && VAR_P (object)); gcc_assert (DECL_DECLARED_CONSTEXPR_P (object)); gcc_assert (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object)); + if (error_operand_p (DECL_INITIAL (object))) + return t; ctx.ctor = unshare_expr (DECL_INITIAL (object)); TREE_READONLY (ctx.ctor) = false; /* Temporarily force decl_really_constant_value to return false --- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C.jj 2019-11-18 21:50:56.152134256 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C 2019-11-18 21:50:56.152134256 +0100 @@ -0,0 +1,15 @@ +// PR c++/92414 +// { dg-do compile { target c++2a } } + +struct A { virtual void foo (); }; + +struct B : A { + constexpr B (int); // { dg-warning "used but never defined" } + constexpr ~B () { } +}; + +struct D : B { + constexpr D () : B (42) { } // { dg-error "used before its definition" } +}; + +constexpr D d; // { dg-message "in 'constexpr' expansion of" } Jakub
On 11/18/19 11:22 PM, Jakub Jelinek wrote: > On Mon, Nov 18, 2019 at 02:38:51PM -0500, Jason Merrill wrote: >> On 11/8/19 9:14 AM, Jakub Jelinek wrote: >>> Hi! >>> >>> We ICE on the following testcase, because DECL_INITIAL (decl) is >>> error_mark_node due to previously reported error and >>> cxx_eval_outermost_constant_expr is unhappy if ctx.ctor is not >>> a CONSTRUCTOR, but error_mark_node. >>> >>> If the initializer is invalid, it should have been diagnosed already and >>> there is no need to try to evaluate constexpr dtor on it. >>> >>> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? >>> >>> 2019-11-08 Jakub Jelinek <jakub@redhat.com> >>> >>> PR c++/92414 >>> * constexpr.c (cxx_constant_dtor): Don't call >>> cxx_eval_outermost_constant_expr if DECL_INITIAL is erroneous. >> >> Why add the error-checking here rather than in >> cxx_eval_outermost_constant_expr when we use DECL_INITIAL? > > So like this? > Also passed bootstrap/regtest on x86_64-linux and i686-linux: OK, thanks. > 2019-11-19 Jakub Jelinek <jakub@redhat.com> > > PR c++/92414 > * constexpr.c (cxx_eval_outermost_constant_expr): If DECL_INITIAL > on object is erroneous, return t without trying to evaluate > a constexpr dtor. > > * g++.dg/cpp2a/constexpr-dtor4.C: New test. > > --- gcc/cp/constexpr.c.jj 2019-11-18 21:50:49.539233013 +0100 > +++ gcc/cp/constexpr.c 2019-11-18 21:52:47.217475549 +0100 > @@ -5834,6 +5834,8 @@ cxx_eval_outermost_constant_expr (tree t > gcc_assert (object && VAR_P (object)); > gcc_assert (DECL_DECLARED_CONSTEXPR_P (object)); > gcc_assert (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object)); > + if (error_operand_p (DECL_INITIAL (object))) > + return t; > ctx.ctor = unshare_expr (DECL_INITIAL (object)); > TREE_READONLY (ctx.ctor) = false; > /* Temporarily force decl_really_constant_value to return false > --- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C.jj 2019-11-18 21:50:56.152134256 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C 2019-11-18 21:50:56.152134256 +0100 > @@ -0,0 +1,15 @@ > +// PR c++/92414 > +// { dg-do compile { target c++2a } } > + > +struct A { virtual void foo (); }; > + > +struct B : A { > + constexpr B (int); // { dg-warning "used but never defined" } > + constexpr ~B () { } > +}; > + > +struct D : B { > + constexpr D () : B (42) { } // { dg-error "used before its definition" } > +}; > + > +constexpr D d; // { dg-message "in 'constexpr' expansion of" } > > > Jakub >
--- gcc/cp/constexpr.c.jj 2019-11-06 08:58:37.000000000 +0100 +++ gcc/cp/constexpr.c 2019-11-07 22:13:58.395840756 +0100 @@ -6024,7 +6024,8 @@ cxx_constant_value (tree t, tree decl) void cxx_constant_dtor (tree t, tree decl) { - cxx_eval_outermost_constant_expr (t, false, true, true, true, decl); + if (!error_operand_p (DECL_INITIAL (decl))) + cxx_eval_outermost_constant_expr (t, false, true, true, true, decl); } /* Helper routine for fold_simple function. Either return simplified --- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C.jj 2019-11-07 22:16:56.943181785 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor4.C 2019-11-07 22:18:16.752993443 +0100 @@ -0,0 +1,15 @@ +// PR c++/92414 +// { dg-do compile { target c++2a } } + +struct A { virtual void foo (); }; + +struct B : A { + constexpr B (int); // { dg-warning "used but never defined" } + constexpr ~B () { } +}; + +struct D : B { + constexpr D () : B (42) { } // { dg-error "used before its definition" } +}; + +constexpr D d; // { dg-message "in 'constexpr' expansion of" }