Message ID | 20200209072735.GG17695@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Fix ICE during constexpr virtual call evaluation [PR93633] | expand |
On 2/9/20 2:27 AM, Jakub Jelinek wrote: > Hi! > > The first (valid) testcase ICEs because for > A *a = new B (); > a->foo (); // virtual method call > we actually see &heap and the "heap " objects don't have the class or > whatever else type was used in new expression, but an array type containing > one (or more of those for array new) and so when using TYPE_BINFO (objtype) > on it we ICE. > This patch handles this special case, and otherwise punts (as shown e.g. in > the second testcase, where because the heap object is already deleted, > we don't really want to allow it to be used. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? OK. > 2020-02-08 Jakub Jelinek <jakub@redhat.com> > > PR c++/93633 > * constexpr.c (cxx_eval_constant_expression): If obj is heap var with > ARRAY_TYPE, use the element type. Punt if objtype after that is not > a class type. > > * g++.dg/cpp2a/constexpr-new11.C: New test. > * g++.dg/cpp2a/constexpr-new12.C: New test. > * g++.dg/cpp2a/constexpr-new13.C: New test. > > --- gcc/cp/constexpr.c.jj 2020-02-08 10:58:15.434064005 +0100 > +++ gcc/cp/constexpr.c 2020-02-08 14:15:55.356768622 +0100 > @@ -6027,6 +6027,17 @@ cxx_eval_constant_expression (const cons > && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))) > obj = TREE_OPERAND (obj, 0); > tree objtype = TREE_TYPE (obj); > + if (VAR_P (obj) > + && DECL_NAME (obj) == heap_identifier > + && TREE_CODE (objtype) == ARRAY_TYPE) > + objtype = TREE_TYPE (objtype); > + if (!CLASS_TYPE_P (objtype)) > + { > + if (!ctx->quiet) > + error_at (loc, "expression %qE is not a constant expression", t); > + *non_constant_p = true; > + return t; > + } > /* Find the function decl in the virtual functions list. TOKEN is > the DECL_VINDEX that says which function we're looking for. */ > tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype)); > --- gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C.jj 2020-02-08 14:22:34.740789172 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C 2020-02-08 14:21:50.689448695 +0100 > @@ -0,0 +1,31 @@ > +// PR c++/93633 > +// { dg-do compile { target c++2a } } > + > +struct A { > + constexpr A () : a (0) {} > + constexpr virtual int foo () { return 1 + a * 4; } > + int a; > +}; > + > +struct B : A { > + constexpr B () : b (0) {} > + constexpr virtual int foo () { return 0 + b * 4; } > + int b; > +}; > + > +constexpr int > +foo () > +{ > + A *a = new B (); > + a->a = 4; > + int r = a->foo (); > + delete a; > + return r; > +} > + > +int > +main () > +{ > + constexpr auto a = foo (); > + static_assert (a == 0); > +} > --- gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C.jj 2020-02-08 14:22:38.043739717 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C 2020-02-08 14:24:04.119451025 +0100 > @@ -0,0 +1,26 @@ > +// PR c++/93633 > +// { dg-do compile { target c++2a } } > + > +struct A { > + constexpr A () : a (0) {} > + constexpr virtual int foo () { return 1 + a * 4; } > + int a; > +}; > + > +struct B : A { > + constexpr B () : b (0) {} > + constexpr virtual int foo () { return 0 + b * 4; } > + int b; > +}; > + > +constexpr int > +foo () > +{ > + A *a = new B (); > + a->a = 4; > + delete a; > + int r = a->foo (); > + return r; > +} > + > +constexpr auto a = foo (); // { dg-error "is not a constant expression" } > --- gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C.jj 2020-02-08 14:22:41.060694553 +0100 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C 2020-02-08 14:25:38.783033750 +0100 > @@ -0,0 +1,26 @@ > +// PR c++/93633 > +// { dg-do compile { target c++2a } } > + > +struct A { > + constexpr A () : a (0) {} > + virtual int foo () { return 1 + a * 4; } > + int a; > +}; > + > +struct B : A { > + constexpr B () : b (0) {} > + virtual int foo () { return 0 + b * 4; } // { dg-message "declared here" } > + int b; > +}; > + > +constexpr int > +foo () > +{ > + A *a = new B (); > + a->a = 4; > + int r = a->foo (); // { dg-error "call to non-.constexpr. function" } > + delete a; > + return r; > +} > + > +constexpr auto a = foo (); > > Jakub >
--- gcc/cp/constexpr.c.jj 2020-02-08 10:58:15.434064005 +0100 +++ gcc/cp/constexpr.c 2020-02-08 14:15:55.356768622 +0100 @@ -6027,6 +6027,17 @@ cxx_eval_constant_expression (const cons && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))) obj = TREE_OPERAND (obj, 0); tree objtype = TREE_TYPE (obj); + if (VAR_P (obj) + && DECL_NAME (obj) == heap_identifier + && TREE_CODE (objtype) == ARRAY_TYPE) + objtype = TREE_TYPE (objtype); + if (!CLASS_TYPE_P (objtype)) + { + if (!ctx->quiet) + error_at (loc, "expression %qE is not a constant expression", t); + *non_constant_p = true; + return t; + } /* Find the function decl in the virtual functions list. TOKEN is the DECL_VINDEX that says which function we're looking for. */ tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype)); --- gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C.jj 2020-02-08 14:22:34.740789172 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C 2020-02-08 14:21:50.689448695 +0100 @@ -0,0 +1,31 @@ +// PR c++/93633 +// { dg-do compile { target c++2a } } + +struct A { + constexpr A () : a (0) {} + constexpr virtual int foo () { return 1 + a * 4; } + int a; +}; + +struct B : A { + constexpr B () : b (0) {} + constexpr virtual int foo () { return 0 + b * 4; } + int b; +}; + +constexpr int +foo () +{ + A *a = new B (); + a->a = 4; + int r = a->foo (); + delete a; + return r; +} + +int +main () +{ + constexpr auto a = foo (); + static_assert (a == 0); +} --- gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C.jj 2020-02-08 14:22:38.043739717 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C 2020-02-08 14:24:04.119451025 +0100 @@ -0,0 +1,26 @@ +// PR c++/93633 +// { dg-do compile { target c++2a } } + +struct A { + constexpr A () : a (0) {} + constexpr virtual int foo () { return 1 + a * 4; } + int a; +}; + +struct B : A { + constexpr B () : b (0) {} + constexpr virtual int foo () { return 0 + b * 4; } + int b; +}; + +constexpr int +foo () +{ + A *a = new B (); + a->a = 4; + delete a; + int r = a->foo (); + return r; +} + +constexpr auto a = foo (); // { dg-error "is not a constant expression" } --- gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C.jj 2020-02-08 14:22:41.060694553 +0100 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C 2020-02-08 14:25:38.783033750 +0100 @@ -0,0 +1,26 @@ +// PR c++/93633 +// { dg-do compile { target c++2a } } + +struct A { + constexpr A () : a (0) {} + virtual int foo () { return 1 + a * 4; } + int a; +}; + +struct B : A { + constexpr B () : b (0) {} + virtual int foo () { return 0 + b * 4; } // { dg-message "declared here" } + int b; +}; + +constexpr int +foo () +{ + A *a = new B (); + a->a = 4; + int r = a->foo (); // { dg-error "call to non-.constexpr. function" } + delete a; + return r; +} + +constexpr auto a = foo ();