On Tue, Feb 28, 2017 at 10:10 AM, Marek Polacek <pola...@redhat.com> wrote: > On Fri, Feb 24, 2017 at 11:11:05AM -0800, Jason Merrill wrote: >> On Fri, Feb 24, 2017 at 8:22 AM, Marek Polacek <pola...@redhat.com> wrote: >> > 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. >> >> Since q is initialized from p, it shouldn't have a DECL_INITIAL of -1; >> that sounds like the bug. > > The DECL_INITIAL of -1 comes from cp_finish_decl: > 7038 The memory occupied by any object of static storage > 7039 duration is zero-initialized at program startup before > 7040 any other initialization takes place. > 7041 > 7042 We cannot create an appropriate initializer until after > 7043 the type of DECL is finalized. If DECL_INITIAL is set, > 7044 then the DECL is statically initialized, and any > 7045 necessary zero-initialization has already been performed. > */ > 7046 if (TREE_STATIC (decl) && !DECL_INITIAL (decl)) > 7047 DECL_INITIAL (decl) = build_zero_init (TREE_TYPE (decl), > 7048 /*nelts=*/NULL_TREE, > 7049 > /*static_storage_p=*/true);
Ah, that makes sense. We do want to do constant-initialization with -1 before we do dynamic initialization with p. So we need to detect in constant_value_1 that the variable has a dynamic initializer and therefore return the variable rather than -1. DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P seems useful, perhaps in combination with DECL_NONTRIVIALLY_INITIALIZED. Jason