diff mbox series

c++: Fix up default initialization with consteval default ctor [PR96994]

Message ID 20200915075706.GN21814@tucnak
State New
Headers show
Series c++: Fix up default initialization with consteval default ctor [PR96994] | expand

Commit Message

Jakub Jelinek Sept. 15, 2020, 7:57 a.m. UTC
Hi!

The following testcase is miscompiled (in particular the a and i
initialization).  The problem is that build_special_member_call due to
the immediate constructors (but not evaluated in constant expression mode)
doesn't create a CALL_EXPR, but returns a TARGET_EXPR with CONSTRUCTOR
as the initializer for it, and then expand_default_init just emits
the returned statement, but this one doesn't have any side-effects and does
nothing.  There is an if to handle constexpr ctors which emits an INIT_EXPR
but constexpr ctors still show up as CALL_EXPR and need to be manually
evaluated to constant expressions (if possible).

The following patch fixes that, though I'm not sure about several things.
One is that the earlier if also has expr == true_exp && in the condition,
not sure if we want it in this case or not.
Another is that for delegating constructors, we emit two separate calls
and build_if_in_charge them together.  Not sure if consteval could come into
play in that case.

Bootstrapped/regtested on x86_64-linux and i686-linux.

2020-09-15  Jakub Jelinek  <jakub@redhat.com>

	PR c++/96994
	* init.c (expand_default_init): If rval is TARGET_EXPR with
	TREE_CONSTANT TARGET_EXPR_INITIAL, emit INIT_EXPR.

	* g++.dg/cpp2a/consteval18.C: New test.


	Jakub

Comments

Stephan Bergmann Sept. 25, 2020, 12:49 p.m. UTC | #1
On 15/09/2020 09:57, Jakub Jelinek via Gcc-patches wrote:
> The following testcase is miscompiled (in particular the a and i
> initialization).  The problem is that build_special_member_call due to
> the immediate constructors (but not evaluated in constant expression mode)
> doesn't create a CALL_EXPR, but returns a TARGET_EXPR with CONSTRUCTOR
> as the initializer for it, and then expand_default_init just emits
> the returned statement, but this one doesn't have any side-effects and does
> nothing.  There is an if to handle constexpr ctors which emits an INIT_EXPR
> but constexpr ctors still show up as CALL_EXPR and need to be manually
> evaluated to constant expressions (if possible).
> 
> The following patch fixes that, though I'm not sure about several things.
> One is that the earlier if also has expr == true_exp && in the condition,
> not sure if we want it in this case or not.
> Another is that for delegating constructors, we emit two separate calls
> and build_if_in_charge them together.  Not sure if consteval could come into
> play in that case.

(Just reporting that with this patch applied, my build of LibreOffice 
using consteval, cf. 
<https://git.libreoffice.org/core/+/4b9e440c51be3e40326bc90c33ae69885bfb51e4%5E!/> 
"Turn OStringLiteral into a consteval'ed, static-refcound rtl_String", 
works fine.)
Jason Merrill Sept. 25, 2020, 8:30 p.m. UTC | #2
On 9/15/20 3:57 AM, Jakub Jelinek wrote:
> Hi!
> 
> The following testcase is miscompiled (in particular the a and i
> initialization).  The problem is that build_special_member_call due to
> the immediate constructors (but not evaluated in constant expression mode)
> doesn't create a CALL_EXPR, but returns a TARGET_EXPR with CONSTRUCTOR
> as the initializer for it,

That seems like the bug; at the end of build_over_call, after you

>        call = cxx_constant_value (call, obj_arg);

You need to build an INIT_EXPR if obj_arg isn't a dummy.

Jason
diff mbox series

Patch

--- gcc/cp/init.c.jj	2020-09-10 11:24:05.019805303 +0200
+++ gcc/cp/init.c	2020-09-14 15:06:59.467341241 +0200
@@ -1999,6 +1999,9 @@  expand_default_init (tree binfo, tree tr
 	    rval = build2 (INIT_EXPR, type, exp, e);
 	}
     }
+  else if (TREE_CODE (rval) == TARGET_EXPR
+	   && TREE_CONSTANT (TARGET_EXPR_INITIAL (rval)))
+    rval = build2 (INIT_EXPR, type, exp, rval);
 
   /* FIXME put back convert_to_void?  */
   if (TREE_SIDE_EFFECTS (rval))
--- gcc/testsuite/g++.dg/cpp2a/consteval18.C.jj	2020-09-14 15:12:50.036282784 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval18.C	2020-09-14 15:12:42.834386644 +0200
@@ -0,0 +1,26 @@ 
+// PR c++/96994
+// { dg-do run { target c++20 } }
+
+struct A { consteval A () { i = 1; } consteval A (int x) : i (x) {} int i = 0; };
+struct B { constexpr B () { i = 1; } constexpr B (int x) : i (x) {} int i = 0; };
+A const a;
+constexpr A b;
+B const c;
+A const constinit d;
+A const e = 2;
+constexpr A f = 3;
+B const g = 4;
+A const constinit h = 5;
+A i;
+B j;
+A k = 6;
+B l = 7;
+static_assert (b.i == 1 && f.i == 3);
+
+int
+main()
+{
+  if (a.i != 1 || c.i != 1 || d.i != 1 || e.i != 2 || g.i != 4 || h.i != 5
+      || i.i != 1 || j.i != 1 || k.i != 6 || l.i != 7)
+    __builtin_abort ();
+}