Message ID | 20180925071754.GX8250@tucnak |
---|---|
State | New |
Headers | show |
Series | [C++] Fix constexpr OBJ_TYPE_REF handling on array elts (PR c++/87398) | expand |
On Tue, Sep 25, 2018 at 09:17:54AM +0200, Jakub Jelinek wrote: > Hi! > > ARRAY_REF is a handled component, so when a virtual call is on an array > element (or some component thereof), the loop to look through handled > components will look through the ARRAY_REFs too and then TREE_TYPE (obj) > might be an ARRAY_TYPE. The code wants to look at the class type instead > though. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2018-09-25 Jakub Jelinek <jakub@redhat.com> > > PR c++/87398 > * constexpr.c (cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Use > strip_array_types before checking TYPE_BINFO. > > * g++.dg/other/pr87398.C: New test. > * g++.dg/cpp2a/constexpr-virtual10.C: New test. Can't approve but this looks fine to me, thanks! Marek
On Tue, Sep 25, 2018 at 3:17 AM, Jakub Jelinek <jakub@redhat.com> wrote: > ARRAY_REF is a handled component, so when a virtual call is on an array > element (or some component thereof), the loop to look through handled > components will look through the ARRAY_REFs too and then TREE_TYPE (obj) > might be an ARRAY_TYPE. The code wants to look at the class type instead > though. Yeah, I think looping through handled components is wrong here; given something like struct A { virtual void f(); }; struct B { A a; } b; int main() { b.a.f(); } Looking through all handled components would give us "b", which has no virtual functions. I think we need to be more specific about what we're expecting here. Jason
On Tue, Sep 25, 2018 at 10:42:08AM -0400, Jason Merrill wrote: > On Tue, Sep 25, 2018 at 3:17 AM, Jakub Jelinek <jakub@redhat.com> wrote: > > ARRAY_REF is a handled component, so when a virtual call is on an array > > element (or some component thereof), the loop to look through handled > > components will look through the ARRAY_REFs too and then TREE_TYPE (obj) > > might be an ARRAY_TYPE. The code wants to look at the class type instead > > though. > > Yeah, I think looping through handled components is wrong here; given > something like > > struct A > { > virtual void f(); > }; > > struct B > { > A a; > } b; > > int main() > { > b.a.f(); > } > > Looking through all handled components would give us "b", which has no > virtual functions. You're right. So like this (only look through COMPONENT_REFs where the FIELD_DECL is DECL_FIELD_IS_BASE)? Only checked make check-c++-all RUNTESTFLAGS="dg.exp='constexpr-virt* pr87398*'" so far, but it also fixes the PR87425 testcase and doesn't regress anything. 2018-09-25 Jakub Jelinek <jakub@redhat.com> PR c++/87398 * constexpr.c (cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Only look through COMPONENT_REFs with DECL_FIELD_IS_BASE FIELD_DECLs. * g++.dg/other/pr87398.C: New test. * g++.dg/cpp2a/constexpr-virtual10.C: New test. --- gcc/cp/constexpr.c.jj 2018-09-25 15:14:36.335386401 +0200 +++ gcc/cp/constexpr.c 2018-09-25 16:50:38.085334475 +0200 @@ -4812,7 +4812,8 @@ cxx_eval_constant_expression (const cons return t; } obj = TREE_OPERAND (obj, 0); - while (handled_component_p (obj)) + while (TREE_CODE (obj) == COMPONENT_REF + && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))) obj = TREE_OPERAND (obj, 0); tree objtype = TREE_TYPE (obj); /* Find the function decl in the virtual functions list. TOKEN is --- gcc/testsuite/g++.dg/other/pr87398.C.jj 2018-09-25 16:49:40.458304980 +0200 +++ gcc/testsuite/g++.dg/other/pr87398.C 2018-09-25 16:49:40.458304980 +0200 @@ -0,0 +1,12 @@ +// PR c++/87398 +// { dg-do compile } + +struct A { virtual int foo (); }; + +int +bar (int x) +{ + A e[5][2]; + int f = e[4][x].foo (); + return f; +} --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C.jj 2018-09-25 16:49:40.458304980 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C 2018-09-25 16:49:40.458304980 +0200 @@ -0,0 +1,18 @@ +// P1064R0 +// { dg-do compile } +// { dg-options "-std=c++2a" } + +struct X +{ + constexpr virtual int f() const { return 1; }; +}; + +struct Y : public X +{ + constexpr virtual int f() const { return 2; }; +}; + +constexpr X a[2][1][3]; +constexpr Y b[3][12]; +static_assert (a[1][0][1].f() == 1); +static_assert (b[2][11].f() == 2); Jakub
On Tue, Sep 25, 2018 at 10:57 AM, Jakub Jelinek <jakub@redhat.com> wrote: > On Tue, Sep 25, 2018 at 10:42:08AM -0400, Jason Merrill wrote: >> On Tue, Sep 25, 2018 at 3:17 AM, Jakub Jelinek <jakub@redhat.com> wrote: >> > ARRAY_REF is a handled component, so when a virtual call is on an array >> > element (or some component thereof), the loop to look through handled >> > components will look through the ARRAY_REFs too and then TREE_TYPE (obj) >> > might be an ARRAY_TYPE. The code wants to look at the class type instead >> > though. >> >> Yeah, I think looping through handled components is wrong here; given >> something like >> >> struct A >> { >> virtual void f(); >> }; >> >> struct B >> { >> A a; >> } b; >> >> int main() >> { >> b.a.f(); >> } >> >> Looking through all handled components would give us "b", which has no >> virtual functions. > > You're right. So like this (only look through COMPONENT_REFs where the > FIELD_DECL is DECL_FIELD_IS_BASE)? > Only checked > make check-c++-all RUNTESTFLAGS="dg.exp='constexpr-virt* pr87398*'" > so far, but it also fixes the PR87425 testcase and doesn't regress anything. Looks good. Jason
On Tue, Sep 25, 2018 at 11:07:19AM -0400, Jason Merrill wrote: > > You're right. So like this (only look through COMPONENT_REFs where the > > FIELD_DECL is DECL_FIELD_IS_BASE)? > > Only checked > > make check-c++-all RUNTESTFLAGS="dg.exp='constexpr-virt* pr87398*'" > > so far, but it also fixes the PR87425 testcase and doesn't regress anything. > > Looks good. Thanks, will bootstrap/regtest it now. I also took your testcase and turned it into something that ICEd without this patch too, is that testcase also ok (constexpr-virtual11.C)? 2018-09-25 Jakub Jelinek <jakub@redhat.com> PR c++/87398 * constexpr.c (cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Only look through COMPONENT_REFs with DECL_FIELD_IS_BASE FIELD_DECLs. * g++.dg/other/pr87398.C: New test. * g++.dg/cpp2a/constexpr-virtual10.C: New test. * g++.dg/cpp2a/constexpr-virtual11.C: New test. --- gcc/cp/constexpr.c.jj 2018-09-25 15:14:36.335386401 +0200 +++ gcc/cp/constexpr.c 2018-09-25 16:50:38.085334475 +0200 @@ -4812,7 +4812,8 @@ cxx_eval_constant_expression (const cons return t; } obj = TREE_OPERAND (obj, 0); - while (handled_component_p (obj)) + while (TREE_CODE (obj) == COMPONENT_REF + && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))) obj = TREE_OPERAND (obj, 0); tree objtype = TREE_TYPE (obj); /* Find the function decl in the virtual functions list. TOKEN is --- gcc/testsuite/g++.dg/other/pr87398.C.jj 2018-09-25 16:49:40.458304980 +0200 +++ gcc/testsuite/g++.dg/other/pr87398.C 2018-09-25 16:49:40.458304980 +0200 @@ -0,0 +1,12 @@ +// PR c++/87398 +// { dg-do compile } + +struct A { virtual int foo (); }; + +int +bar (int x) +{ + A e[5][2]; + int f = e[4][x].foo (); + return f; +} --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C.jj 2018-09-25 16:49:40.458304980 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C 2018-09-25 16:49:40.458304980 +0200 @@ -0,0 +1,18 @@ +// P1064R0 +// { dg-do compile } +// { dg-options "-std=c++2a" } + +struct X +{ + constexpr virtual int f() const { return 1; }; +}; + +struct Y : public X +{ + constexpr virtual int f() const { return 2; }; +}; + +constexpr X a[2][1][3]; +constexpr Y b[3][12]; +static_assert (a[1][0][1].f() == 1); +static_assert (b[2][11].f() == 2); --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual11.C.jj 2018-09-01 11:09:41.506153390 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual11.C 2018-09-25 17:11:30.563244029 +0200 @@ -0,0 +1,26 @@ +// P1064R0 +// { dg-do compile } +// { dg-options "-std=c++2a" } + +struct A +{ + constexpr virtual int f () const { return 1; } +}; + +struct B : public A +{ + constexpr virtual int f () const { return 2; } +}; + +struct C +{ + A a; + B b; +}; + +constexpr C c; +constexpr const A &d = c.a; +constexpr const A &e = c.b; +constexpr const B &f = c.b; +static_assert (c.a.f () == 1 && c.b.f () == 2); +static_assert (d.f () == 1 && e.f () == 2 && f.f () == 2); Jakub
Yes, thanks. On Tue, Sep 25, 2018 at 11:14 AM, Jakub Jelinek <jakub@redhat.com> wrote: > On Tue, Sep 25, 2018 at 11:07:19AM -0400, Jason Merrill wrote: >> > You're right. So like this (only look through COMPONENT_REFs where the >> > FIELD_DECL is DECL_FIELD_IS_BASE)? >> > Only checked >> > make check-c++-all RUNTESTFLAGS="dg.exp='constexpr-virt* pr87398*'" >> > so far, but it also fixes the PR87425 testcase and doesn't regress anything. >> >> Looks good. > > Thanks, will bootstrap/regtest it now. I also took your testcase and turned it into > something that ICEd without this patch too, is that testcase also ok > (constexpr-virtual11.C)? > > 2018-09-25 Jakub Jelinek <jakub@redhat.com> > > PR c++/87398 > * constexpr.c (cxx_eval_constant_expression) <case OBJ_TYPE_REF>: Only > look through COMPONENT_REFs with DECL_FIELD_IS_BASE FIELD_DECLs. > > * g++.dg/other/pr87398.C: New test. > * g++.dg/cpp2a/constexpr-virtual10.C: New test. > * g++.dg/cpp2a/constexpr-virtual11.C: New test. > > --- gcc/cp/constexpr.c.jj 2018-09-25 15:14:36.335386401 +0200 > +++ gcc/cp/constexpr.c 2018-09-25 16:50:38.085334475 +0200 > @@ -4812,7 +4812,8 @@ cxx_eval_constant_expression (const cons > return t; > } > obj = TREE_OPERAND (obj, 0); > - while (handled_component_p (obj)) > + while (TREE_CODE (obj) == COMPONENT_REF > + && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))) > obj = TREE_OPERAND (obj, 0); > tree objtype = TREE_TYPE (obj); > /* Find the function decl in the virtual functions list. TOKEN is > --- gcc/testsuite/g++.dg/other/pr87398.C.jj 2018-09-25 16:49:40.458304980 +0200 > +++ gcc/testsuite/g++.dg/other/pr87398.C 2018-09-25 16:49:40.458304980 +0200 > @@ -0,0 +1,12 @@ > +// PR c++/87398 > +// { dg-do compile } > + > +struct A { virtual int foo (); }; > + > +int > +bar (int x) > +{ > + A e[5][2]; > + int f = e[4][x].foo (); > + return f; > +} > --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C.jj 2018-09-25 16:49:40.458304980 +0200 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C 2018-09-25 16:49:40.458304980 +0200 > @@ -0,0 +1,18 @@ > +// P1064R0 > +// { dg-do compile } > +// { dg-options "-std=c++2a" } > + > +struct X > +{ > + constexpr virtual int f() const { return 1; }; > +}; > + > +struct Y : public X > +{ > + constexpr virtual int f() const { return 2; }; > +}; > + > +constexpr X a[2][1][3]; > +constexpr Y b[3][12]; > +static_assert (a[1][0][1].f() == 1); > +static_assert (b[2][11].f() == 2); > --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual11.C.jj 2018-09-01 11:09:41.506153390 +0200 > +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual11.C 2018-09-25 17:11:30.563244029 +0200 > @@ -0,0 +1,26 @@ > +// P1064R0 > +// { dg-do compile } > +// { dg-options "-std=c++2a" } > + > +struct A > +{ > + constexpr virtual int f () const { return 1; } > +}; > + > +struct B : public A > +{ > + constexpr virtual int f () const { return 2; } > +}; > + > +struct C > +{ > + A a; > + B b; > +}; > + > +constexpr C c; > +constexpr const A &d = c.a; > +constexpr const A &e = c.b; > +constexpr const B &f = c.b; > +static_assert (c.a.f () == 1 && c.b.f () == 2); > +static_assert (d.f () == 1 && e.f () == 2 && f.f () == 2); > > > Jakub
--- gcc/cp/constexpr.c.jj 2018-09-24 10:36:53.687031261 +0200 +++ gcc/cp/constexpr.c 2018-09-24 11:01:34.035268597 +0200 @@ -4814,7 +4814,7 @@ cxx_eval_constant_expression (const cons obj = TREE_OPERAND (obj, 0); while (handled_component_p (obj)) obj = TREE_OPERAND (obj, 0); - tree objtype = TREE_TYPE (obj); + tree objtype = strip_array_types (TREE_TYPE (obj)); /* 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/other/pr87398.C.jj 2018-09-24 10:53:41.605170048 +0200 +++ gcc/testsuite/g++.dg/other/pr87398.C 2018-09-24 10:53:14.642621001 +0200 @@ -0,0 +1,12 @@ +// PR c++/87398 +// { dg-do compile } + +struct A { virtual int foo (); }; + +int +bar (int x) +{ + A e[5][2]; + int f = e[4][x].foo (); + return f; +} --- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C.jj 2018-09-24 10:56:15.604594387 +0200 +++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual10.C 2018-09-24 10:56:54.882937453 +0200 @@ -0,0 +1,18 @@ +// P1064R0 +// { dg-do compile } +// { dg-options "-std=c++2a" } + +struct X +{ + constexpr virtual int f() const { return 1; }; +}; + +struct Y : public X +{ + constexpr virtual int f() const { return 2; }; +}; + +constexpr X a[2][1][3]; +constexpr Y b[3][12]; +static_assert (a[1][0][1].f() == 1); +static_assert (b[2][11].f() == 2);