return NULL_TREE;
}
+/* Try to fold expressions like
+ (struct S *) (&a[0].D.2378 + 12)
+ into
+ &MEM <struct T> [(void *)&a + 12B]
+ This is something normally done by gimple_fold_stmt_to_constant_1
+ on GIMPLE, but is undesirable on GENERIC if we are e.g. going to
+ dereference the address because some details are lost.
+ For pointer comparisons we want such folding though so that
+ match.pd address_compare optimization works. */
+
+static tree
+cxx_maybe_fold_addr_pointer_plus (tree t)
+{
+ while (CONVERT_EXPR_P (t)
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0))))
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != POINTER_PLUS_EXPR)
+ return NULL_TREE;
+ tree op0 = TREE_OPERAND (t, 0);
+ tree op1 = TREE_OPERAND (t, 1);
+ if (TREE_CODE (op1) != INTEGER_CST)
+ return NULL_TREE;
+ while (CONVERT_EXPR_P (op0)
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0))))
+ op0 = TREE_OPERAND (op0, 0);
+ if (TREE_CODE (op0) != ADDR_EXPR)
+ return NULL_TREE;
+ op1 = fold_convert (ptr_type_node, op1);
+ tree r = fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (op0)), op0, op1);
+ return build1_loc (EXPR_LOCATION (t), ADDR_EXPR, TREE_TYPE (op0), r);
+}
+
/* Subroutine of cxx_eval_constant_expression.
Like cxx_eval_unary_expression, except for binary expressions. */
else if (TREE_CODE (rhs) == PTRMEM_CST)
rhs = cplus_expand_constant (rhs);
}
+ if (r == NULL_TREE
+ && TREE_CODE_CLASS (code) == tcc_comparison
+ && POINTER_TYPE_P (TREE_TYPE (lhs)))
+ {
+ if (tree lhso = cxx_maybe_fold_addr_pointer_plus (lhs))
+ lhs = fold_convert (TREE_TYPE (lhs), lhso);
+ if (tree rhso = cxx_maybe_fold_addr_pointer_plus (rhs))
+ rhs = fold_convert (TREE_TYPE (rhs), rhso);
+ }
if (code == POINTER_PLUS_EXPR && !*non_constant_p
&& integer_zerop (lhs) && !integer_zerop (rhs))
{
--- /dev/null
+// PR c++/89074
+// { dg-do compile { target c++17 } }
+
+struct S { int s; };
+struct T : public S { };
+struct U : public T { };
+
+constexpr bool
+foo ()
+{
+ U a[] = { 1, 2, 3, 4 };
+ U b[] = { 5, 6, 7, 8 };
+ T *c = (T *) a + 1;
+ S *d = (S *) c + 2;
+ S *e = (S *) b + 1;
+
+ if (a + 0 == b + 0)
+ return false;
+
+ if (d == e)
+ return false;
+
+ return true;
+}
+
+static_assert (foo (), "");