c++: Delegating constructor in constexpr init [PR94772]
In the first testcase below, the call to the target constructor foo{} from foo's delegating constructor is encoded as the INIT_EXPR *(struct foo *) this = AGGR_INIT_EXPR <4, __ct_comp, D.2140, ...>; During initialization of the variable 'bar', we prematurely set TREE_READONLY on bar's CONSTRUCTOR in two places before the outer delegating constructor has returned: first, at the end of cxx_eval_call_expression after evaluating the RHS of the above INIT_EXPR, and second, at the end of cxx_eval_store_expression after having finished evaluating the above INIT_EXPR. This then prevents the rest of the outer delegating constructor from mutating 'bar'. This (hopefully minimally risky) patch makes cxx_eval_call_expression refrain from setting TREE_READONLY when evaluating the target constructor of a delegating constructor. It also makes cxx_eval_store_expression refrain from setting TREE_READONLY when the object being initialized is "*this', on the basis that it should be the responsibility of the routine that set 'this' in the first place to set the object's TREE_READONLY appropriately. gcc/cp/ChangeLog: PR c++/94772 * constexpr.c (cxx_eval_call_expression): Don't set new_obj if we're evaluating the target constructor of a delegating constructor. (cxx_eval_store_expression): Don't set TREE_READONLY if the LHS of the INIT_EXPR is '*this'. gcc/testsuite/ChangeLog: PR c++/94772 * g++.dg/cpp1y/constexpr-tracking-const23.C: New test. * g++.dg/cpp1y/constexpr-tracking-const24.C: New test. * g++.dg/cpp1y/constexpr-tracking-const25.C: New test.
This commit is contained in:
parent
067ebf8413
commit
64da1b761d
@ -1,3 +1,11 @@
|
||||
2020-04-27 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
PR c++/94772
|
||||
* constexpr.c (cxx_eval_call_expression): Don't set new_obj if we're
|
||||
evaluating the target constructor of a delegating constructor.
|
||||
(cxx_eval_store_expression): Don't set TREE_READONLY if the LHS of the
|
||||
INIT_EXPR is '*this'.
|
||||
|
||||
2020-04-26 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/90320
|
||||
|
@ -2371,6 +2371,21 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
|
||||
STRIP_NOPS (new_obj);
|
||||
if (TREE_CODE (new_obj) == ADDR_EXPR)
|
||||
new_obj = TREE_OPERAND (new_obj, 0);
|
||||
|
||||
if (ctx->call && ctx->call->fundef
|
||||
&& DECL_CONSTRUCTOR_P (ctx->call->fundef->decl))
|
||||
{
|
||||
tree cur_obj = TREE_VEC_ELT (ctx->call->bindings, 0);
|
||||
STRIP_NOPS (cur_obj);
|
||||
if (TREE_CODE (cur_obj) == ADDR_EXPR)
|
||||
cur_obj = TREE_OPERAND (cur_obj, 0);
|
||||
if (new_obj == cur_obj)
|
||||
/* We're calling the target constructor of a delegating
|
||||
constructor, or accessing a base subobject through a
|
||||
NOP_EXPR as part of a call to a base constructor, so
|
||||
there is no new (sub)object. */
|
||||
new_obj = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
tree result = NULL_TREE;
|
||||
@ -4950,7 +4965,18 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
|
||||
if (TREE_CODE (t) == INIT_EXPR
|
||||
&& TREE_CODE (*valp) == CONSTRUCTOR
|
||||
&& TYPE_READONLY (type))
|
||||
TREE_READONLY (*valp) = true;
|
||||
{
|
||||
if (INDIRECT_REF_P (target)
|
||||
&& (is_this_parameter
|
||||
(tree_strip_nop_conversions (TREE_OPERAND (target, 0)))))
|
||||
/* We've just initialized '*this' (perhaps via the target
|
||||
constructor of a delegating constructor). Leave it up to the
|
||||
caller that set 'this' to set TREE_READONLY appropriately. */
|
||||
gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
|
||||
(TREE_TYPE (target), type));
|
||||
else
|
||||
TREE_READONLY (*valp) = true;
|
||||
}
|
||||
|
||||
/* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
|
||||
CONSTRUCTORs, if any. */
|
||||
|
@ -1,3 +1,10 @@
|
||||
2020-04-27 Patrick Palka <ppalka@redhat.com>
|
||||
|
||||
PR c++/94772
|
||||
* g++.dg/cpp1y/constexpr-tracking-const23.C: New test.
|
||||
* g++.dg/cpp1y/constexpr-tracking-const24.C: New test.
|
||||
* g++.dg/cpp1y/constexpr-tracking-const25.C: New test.
|
||||
|
||||
2020-04-27 Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
|
||||
PR target/94697
|
||||
|
21
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const23.C
Normal file
21
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const23.C
Normal file
@ -0,0 +1,21 @@
|
||||
// PR c++/94772
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct foo
|
||||
{
|
||||
int x{};
|
||||
|
||||
constexpr foo() noexcept = default;
|
||||
|
||||
constexpr foo(int a) : foo{}
|
||||
{ x = -a; }
|
||||
|
||||
constexpr foo(int a, int b) : foo{a}
|
||||
{ x += a + b; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr foo bar{1, 2};
|
||||
static_assert(bar.x == 2, "");
|
||||
}
|
26
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const24.C
Normal file
26
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const24.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR c++/94772
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct base
|
||||
{
|
||||
base() = default;
|
||||
|
||||
constexpr base(int) : base{} { }
|
||||
};
|
||||
|
||||
struct foo : base
|
||||
{
|
||||
int x{};
|
||||
|
||||
constexpr foo(int a) : base{a}
|
||||
{ x = -a; }
|
||||
|
||||
constexpr foo(int a, int b) : foo{a}
|
||||
{ x += a + b; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr foo bar{1, 2};
|
||||
static_assert(bar.x == 2, "");
|
||||
}
|
66
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const25.C
Normal file
66
gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const25.C
Normal file
@ -0,0 +1,66 @@
|
||||
// PR c++/94772
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
template<int>
|
||||
struct base
|
||||
{
|
||||
int y{};
|
||||
|
||||
base() = default;
|
||||
|
||||
constexpr base(int a) : base{}
|
||||
{ y = a; }
|
||||
};
|
||||
|
||||
struct foo : base<1>, base<2>
|
||||
{
|
||||
int x{};
|
||||
|
||||
constexpr foo() : base<2>{}
|
||||
{
|
||||
++x; --x;
|
||||
++base<1>::y;
|
||||
++base<2>::y;
|
||||
}
|
||||
|
||||
constexpr foo(int a) : base<2>{a}
|
||||
{
|
||||
x = -base<2>::y;
|
||||
++base<1>::y;
|
||||
++base<2>::y;
|
||||
}
|
||||
|
||||
constexpr foo(int a, int b) : foo{a}
|
||||
{
|
||||
x += a + b;
|
||||
++base<1>::y;
|
||||
++base<2>::y;
|
||||
}
|
||||
|
||||
constexpr foo(int a, int b, int c) : base<1>{a}
|
||||
{
|
||||
x += a + b + c;
|
||||
++base<1>::y;
|
||||
++base<2>::y;
|
||||
}
|
||||
};
|
||||
|
||||
#define SA(X) static_assert(X, #X)
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr foo bar1{1, 2};
|
||||
SA( bar1.x == 2 );
|
||||
SA( bar1.base<1>::y == 2 );
|
||||
SA( bar1.base<2>::y == 3 );
|
||||
|
||||
constexpr foo bar2{1, 2, 3};
|
||||
SA( bar2.x == 6 );
|
||||
SA( bar2.base<1>::y == 2 );
|
||||
SA( bar2.base<2>::y == 1 );
|
||||
|
||||
constexpr foo bar3{};
|
||||
SA( bar3.x == 0 );
|
||||
SA( bar3.base<1>::y == 1 );
|
||||
SA( bar3.base<2>::y == 1 );
|
||||
}
|
Loading…
Reference in New Issue
Block a user