When we process a store that changes the active member of a union, we need to forget about other members.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 23c02701a1f2d115b9b88ccd88e1d3a26674ab14 Author: Jason Merrill <ja...@redhat.com> Date: Fri Feb 10 12:35:49 2017 -0500 PR c++/78897 - constexpr union * constexpr.c (cxx_eval_store_expression): A store to a union member erases a previous store to another member. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index bb45f1e..bfdde9e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3466,6 +3466,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, tree fields = TYPE_FIELDS (DECL_CONTEXT (index)); unsigned HOST_WIDE_INT idx; + if (code == UNION_TYPE && CONSTRUCTOR_NELTS (*valp) + && CONSTRUCTOR_ELT (*valp, 0)->index != index) + /* Changing active member. */ + vec_safe_truncate (CONSTRUCTOR_ELTS (*valp), 0); + for (idx = 0; vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep); idx++, fields = DECL_CHAIN (fields)) diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-union1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-union1.C new file mode 100644 index 0000000..8aed6d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-union1.C @@ -0,0 +1,11 @@ +// PR c++/78897 +// { dg-do compile { target c++14 } } + +struct Optional { + constexpr Optional() : _dummy{} { _value = 1; } + union { + int _dummy; + int _value; + }; +}; +Optional opt{};