diff options
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 117 |
1 files changed, 82 insertions, 35 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index aedd004..ca259cb 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2183,9 +2183,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, lval, non_constant_p, overflow_p); tree index, oldidx; - HOST_WIDE_INT i; - tree elem_type; - unsigned len, elem_nchars = 1; + HOST_WIDE_INT i = 0; + tree elem_type = NULL_TREE; + unsigned len = 0, elem_nchars = 1; if (*non_constant_p) return t; oldidx = TREE_OPERAND (t, 1); @@ -2193,39 +2193,38 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, false, non_constant_p, overflow_p); VERIFY_CONSTANT (index); - if (lval && ary == oldary && index == oldidx) - return t; - else if (lval) - return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); - elem_type = TREE_TYPE (TREE_TYPE (ary)); - if (TREE_CODE (ary) == VIEW_CONVERT_EXPR - && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0))) - && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0)))) - ary = TREE_OPERAND (ary, 0); - if (TREE_CODE (ary) == CONSTRUCTOR) - len = CONSTRUCTOR_NELTS (ary); - else if (TREE_CODE (ary) == STRING_CST) + if (!lval) { - elem_nchars = (TYPE_PRECISION (elem_type) - / TYPE_PRECISION (char_type_node)); - len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; - } - else if (TREE_CODE (ary) == VECTOR_CST) - len = VECTOR_CST_NELTS (ary); - else - { - /* We can't do anything with other tree codes, so use - VERIFY_CONSTANT to complain and fail. */ - VERIFY_CONSTANT (ary); - gcc_unreachable (); - } + elem_type = TREE_TYPE (TREE_TYPE (ary)); + if (TREE_CODE (ary) == VIEW_CONVERT_EXPR + && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0))) + && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0)))) + ary = TREE_OPERAND (ary, 0); + if (TREE_CODE (ary) == CONSTRUCTOR) + len = CONSTRUCTOR_NELTS (ary); + else if (TREE_CODE (ary) == STRING_CST) + { + elem_nchars = (TYPE_PRECISION (elem_type) + / TYPE_PRECISION (char_type_node)); + len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; + } + else if (TREE_CODE (ary) == VECTOR_CST) + len = VECTOR_CST_NELTS (ary); + else + { + /* We can't do anything with other tree codes, so use + VERIFY_CONSTANT to complain and fail. */ + VERIFY_CONSTANT (ary); + gcc_unreachable (); + } - if (!tree_fits_shwi_p (index) - || (i = tree_to_shwi (index)) < 0) - { - diag_array_subscript (ctx, ary, index); - *non_constant_p = true; - return t; + if (!tree_fits_shwi_p (index) + || (i = tree_to_shwi (index)) < 0) + { + diag_array_subscript (ctx, ary, index); + *non_constant_p = true; + return t; + } } tree nelts; @@ -2240,13 +2239,20 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p, overflow_p); VERIFY_CONSTANT (nelts); - if (!tree_int_cst_lt (index, nelts)) + if (lval + ? !tree_int_cst_le (index, nelts) + : !tree_int_cst_lt (index, nelts)) { diag_array_subscript (ctx, ary, index); *non_constant_p = true; return t; } + if (lval && ary == oldary && index == oldidx) + return t; + else if (lval) + return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); + bool found; if (TREE_CODE (ary) == CONSTRUCTOR) { @@ -3281,6 +3287,47 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (*non_constant_p) return t; + /* cxx_eval_array_reference for lval = true allows references one past + end of array, because it does not know if it is just taking address + (which is valid), or actual dereference. Here we know it is + a dereference, so diagnose it here. */ + for (tree probe = target; probe; ) + { + switch (TREE_CODE (probe)) + { + case ARRAY_REF: + tree nelts, ary; + ary = TREE_OPERAND (probe, 0); + if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE) + nelts = array_type_nelts_top (TREE_TYPE (ary)); + else if (VECTOR_TYPE_P (TREE_TYPE (ary))) + nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary))); + else + gcc_unreachable (); + nelts = cxx_eval_constant_expression (ctx, nelts, false, + non_constant_p, overflow_p); + VERIFY_CONSTANT (nelts); + gcc_assert (TREE_CODE (nelts) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (probe, 1)) == INTEGER_CST); + if (wi::eq_p (TREE_OPERAND (probe, 1), nelts)) + { + diag_array_subscript (ctx, ary, TREE_OPERAND (probe, 1)); + *non_constant_p = true; + return t; + } + /* FALLTHRU */ + + case BIT_FIELD_REF: + case COMPONENT_REF: + probe = TREE_OPERAND (probe, 0); + continue; + + default: + probe = NULL_TREE; + continue; + } + } + if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type)) { /* For initialization of an empty base, the original target will be |