Message ID | 20200224164440.390576-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Fix ICE with constexpr init and [[no_unique_address]] [PR93803] | expand |
On 2/24/20 11:44 AM, Marek Polacek wrote: > Here we crash when constexpr-initializing a class member of empty class > type with [[no_unique_address]]. Without the attribute we would have > a ctor (that initializes bar) of the form > > { .D.2173 = { .x = {} } } > > but with the attribute reduced_constant_expression_p gets > > { .x = {} } > > That means that "idx != field" is true for the latter and we see that > foo, the base class of bar, is an empty class, so we want to look at > the next initializable field (since empty class fields may not have an > initializer). But in this case there are no more, therefore accessing > DECL_CHAIN (field) crashes. Long story short, we need to avoid a crash > on a null field when we're initializing a class that only contains an > empty base class. > > While poking into this I discovered c++/93898, but that's a different > problem. > > Bootstrapped/regtested on x86_64-linux, ok for trunk? OK. > 2020-02-24 Marek Polacek <polacek@redhat.com> > > PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. > * constexpr.c (reduced_constant_expression_p): Don't crash on a null > field. > > * g++.dg/cpp2a/constexpr-init16.C: New test. > * g++.dg/cpp2a/constexpr-init17.C: New test. > --- > gcc/cp/constexpr.c | 16 +++++++--------- > gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C | 15 +++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C | 15 +++++++++++++++ > 3 files changed, 37 insertions(+), 9 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C > > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c > index 128f760778b..3da1609cdaa 100644 > --- a/gcc/cp/constexpr.c > +++ b/gcc/cp/constexpr.c > @@ -2603,16 +2603,14 @@ reduced_constant_expression_p (tree t) > element. */ > if (!reduced_constant_expression_p (val)) > return false; > + /* Empty class field may or may not have an initializer. */ > + for (; field && idx != field; > + field = next_initializable_field (DECL_CHAIN (field))) > + if (!is_really_empty_class (TREE_TYPE (field), > + /*ignore_vptr*/false)) > + return false; > if (field) > - { > - /* Empty class field may or may not have an initializer. */ > - for (; idx != field; > - field = next_initializable_field (DECL_CHAIN (field))) > - if (!is_really_empty_class (TREE_TYPE (field), > - /*ignore_vptr*/false)) > - return false; > - field = next_initializable_field (DECL_CHAIN (field)); > - } > + field = next_initializable_field (DECL_CHAIN (field)); > } > /* There could be a non-empty field at the end. */ > for (; field; field = next_initializable_field (DECL_CHAIN (field))) > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C > new file mode 100644 > index 00000000000..16db2974f2a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C > @@ -0,0 +1,15 @@ > +// PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. > +// { dg-do compile { target c++2a } } > + > +struct empty { }; > + > +struct foo { > + [[no_unique_address]] empty x; > + constexpr foo() : x{} { } > +}; > + > +struct bar : foo { > + using foo::foo; > +}; > + > +constexpr bar a{}; > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C > new file mode 100644 > index 00000000000..34d9fe58ecb > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C > @@ -0,0 +1,15 @@ > +// PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. > +// { dg-do compile { target c++2a } } > + > +struct empty { }; > + > +struct foo { > + [[no_unique_address]] empty x, x2, x3; > + constexpr foo() : x{}, x2{} { } > +}; > + > +struct bar : foo { > + using foo::foo; > +}; > + > +constexpr bar a{}; > > base-commit: 004f2c07b6d3fa543f0fe86c55a7b3c227de2bb6 >
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 128f760778b..3da1609cdaa 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2603,16 +2603,14 @@ reduced_constant_expression_p (tree t) element. */ if (!reduced_constant_expression_p (val)) return false; + /* Empty class field may or may not have an initializer. */ + for (; field && idx != field; + field = next_initializable_field (DECL_CHAIN (field))) + if (!is_really_empty_class (TREE_TYPE (field), + /*ignore_vptr*/false)) + return false; if (field) - { - /* Empty class field may or may not have an initializer. */ - for (; idx != field; - field = next_initializable_field (DECL_CHAIN (field))) - if (!is_really_empty_class (TREE_TYPE (field), - /*ignore_vptr*/false)) - return false; - field = next_initializable_field (DECL_CHAIN (field)); - } + field = next_initializable_field (DECL_CHAIN (field)); } /* There could be a non-empty field at the end. */ for (; field; field = next_initializable_field (DECL_CHAIN (field))) diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C new file mode 100644 index 00000000000..16db2974f2a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init16.C @@ -0,0 +1,15 @@ +// PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. +// { dg-do compile { target c++2a } } + +struct empty { }; + +struct foo { + [[no_unique_address]] empty x; + constexpr foo() : x{} { } +}; + +struct bar : foo { + using foo::foo; +}; + +constexpr bar a{}; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C new file mode 100644 index 00000000000..34d9fe58ecb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init17.C @@ -0,0 +1,15 @@ +// PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. +// { dg-do compile { target c++2a } } + +struct empty { }; + +struct foo { + [[no_unique_address]] empty x, x2, x3; + constexpr foo() : x{}, x2{} { } +}; + +struct bar : foo { + using foo::foo; +}; + +constexpr bar a{};