Our beloved condition combining code to BIT_FIELD_REFs miscompiles the testcase because it relies on operand_equal_p to detect equal bases. For some reason that very same operand_equal_p is treating any dereference of a pointer based on the same pointer or decl the same - idependent on the actual type used for the access (in this case, two different sized structs). Weirdly it already checks alignment...
The following patch makes operand_equal_p behave and more in line with what it does for MEM_REF handling. Bootstrap & regtest running on x86_64-unknown-linux-gnu. Richard. 2019-03-14 Richard Biener <rguent...@suse.de> PR middle-end/89698 * fold-const.c (operand_equal_p): For INDIRECT_REF check that the access types are similar. * g++.dg/torture/pr89698.C: New testcase. Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 269641) +++ gcc/fold-const.c (working copy) @@ -3220,10 +3220,16 @@ operand_equal_p (const_tree arg0, const_ switch (TREE_CODE (arg0)) { case INDIRECT_REF: - if (!(flags & OEP_ADDRESS_OF) - && (TYPE_ALIGN (TREE_TYPE (arg0)) - != TYPE_ALIGN (TREE_TYPE (arg1)))) - return 0; + if (!(flags & OEP_ADDRESS_OF)) + { + if (TYPE_ALIGN (TREE_TYPE (arg0)) + != TYPE_ALIGN (TREE_TYPE (arg1))) + return 0; + /* Verify that the access types are compatible. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg0)) + != TYPE_MAIN_VARIANT (TREE_TYPE (arg1))) + return 0; + } flags &= ~OEP_ADDRESS_OF; return OP_SAME (0); Index: gcc/testsuite/g++.dg/torture/pr89698.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr89698.C (nonexistent) +++ gcc/testsuite/g++.dg/torture/pr89698.C (working copy) @@ -0,0 +1,28 @@ +/* { dg-do run } */ + +extern "C" void abort (void); + +class A { + virtual void f(){}; +public: + int x; + A(int in): x(in) {}; +}; + +class B: public A { +public: + int y; + B(int in):A(in-1), y(in) {}; +}; + +int test(void) +{ + int res; + B b(2); + A* bp = &b; + void* vp = dynamic_cast<void*>(bp); + if (((A*)vp)->x == 1 && ((B*)vp)->y == 2) + return 1; + return 0; +} +int main() { if (test() != 1) abort (); return 0; }