From 11f449abc6fc745486699f2f7079497d4c582d40 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 14 Jun 2011 14:15:43 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 7 + gcc/cp/semantics.c | 184 +++++++++++++++++----- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr7.C | 20 +++ 4 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr7.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d214ea2..5ae5d2d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2011-06-14 Jason Merrill + + 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 * decl2.c (cp_write_global_declarations): Process aliases; look trhough diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 481318e..55f9519 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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 don't really make sense outside of constant expression evaluation. Also 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 -cxx_eval_indirect_ref (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p) +cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) { - tree orig_op0 = TREE_OPERAND (t, 0); - 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; + tree sub, subtype; - /* Don't VERIFY_CONSTANT here. */ - if (*non_constant_p) - return t; - - type = TREE_TYPE (t); sub = op0; - r = NULL_TREE; - empty_base = false; - STRIP_NOPS (sub); subtype = TREE_TYPE (sub); gcc_assert (POINTER_TYPE_P (subtype)); @@ -6786,16 +6774,52 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, tree op = TREE_OPERAND (sub, 0); 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)) - 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 */ + 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 is represented with a NOP_EXPR. */ - else if (!addr && is_empty_class (type) + else if (is_empty_class (type) && CLASS_TYPE_P (optype) && DERIVED_FROM_P (type, optype)) { - r = op; - empty_base = true; + *empty_base = true; + return op; } /* *(foo *)&struct_with_foo_field => COMPONENT_REF */ else if (RECORD_OR_UNION_TYPE_P (optype)) @@ -6807,7 +6831,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, && (same_type_ignoring_top_level_qualifiers_p (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; } } @@ -6825,8 +6849,49 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, op00 = TREE_OPERAND (op00, 0); op00type = TREE_TYPE (op00); + /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF */ + 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 */ - if (RECORD_OR_UNION_TYPE_P (op00type)) + else if (RECORD_OR_UNION_TYPE_P (op00type)) { tree field = TYPE_FIELDS (op00type); for (; field; field = DECL_CHAIN (field)) @@ -6835,32 +6900,71 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, && (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), type))) { - r = fold_build3 (COMPONENT_REF, type, op00, + return fold_build3 (COMPONENT_REF, type, op00, field, NULL_TREE); 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. */ - if (r == NULL_TREE) - r = build_fold_indirect_ref (op0); - if (TREE_CODE (r) != INDIRECT_REF) + return NULL_TREE; +} + +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, addr, non_constant_p); - else if (TREE_CODE (sub) == ADDR_EXPR - || TREE_CODE (sub) == POINTER_PLUS_EXPR) + else { - gcc_assert (!same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); - /* FIXME Mike Miller wants this to be OK. */ - if (!allow_non_constant) - error ("accessing value of %qE through a %qT glvalue in a " - "constant expression", build_fold_indirect_ref (sub), - TREE_TYPE (t)); - *non_constant_p = true; - return t; + tree sub = op0; + STRIP_NOPS (sub); + if (TREE_CODE (sub) == ADDR_EXPR + || TREE_CODE (sub) == POINTER_PLUS_EXPR) + { + gcc_assert (!same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); + /* FIXME Mike Miller wants this to be OK. */ + if (!allow_non_constant) + error ("accessing value of %qE through a %qT glvalue in a " + "constant expression", build_fold_indirect_ref (sub), + TREE_TYPE (t)); + *non_constant_p = true; + return t; + } } /* If we're pulling out the value of an empty base, make sure @@ -6873,7 +6977,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, TREE_CONSTANT (r) = true; } - if (TREE_CODE (r) == INDIRECT_REF && TREE_OPERAND (r, 0) == orig_op0) + if (r == NULL_TREE) return t; return r; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c450a22..8b324e3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-06-14 Jason Merrill + + * g++.dg/cpp0x/constexpr-array-ptr7.C: New. + 2011-06-14 Jakub Jelinek PR fortran/49103 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr7.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr7.C new file mode 100644 index 0000000..44775c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr7.C @@ -0,0 +1,20 @@ +// 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); -- 2.7.4