commit 7881846ebf44868b0a27f727064d84c271127c65 Author: Jason Merrill Date: Tue Jun 7 00:00:36 2011 -0400 PR c++/49290 gcc/ * fold-const.c (fold_indirect_ref_maybe_permissive): Split out from... (fold_indirect_ref_1): ...here. * tree.h: Declare fold_indirect_ref_maybe_permissive. gcc/cp/ * semantics.c (cxx_eval_indirect_ref): Use fold_indirect_ref_maybe_permissive. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f005f2f..d979c18 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6765,6 +6765,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, /*addr*/false, non_constant_p); tree type, sub, subtype, r; bool empty_base; + location_t loc = EXPR_LOCATION (t); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) @@ -6843,8 +6844,8 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t, /* 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) + r = fold_indirect_ref_maybe_permissive (loc, type, op0, true); + if (r) r = cxx_eval_constant_expression (call, r, allow_non_constant, addr, non_constant_p); else if (TREE_CODE (sub) == ADDR_EXPR @@ -6871,7 +6872,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/fold-const.c b/gcc/fold-const.c index 9a3f8cb..ef880fc 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -15555,14 +15555,19 @@ fold_build_cleanup_point_expr (tree type, tree expr) /* Given a pointer value OP0 and a type TYPE, return a simplified version of an indirection through OP0, or NULL_TREE if no simplification is - possible. */ + possible. If PERMISSIVE is true, allow some variation in types. */ tree -fold_indirect_ref_1 (location_t loc, tree type, tree op0) +fold_indirect_ref_maybe_permissive (location_t loc, tree type, tree op0, + bool permissive) { tree sub = op0; tree subtype; +#define SAME_TYPE(X,Y) (permissive \ + ? TYPE_MAIN_VARIANT (X) == TYPE_MAIN_VARIANT (Y) \ + : (X) == (Y)) + STRIP_NOPS (sub); subtype = TREE_TYPE (sub); if (!POINTER_TYPE_P (subtype)) @@ -15586,7 +15591,7 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) } /* *(foo *)&fooarray => fooarray[0] */ else if (TREE_CODE (optype) == ARRAY_TYPE - && type == TREE_TYPE (optype) + && SAME_TYPE (type, TREE_TYPE (optype)) && (!in_gimple_form || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) { @@ -15602,11 +15607,11 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) } /* *(foo *)&complexfoo => __real__ complexfoo */ else if (TREE_CODE (optype) == COMPLEX_TYPE - && type == TREE_TYPE (optype)) + && SAME_TYPE (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 - && type == TREE_TYPE (optype)) + && SAME_TYPE (type, TREE_TYPE (optype))) { tree part_width = TYPE_SIZE (type); tree index = bitsize_int (0); @@ -15629,7 +15634,7 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF */ if (TREE_CODE (op00type) == VECTOR_TYPE - && type == TREE_TYPE (op00type)) + && SAME_TYPE (type, TREE_TYPE (op00type))) { HOST_WIDE_INT offset = tree_low_cst (op01, 0); tree part_width = TYPE_SIZE (type); @@ -15645,7 +15650,7 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) } /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ else if (TREE_CODE (op00type) == COMPLEX_TYPE - && type == TREE_TYPE (op00type)) + && SAME_TYPE (type, TREE_TYPE (op00type))) { tree size = TYPE_SIZE_UNIT (type); if (tree_int_cst_equal (size, op01)) @@ -15653,7 +15658,7 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) } /* ((foo *)&fooarray)[1] => fooarray[1] */ else if (TREE_CODE (op00type) == ARRAY_TYPE - && type == TREE_TYPE (op00type)) + && SAME_TYPE (type, TREE_TYPE (op00type))) { tree type_domain = TYPE_DOMAIN (op00type); tree min_val = size_zero_node; @@ -15670,7 +15675,7 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) /* *(foo *)fooarrptr => (*fooarrptr)[0] */ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE - && type == TREE_TYPE (TREE_TYPE (subtype)) + && SAME_TYPE (type, TREE_TYPE (TREE_TYPE (subtype))) && (!in_gimple_form || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)) { @@ -15690,6 +15695,12 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) return NULL_TREE; } +tree +fold_indirect_ref_1 (location_t loc, tree type, tree op0) +{ + return fold_indirect_ref_maybe_permissive (loc, type, op0, false); +} + /* Builds an expression for an indirection through T, simplifying some cases. */ 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..75e6f43 --- /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 const 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); diff --git a/gcc/tree.h b/gcc/tree.h index c7338ba..5b20a07 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5172,6 +5172,7 @@ extern tree fold_single_bit_test (location_t, enum tree_code, tree, tree, tree); extern tree fold_ignored_result (tree); extern tree fold_abs_const (tree, tree); extern tree fold_indirect_ref_1 (location_t, tree, tree); +extern tree fold_indirect_ref_maybe_permissive (location_t, tree, tree, bool); extern void fold_defer_overflow_warnings (void); extern void fold_undefer_overflow_warnings (bool, const_gimple, int); extern void fold_undefer_and_ignore_overflow_warnings (void);