aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/constexpr.c38
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-base2.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-base2a.C17
3 files changed, 58 insertions, 12 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index af6a4a7..d0da4a7 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5215,6 +5215,25 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
if (!INDIRECT_TYPE_P (subtype))
return NULL_TREE;
+ /* Canonicalizes the given OBJ/OFF pair by iteratively absorbing
+ the innermost component into the offset until it would make the
+ offset positive, so that cxx_fold_indirect_ref_1 can identify
+ more folding opportunities. */
+ auto canonicalize_obj_off = [] (tree& obj, tree& off) {
+ while (TREE_CODE (obj) == COMPONENT_REF
+ && (tree_int_cst_sign_bit (off) || integer_zerop (off)))
+ {
+ tree field = TREE_OPERAND (obj, 1);
+ tree pos = byte_position (field);
+ if (integer_zerop (off) && integer_nonzerop (pos))
+ /* If the offset is already 0, keep going as long as the
+ component is at position 0. */
+ break;
+ off = int_const_binop (PLUS_EXPR, off, pos);
+ obj = TREE_OPERAND (obj, 0);
+ }
+ };
+
if (TREE_CODE (sub) == ADDR_EXPR)
{
tree op = TREE_OPERAND (sub, 0);
@@ -5233,7 +5252,12 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
return op;
}
else
- return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base);
+ {
+ tree off = integer_zero_node;
+ canonicalize_obj_off (op, off);
+ gcc_assert (integer_zerop (off));
+ return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base);
+ }
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
&& tree_fits_uhwi_p (TREE_OPERAND (sub, 1)))
@@ -5245,17 +5269,7 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
if (TREE_CODE (op00) == ADDR_EXPR)
{
tree obj = TREE_OPERAND (op00, 0);
- while (TREE_CODE (obj) == COMPONENT_REF
- && tree_int_cst_sign_bit (off))
- {
- /* Canonicalize this object/offset pair by iteratively absorbing
- the innermost component into the offset until the offset is
- nonnegative, so that cxx_fold_indirect_ref_1 can identify
- more folding opportunities. */
- tree field = TREE_OPERAND (obj, 1);
- off = int_const_binop (PLUS_EXPR, off, byte_position (field));
- obj = TREE_OPERAND (obj, 0);
- }
+ canonicalize_obj_off (obj, off);
return cxx_fold_indirect_ref_1 (ctx, loc, type, obj,
tree_to_uhwi (off), empty_base);
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-base2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-base2.C
new file mode 100644
index 0000000..a267c14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-base2.C
@@ -0,0 +1,15 @@
+// PR c++/103879
+// { dg-do compile { target c++14 } }
+
+struct A { int n = 42; };
+struct B : A { };
+struct C { B b; };
+
+constexpr int f() {
+ C c;
+ A& a = static_cast<A&>(c.b);
+ B& b = static_cast<B&>(a);
+ return b.n;
+}
+
+static_assert(f() == 42, "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-base2a.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-base2a.C
new file mode 100644
index 0000000..9eb72b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-base2a.C
@@ -0,0 +1,17 @@
+// PR c++/103879
+// { dg-do compile { target c++14 } }
+
+struct A { int n = 42; };
+struct Y { int m = 0; };
+struct X : Y, A { };
+struct B : X { };
+struct C { B b; };
+
+constexpr int f() {
+ C c;
+ A& a = static_cast<A&>(c.b);
+ B& b = static_cast<B&>(a);
+ return b.n;
+}
+
+static_assert(f() == 42, "");