break;
}
}
- /* *(&A[i] p+ j) => A[i + j] */
- else if (TREE_CODE (op00) == ARRAY_REF
- && TREE_CODE (TREE_OPERAND (op00, 1)) == INTEGER_CST
- && TREE_CODE (op01) == INTEGER_CST)
- {
- tree t = fold_convert_loc (loc, ssizetype,
- TREE_OPERAND (op00, 1));
- tree nelts
- = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (op00, 0)));
- /* Don't fold an out-of-bound access. */
- if (!tree_int_cst_le (t, nelts))
- return NULL_TREE;
- /* Make sure to treat the second operand of POINTER_PLUS_EXPR
- as signed. */
- op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype,
- cp_fold_convert (ssizetype, op01),
- TYPE_SIZE_UNIT (type));
- t = size_binop_loc (loc, PLUS_EXPR, op01, t);
- return build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (op00, 0),
- t, NULL_TREE, NULL_TREE);
- }
}
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
return NULL_TREE;
}
+/* Subroutine of cxx_eval_constant_expression.
+ Attempt to reduce a POINTER_PLUS_EXPR expression T. */
+
+static tree
+cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
+ bool lval, bool *non_constant_p,
+ bool *overflow_p)
+{
+ tree op00 = TREE_OPERAND (t, 0);
+ tree op01 = TREE_OPERAND (t, 1);
+ location_t loc = EXPR_LOCATION (t);
+
+ STRIP_NOPS (op00);
+ if (TREE_CODE (op00) != ADDR_EXPR)
+ return NULL_TREE;
+
+ op00 = TREE_OPERAND (op00, 0);
+
+ /* &A[i] p+ j => &A[i + j] */
+ if (TREE_CODE (op00) == ARRAY_REF
+ && TREE_CODE (TREE_OPERAND (op00, 1)) == INTEGER_CST
+ && TREE_CODE (op01) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (op00);
+ t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (op00, 1));
+ tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (op00, 0)));
+ /* Don't fold an out-of-bound access. */
+ if (!tree_int_cst_le (t, nelts))
+ return NULL_TREE;
+ /* Make sure to treat the second operand of POINTER_PLUS_EXPR
+ as signed. */
+ op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype,
+ cp_fold_convert (ssizetype, op01),
+ TYPE_SIZE_UNIT (type));
+ t = size_binop_loc (loc, PLUS_EXPR, op01, t);
+ t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (op00, 0),
+ t, NULL_TREE, NULL_TREE);
+ t = cp_build_addr_expr (t, tf_warning_or_error);
+ return cxx_eval_constant_expression (ctx, t, lval, non_constant_p,
+ overflow_p);
+ }
+
+ return NULL_TREE;
+}
+
/* Attempt to reduce the expression T to a constant value.
On failure, issue diagnostic and return error_mark_node. */
/* FIXME unify with c_fully_fold */
break;
case POINTER_PLUS_EXPR:
+ r = cxx_eval_pointer_plus_expression (ctx, t, lval, non_constant_p,
+ overflow_p);
+ if (r)
+ break;
+ /* else fall through */
+
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
--- /dev/null
+// PR c++/65398
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+constexpr char s[] = "abc";
+
+SA((&s[0] + 0) == (&s[0] + 0));
+SA((&s[0] + 1) == (&s[1] + 0));
+SA((&s[0] + 2) == (&s[1] + 1));
+SA((&s[0] + 3) == (&s[1] + 2));
+SA((&s[0] + 4) == (&s[1] + 3));
+SA((&s[2] + 0) == (&s[0] + 2));
+SA((&s[2] + 1) == (&s[3] + 0));
+SA((&s[2] + 2) == (&s[3] + 1));
+SA((&s[4] + 0) == (&s[2] + 2));
+
+SA((&s[0] + 0) != (&s[1] + 0));
+SA((&s[0] + 2) != (&s[1] + 0));
+SA((&s[2] + 0) != (&s[2] + 1));
+SA((&s[1] + 1) != (&s[0] + 1));
+
+constexpr int l[] = { 'c', 'd', 'e', '\0' };
+
+SA((&l[0] + 0) == (&l[0] + 0));
+SA((&l[0] + 1) == (&l[1] + 0));
+SA((&l[0] + 2) == (&l[1] + 1));
+SA((&l[0] + 3) == (&l[1] + 2));
+SA((&l[0] + 4) == (&l[1] + 3));
+SA((&l[2] + 0) == (&l[0] + 2));
+SA((&l[2] + 1) == (&l[3] + 0));
+SA((&l[2] + 2) == (&l[3] + 1));
+SA((&l[4] + 0) == (&l[2] + 2));
+
+SA((&l[0] + 0) != (&l[1] + 0));
+SA((&l[0] + 2) != (&l[1] + 0));
+SA((&l[2] + 0) != (&l[2] + 1));
+SA((&l[1] + 1) != (&l[0] + 1));