On Wed, Nov 27, 2019 at 04:47:01PM -0500, Jason Merrill wrote: > On 11/27/19 2:36 PM, Marek Polacek wrote: > > On Sun, Nov 24, 2019 at 12:24:48PM -0500, Jason Merrill wrote: > > > On 11/16/19 5:23 PM, Marek Polacek wrote: > > > > [ Working virtually on Baker Island. ] > > > > > > > > This patch implements C++20 P1331, allowing trivial default > > > > initialization in > > > > constexpr contexts. > > > > > > > > I used Jakub's patch from the PR which allowed uninitialized variables > > > > in > > > > constexpr contexts. But the hard part was handling > > > > CONSTRUCTOR_NO_CLEARING > > > > which is always cleared in cxx_eval_call_expression. We need to set it > > > > in > > > > the case a constexpr constructor doesn't initialize all the members, so > > > > that > > > > we can give proper diagnostic instead of value-initializing. A lot of > > > > my > > > > attempts flopped but then I came up with this approach, which handles > > > > various > > > > cases as tested in constexpr-init8.C, where S is initialized by a > > > > non-default > > > > constexpr constructor, and constexpr-init9.C, using delegating > > > > constructors. > > > > And the best part is that I didn't need any new > > > > cx_check_missing_mem_inits > > > > calls! Just save the information whether a constructor is missing an > > > > init > > > > into constexpr_fundef_table and retrieve it when needed. > > > > > > Is it necessary to clear the flag for constructors that do happen to > > > initialize all the members? I would think that leaving that clearing to > > > reduced_constant_expression_p would be enough. > > > > It seems so: if I tweak cxx_eval_call_expression to only call > > clear_no_implicit_zero > > when 'fun' isn't DECL_CONSTRUCTOR_P, then a lot breaks, e.g. > > constexpr-base.C > > where the constructor initializes all the members. By breaking I mean > > spurious > > errors coming from > > > > 5937 if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) > > 5938 { > > 5939 if (!allow_non_constant) > > 5940 error ("%qE is not a constant expression because it refers to " > > 5941 "an incompletely initialized variable", t); > > 5942 TREE_CONSTANT (r) = false; > > 5943 non_constant_p = true; > > 5944 } > > Why didn't reduced_constant_expression_p unset CONSTRUCTOR_NO_CLEARING?
We have a constructor that initializes a base class and members of a class: {.D.2364={.i=12}, .a={.i=24}, .j=36} Say we don't clear CONSTRUCTOR_NO_CLEARING in this ctor in cxx_eval_call_expression. Then soon in reduced_constant_expression_p we do 2221 field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t))); and since "Implement P0017R1, C++17 aggregates with bases. / r241187" we skip base fields in C++17 so 'field' is set to 'a'. Now we look at each element of the constructor; the first one is D.2364={.i=12}. But we hit 2233 if (idx != field) 2234 return false; because field is 'a' and idx is D.2364. Were you thinking of tweaking reduced_constant_expression_p's behavior in C++20 and dropping the whole cxx_eval_call_expression hunk? -- Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA