I had an interesting time tracking down some of the problems with this code. Hopefully I've sussed out now how this stuff works.
We've got struct A { char c; }; char A::*p = &A::c; static char A::*const q = p; and then &(a.*q) - &a.c which should evaluate to 0. Here "p" will be 0, that's the offset from the start of the struct to "c". "q" is const-qualified and static and initialized with "p", so we get to cp_fold_maybe_rvalue -> decl_constant_value -> constant_value_1. Now, NULL pointer-to-data-members are represented by -1, so that a null pointer is distinguishable from an offset of the first member of a struct (0). So constant_value_1 looks at the DECL_INITIAL of "q", which is -1, a constant, we fold "q" to -1, and sadness ensues. I believe the -1 value is only an internal representation and shouldn't be used like that. Hence my attempt to fix this as below. Anybody see a problem with this approach? My first version just skipped folding TYPE_PTRMEMDATA_P, much like with REFERENCE_TYPEs above, but the problem is just with NULL member pointers, methinks. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-02-24 Marek Polacek <pola...@redhat.com> PR c++/79687 * cp-gimplify.c (cp_fold_maybe_rvalue): Don't fold NULL pointer-to-data-members. * g++.dg/expr/ptrmem8.C: New test. * g++.dg/expr/ptrmem9.C: New test. diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c index 3eec940..6de88af 100644 --- gcc/cp/cp-gimplify.c +++ gcc/cp/cp-gimplify.c @@ -1976,7 +1976,9 @@ cp_fold_maybe_rvalue (tree x, bool rval) && TREE_CODE (TREE_TYPE (x)) != REFERENCE_TYPE) { tree v = decl_constant_value (x); - if (v != x && v != error_mark_node) + if (v != x + && v != error_mark_node + && !null_member_pointer_value_p (v)) { x = v; continue; diff --git gcc/testsuite/g++.dg/expr/ptrmem8.C gcc/testsuite/g++.dg/expr/ptrmem8.C index e69de29..c5a766a 100644 --- gcc/testsuite/g++.dg/expr/ptrmem8.C +++ gcc/testsuite/g++.dg/expr/ptrmem8.C @@ -0,0 +1,15 @@ +// PR c++/79687 +// { dg-do run } + +struct A +{ + char c; +}; + +int main() +{ + char A::* p = &A::c; + static char A::* const q = p; + A a; + return &(a.*q) - &a.c; +} diff --git gcc/testsuite/g++.dg/expr/ptrmem9.C gcc/testsuite/g++.dg/expr/ptrmem9.C index e69de29..32ce777 100644 --- gcc/testsuite/g++.dg/expr/ptrmem9.C +++ gcc/testsuite/g++.dg/expr/ptrmem9.C @@ -0,0 +1,19 @@ +// PR c++/79687 +// { dg-do run } + +struct A +{ + char c; +}; + +int main() +{ + static char A::* p1 = &A::c; + char A::* const q1 = p1; + + char A::* p2 = &A::c; + static char A::* const q2 = p2; + + A a; + return (&(a.*q1) - &a.c) || (&(a.*q2) - &a.c); +} Marek