c++: Fix verify_ctor_sanity ICE [PR96241]
The code added in r10-6437 caused us to create a CONSTRUCTOR when we're {}-initializing an aggregate. Then we pass this new CONSTRUCTOR down to cxx_eval_constant_expression which, if the CONSTRUCTOR isn't TREE_CONSTANT or reduced_constant_expression_p, calls cxx_eval_bare_aggregate. In this case the CONSTRUCTOR wasn't reduced_constant_expression_p because for r_c_e_p a CONST_DECL isn't good enough so it returns false. So we go to cxx_eval_bare_aggregate where we crash, because ctx->ctor wasn't set up properly. So my fix is to do so. Since we're value-initializing, I'm not setting CONSTRUCTOR_NO_CLEARING. To avoid keeping a garbage constructor around, I call free_constructor in case the evaluation did not use it. gcc/cp/ChangeLog: PR c++/96241 * constexpr.c (cxx_eval_array_reference): Set up ctx->ctor if we are initializing an aggregate. Call free_constructor on the new CONSTRUCTOR if it isn't returned from cxx_eval_constant_expression. gcc/testsuite/ChangeLog: PR c++/96241 * g++.dg/cpp0x/constexpr-96241.C: New test. * g++.dg/cpp1y/constexpr-96241.C: New test.
This commit is contained in:
parent
16e2427f50
commit
0df73beea0
@ -3657,15 +3657,22 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
|
||||
initializer, it's initialized from {}. But use build_value_init
|
||||
directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */
|
||||
tree val;
|
||||
constexpr_ctx new_ctx;
|
||||
if (CP_AGGREGATE_TYPE_P (elem_type))
|
||||
{
|
||||
tree empty_ctor = build_constructor (init_list_type_node, NULL);
|
||||
val = digest_init (elem_type, empty_ctor, tf_warning_or_error);
|
||||
new_ctx = *ctx;
|
||||
new_ctx.ctor = build_constructor (elem_type, NULL);
|
||||
ctx = &new_ctx;
|
||||
}
|
||||
else
|
||||
val = build_value_init (elem_type, tf_warning_or_error);
|
||||
return cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
|
||||
overflow_p);
|
||||
t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
|
||||
overflow_p);
|
||||
if (CP_AGGREGATE_TYPE_P (elem_type) && t != ctx->ctor)
|
||||
free_constructor (ctx->ctor);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Subroutine of cxx_eval_constant_expression.
|
||||
|
18
gcc/testsuite/g++.dg/cpp0x/constexpr-96241.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/constexpr-96241.C
Normal file
@ -0,0 +1,18 @@
|
||||
// PR c++/96241
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
template <typename T, T...> struct S {};
|
||||
template <typename T, T t> using U = S<T, __integer_pack(t)...>;
|
||||
template <long... N> using f = S<unsigned long, N...>;
|
||||
template <long N> using V = U<unsigned long, N>;
|
||||
template <int N> struct A { typedef int type[N]; };
|
||||
template <int N> struct B { typename A<N>::type k; };
|
||||
template <typename T, int N, unsigned long... P>
|
||||
constexpr B<N> bar(T (&arr)[N], f<P...>) {
|
||||
return {arr[P]...};
|
||||
}
|
||||
template <typename T, int N> constexpr B<N> foo(T (&arr)[N]) {
|
||||
return bar(arr, V<N>{});
|
||||
}
|
||||
constexpr char arr[2]{};
|
||||
B<2> b = foo(arr);
|
47
gcc/testsuite/g++.dg/cpp1y/constexpr-96241.C
Normal file
47
gcc/testsuite/g++.dg/cpp1y/constexpr-96241.C
Normal file
@ -0,0 +1,47 @@
|
||||
// PR c++/96241
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
#define assert(expr) static_assert (expr, #expr)
|
||||
|
||||
enum E { o };
|
||||
|
||||
struct S {
|
||||
int e = o;
|
||||
};
|
||||
|
||||
using T = S[3];
|
||||
|
||||
constexpr struct S s[1][1][1] = { };
|
||||
assert (0 == s[0][0][0].e);
|
||||
|
||||
constexpr int
|
||||
fn0 ()
|
||||
{
|
||||
return T{}[0].e;
|
||||
}
|
||||
assert(fn0 () == 0);
|
||||
|
||||
constexpr int
|
||||
fn1 ()
|
||||
{
|
||||
S d[1];
|
||||
int x = d[0].e;
|
||||
return x;
|
||||
}
|
||||
assert(fn1 () == 0);
|
||||
|
||||
constexpr int
|
||||
fn2 ()
|
||||
{
|
||||
S d[1];
|
||||
return d[0].e;
|
||||
}
|
||||
assert(fn2 () == 0);
|
||||
|
||||
constexpr int
|
||||
fn3 ()
|
||||
{
|
||||
struct X { int e = o; } d[1]{};
|
||||
return d[0].e;
|
||||
}
|
||||
assert(fn3 () == 0);
|
Loading…
Reference in New Issue
Block a user