Commit 37244b21 by Patrick Palka

c++: Fix constexpr evaluation of self-modifying CONSTRUCTORs [PR94219]

This PR reveals that cxx_eval_bare_aggregate and cxx_eval_store_expression do
not anticipate that a constructor element's initializer could mutate the
underlying CONSTRUCTOR.  Evaluation of the initializer could add new elements to
the underlying CONSTRUCTOR, thereby potentially invalidating any pointers to
or assumptions about the CONSTRUCTOR's elements, and so these routines should be
prepared for that.

To fix this problem, this patch makes cxx_eval_bare_aggregate and
cxx_eval_store_expression recompute the constructor_elt pointers through which
we're assigning, after it evaluates the initializer.  Care is taken to to not
slow down the common case where the initializer does not modify the underlying
CONSTRUCTOR.

gcc/cp/ChangeLog:

	PR c++/94219
	PR c++/94205
	* constexpr.c (get_or_insert_ctor_field): Split out (while adding
	support for VECTOR_TYPEs, and optimizations for the common case)
	from ...
	(cxx_eval_store_expression): ... here.  Rename local variable
	'changed_active_union_member_p' to 'activated_union_member_p'.  Record
	the sequence of indexes into 'indexes' that yields the subobject we're
	assigning to.  Record the integer offsets of the constructor indexes
	we're assigning through into 'index_pos_hints'.  After evaluating the
	initializer of the store expression, recompute 'valp' using 'indexes'
	and using 'index_pos_hints' as hints.
	(cxx_eval_bare_aggregate): Tweak comments.  Use get_or_insert_ctor_field
	to recompute the constructor_elt pointer we're assigning through after
	evaluating each initializer.

gcc/testsuite/ChangeLog:

	PR c++/94219
	PR c++/94205
	* g++.dg/cpp1y/constexpr-nsdmi3.C: New test.
	* g++.dg/cpp1y/constexpr-nsdmi4.C: New test.
	* g++.dg/cpp1y/constexpr-nsdmi5.C: New test.
	* g++.dg/cpp1z/lambda-this5.C: New test.
parent 21e28527
2020-04-04 Patrick Palka <ppalka@redhat.com>
PR c++/94219
PR c++/94205
* constexpr.c (get_or_insert_ctor_field): Split out (while adding
support for VECTOR_TYPEs, and optimizations for the common case)
from ...
(cxx_eval_store_expression): ... here. Rename local variable
'changed_active_union_member_p' to 'activated_union_member_p'. Record
the sequence of indexes into 'indexes' that yields the subobject we're
assigning to. Record the integer offsets of the constructor indexes
we're assigning through into 'index_pos_hints'. After evaluating the
initializer of the store expression, recompute 'valp' using 'indexes'
and using 'index_pos_hints' as hints.
(cxx_eval_bare_aggregate): Tweak comments. Use get_or_insert_ctor_field
to recompute the constructor_elt pointer we're assigning through after
evaluating each initializer.
2020-04-04 Jason Merrill <jason@redhat.com>
PR c++/67825
......
2020-04-04 Patrick Palka <ppalka@redhat.com>
PR c++/94219
PR c++/94205
* g++.dg/cpp1y/constexpr-nsdmi3.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi4.C: New test.
* g++.dg/cpp1y/constexpr-nsdmi5.C: New test.
* g++.dg/cpp1z/lambda-this5.C: New test.
2020-04-04 Jan Hubicka <hubicka@ucw.cz>
PR ipa/93940
......
// PR c++/94205
// { dg-do compile { target c++14 } }
struct S
{
struct A
{
S *p;
constexpr A(S* p): p(p) {}
constexpr operator int() { p->a = 5; return 6; }
};
int a = A(this);
};
constexpr S s = {};
#define SA(X) static_assert((X),#X)
SA(s.a == 6);
// PR c++/94219
// { dg-do compile { target c++14 } }
struct A { long x; };
struct U;
constexpr A foo(U *up);
struct U {
A a = foo(this); int y;
};
constexpr A foo(U *up) {
up->y = 11;
return {42};
}
extern constexpr U u = {};
static_assert(u.y == 11, "");
static_assert(u.a.x == 42, "");
// PR c++/94219
// { dg-do compile { target c++14 } }
struct A { long x; };
struct U;
constexpr A foo(U *up);
struct U {
U() = default;
int y; A a = foo(this);
};
constexpr A foo(U *up) {
up->y = 11;
return {42};
}
extern constexpr U u = {};
static_assert(u.y == 11, "");
static_assert(u.a.x == 42, "");
// PR c++/94205
// { dg-do compile { target c++17 } }
struct S
{
int a = [this] { this->a = 5; return 6; } ();
};
constexpr S s = {};
static_assert(s.a == 6);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment