Commit 11f449ab by Jason Merrill Committed by Jason Merrill

re PR c++/49290 ([C++0x] ICE in in cxx_eval_indirect_ref, at cp/semantics.c:6795)

	PR c++/49290
	* semantics.c (cxx_fold_indirect_ref): Local, more permissive copy
	of fold_indirect_ref_1.
	(cxx_eval_indirect_ref): Use it.

From-SVN: r175041
parent 870c3cf8
2011-06-14 Jason Merrill <jason@redhat.com>
PR c++/49290
* semantics.c (cxx_fold_indirect_ref): Local, more permissive copy
of fold_indirect_ref_1.
(cxx_eval_indirect_ref): Use it.
2011-06-11 Jan Hubicka <jh@suse.cz> 2011-06-11 Jan Hubicka <jh@suse.cz>
* decl2.c (cp_write_global_declarations): Process aliases; look trhough * decl2.c (cp_write_global_declarations): Process aliases; look trhough
......
...@@ -6755,28 +6755,16 @@ cxx_eval_vec_init (const constexpr_call *call, tree t, ...@@ -6755,28 +6755,16 @@ cxx_eval_vec_init (const constexpr_call *call, tree t,
because we're dealing with things like ADDR_EXPR of INTEGER_CST which because we're dealing with things like ADDR_EXPR of INTEGER_CST which
don't really make sense outside of constant expression evaluation. Also don't really make sense outside of constant expression evaluation. Also
we want to allow folding to COMPONENT_REF, which could cause trouble we want to allow folding to COMPONENT_REF, which could cause trouble
with TBAA in fold_indirect_ref_1. */ with TBAA in fold_indirect_ref_1.
Try to keep this function synced with fold_indirect_ref_1. */
static tree static tree
cxx_eval_indirect_ref (const constexpr_call *call, tree t, cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
bool allow_non_constant, bool addr,
bool *non_constant_p)
{ {
tree orig_op0 = TREE_OPERAND (t, 0); tree sub, subtype;
tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant,
/*addr*/false, non_constant_p);
tree type, sub, subtype, r;
bool empty_base;
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
type = TREE_TYPE (t);
sub = op0; sub = op0;
r = NULL_TREE;
empty_base = false;
STRIP_NOPS (sub); STRIP_NOPS (sub);
subtype = TREE_TYPE (sub); subtype = TREE_TYPE (sub);
gcc_assert (POINTER_TYPE_P (subtype)); gcc_assert (POINTER_TYPE_P (subtype));
...@@ -6786,16 +6774,52 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6786,16 +6774,52 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
tree op = TREE_OPERAND (sub, 0); tree op = TREE_OPERAND (sub, 0);
tree optype = TREE_TYPE (op); tree optype = TREE_TYPE (op);
/* *&CONST_DECL -> to the value of the const decl. */
if (TREE_CODE (op) == CONST_DECL)
return DECL_INITIAL (op);
/* *&p => p; make sure to handle *&"str"[cst] here. */
if (same_type_ignoring_top_level_qualifiers_p (optype, type)) if (same_type_ignoring_top_level_qualifiers_p (optype, type))
r = op; {
tree fop = fold_read_from_constant_string (op);
if (fop)
return fop;
else
return op;
}
/* *(foo *)&fooarray => fooarray[0] */
else if (TREE_CODE (optype) == ARRAY_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (optype))))
{
tree type_domain = TYPE_DOMAIN (optype);
tree min_val = size_zero_node;
if (type_domain && TYPE_MIN_VALUE (type_domain))
min_val = TYPE_MIN_VALUE (type_domain);
return build4_loc (loc, ARRAY_REF, type, op, min_val,
NULL_TREE, NULL_TREE);
}
/* *(foo *)&complexfoo => __real__ complexfoo */
else if (TREE_CODE (optype) == COMPLEX_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (optype))))
return fold_build1_loc (loc, REALPART_EXPR, type, op);
/* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
else if (TREE_CODE (optype) == VECTOR_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (optype))))
{
tree part_width = TYPE_SIZE (type);
tree index = bitsize_int (0);
return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, index);
}
/* Also handle conversion to an empty base class, which /* Also handle conversion to an empty base class, which
is represented with a NOP_EXPR. */ is represented with a NOP_EXPR. */
else if (!addr && is_empty_class (type) else if (is_empty_class (type)
&& CLASS_TYPE_P (optype) && CLASS_TYPE_P (optype)
&& DERIVED_FROM_P (type, optype)) && DERIVED_FROM_P (type, optype))
{ {
r = op; *empty_base = true;
empty_base = true; return op;
} }
/* *(foo *)&struct_with_foo_field => COMPONENT_REF */ /* *(foo *)&struct_with_foo_field => COMPONENT_REF */
else if (RECORD_OR_UNION_TYPE_P (optype)) else if (RECORD_OR_UNION_TYPE_P (optype))
...@@ -6807,7 +6831,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6807,7 +6831,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
&& (same_type_ignoring_top_level_qualifiers_p && (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (field), type))) (TREE_TYPE (field), type)))
{ {
r = fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE);
break; break;
} }
} }
...@@ -6825,8 +6849,49 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6825,8 +6849,49 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
op00 = TREE_OPERAND (op00, 0); op00 = TREE_OPERAND (op00, 0);
op00type = TREE_TYPE (op00); op00type = TREE_TYPE (op00);
/* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
if (TREE_CODE (op00type) == VECTOR_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (op00type))))
{
HOST_WIDE_INT offset = tree_low_cst (op01, 0);
tree part_width = TYPE_SIZE (type);
unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT;
unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
tree index = bitsize_int (indexi);
if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (op00type))
return fold_build3_loc (loc,
BIT_FIELD_REF, type, op00,
part_width, index);
}
/* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
else if (TREE_CODE (op00type) == COMPLEX_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (op00type))))
{
tree size = TYPE_SIZE_UNIT (type);
if (tree_int_cst_equal (size, op01))
return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
}
/* ((foo *)&fooarray)[1] => fooarray[1] */
else if (TREE_CODE (op00type) == ARRAY_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (op00type))))
{
tree type_domain = TYPE_DOMAIN (op00type);
tree min_val = size_zero_node;
if (type_domain && TYPE_MIN_VALUE (type_domain))
min_val = TYPE_MIN_VALUE (type_domain);
op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01,
TYPE_SIZE_UNIT (type));
op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val);
return build4_loc (loc, ARRAY_REF, type, op00, op01,
NULL_TREE, NULL_TREE);
}
/* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */ /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */
if (RECORD_OR_UNION_TYPE_P (op00type)) else if (RECORD_OR_UNION_TYPE_P (op00type))
{ {
tree field = TYPE_FIELDS (op00type); tree field = TYPE_FIELDS (op00type);
for (; field; field = DECL_CHAIN (field)) for (; field; field = DECL_CHAIN (field))
...@@ -6835,21 +6900,59 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6835,21 +6900,59 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
&& (same_type_ignoring_top_level_qualifiers_p && (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (field), type))) (TREE_TYPE (field), type)))
{ {
r = fold_build3 (COMPONENT_REF, type, op00, return fold_build3 (COMPONENT_REF, type, op00,
field, NULL_TREE); field, NULL_TREE);
break; break;
} }
} }
} }
} }
/* *(foo *)fooarrptreturn> (*fooarrptr)[0] */
else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (TREE_TYPE (subtype)))))
{
tree type_domain;
tree min_val = size_zero_node;
sub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL);
if (!sub)
sub = build1_loc (loc, INDIRECT_REF, TREE_TYPE (subtype), sub);
type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
if (type_domain && TYPE_MIN_VALUE (type_domain))
min_val = TYPE_MIN_VALUE (type_domain);
return build4_loc (loc, ARRAY_REF, type, sub, min_val, NULL_TREE,
NULL_TREE);
}
/* Let build_fold_indirect_ref handle the cases it does fine with. */ return NULL_TREE;
if (r == NULL_TREE) }
r = build_fold_indirect_ref (op0);
if (TREE_CODE (r) != INDIRECT_REF) static tree
cxx_eval_indirect_ref (const constexpr_call *call, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p)
{
tree orig_op0 = TREE_OPERAND (t, 0);
tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant,
/*addr*/false, non_constant_p);
bool empty_base = false;
tree r;
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0,
&empty_base);
if (r)
r = cxx_eval_constant_expression (call, r, allow_non_constant, r = cxx_eval_constant_expression (call, r, allow_non_constant,
addr, non_constant_p); addr, non_constant_p);
else if (TREE_CODE (sub) == ADDR_EXPR else
{
tree sub = op0;
STRIP_NOPS (sub);
if (TREE_CODE (sub) == ADDR_EXPR
|| TREE_CODE (sub) == POINTER_PLUS_EXPR) || TREE_CODE (sub) == POINTER_PLUS_EXPR)
{ {
gcc_assert (!same_type_ignoring_top_level_qualifiers_p gcc_assert (!same_type_ignoring_top_level_qualifiers_p
...@@ -6862,6 +6965,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6862,6 +6965,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
*non_constant_p = true; *non_constant_p = true;
return t; return t;
} }
}
/* If we're pulling out the value of an empty base, make sure /* If we're pulling out the value of an empty base, make sure
that the whole object is constant and then return an empty that the whole object is constant and then return an empty
...@@ -6873,7 +6977,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, ...@@ -6873,7 +6977,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
TREE_CONSTANT (r) = true; TREE_CONSTANT (r) = true;
} }
if (TREE_CODE (r) == INDIRECT_REF && TREE_OPERAND (r, 0) == orig_op0) if (r == NULL_TREE)
return t; return t;
return r; return r;
} }
......
2011-06-14 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/constexpr-array-ptr7.C: New.
2011-06-14 Jakub Jelinek <jakub@redhat.com> 2011-06-14 Jakub Jelinek <jakub@redhat.com>
PR fortran/49103 PR fortran/49103
......
// PR c++/49290
// { dg-options -std=c++0x }
typedef unsigned T;
struct S
{
constexpr T foo (void);
unsigned s1[16];
};
constexpr T
S::foo ()
{
return *(T *) (s1 + 10);
}
constexpr S s = { 0,1,2,3,4,5,6,7,8,9,10 };
#define SA(X) static_assert ((X), #X)
SA(s.foo() == 10);
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