diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constexpr.c | 38 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-base2.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-base2a.C | 17 |
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, ""); |