On Mar 30, 2018, Jason Merrill <ja...@redhat.com> wrote: > On Fri, Mar 30, 2018 at 3:55 AM, Alexandre Oliva <aol...@redhat.com> wrote: >> Types defined within a __builtin_offsetof argument don't always get >> properly recorded as members of their context types
>> I suppose this means I should look for another solution that doesn't >> involve rejecting these definitions, eh? > Hmm, I'm afraid so Ok, but... tricky... If I were to make the anonymous types members of the enclosing class, their members would be promoted to members of the enclosing class, which doesn't sound like the right thing to do. But I wonder, should they even be regarded as members of the enclosing class, when they do not appear inside the body of the class. Perhaps their context should be something else, say the innermost enclosing namespace, the global namespace, some anonymous namespace introduced for the offsetof... One thing that's not clear to me is whether types defined in offsetof can be referenced outside their own definition. In C, that would be natural, since the struct namespace is flat, but in C++, structs belong to a context, and it's not obvious to me that offsetof should inject names in an enclosing context, or in a separate invisible namespace. I lean towards the latter, but then I tried: template <typename T> class foo { }; int j = __builtin_offsetof(struct a { int i; static foo<a> x = foo<a>(); }, i); and found (through debug info) that foo<a> is mangled as if struct a was defined in the global namespace. And, indeed, a is recorded in the global namespace: a b; which was slightly surprising to me. But it seems to be consistent: when the offsetof expression is within a function, the type will be defined within the function; when it is used in the initializer of a data member, the context is the class containing the data member, even if the initializer is outside the class body, but the type is defined in the global namespace: struct a { static int const z, i = __builtin_offsetof(struct b { int j; }, j); b c; }; int const a::z = __builtin_offsetof(struct d { int k; }, k); d e; b f; // b is not defined a::b g; // ok So, the problem with anon types defined in offsetof appears to be the inconsistency between the scope in which d is introduced, namely the global namespace because that's the current scope, and the DECL_CONTEXT, copied to TYPE_CONTEXT, that is taken as class a because we're parsing the initializer for a::z. Since they disagree, we don't find the type defined in the context named as enclosing it. Since d is visible, I suppose the most conservative solution would be to name the global namespace as the context for type d, rather than defining it as a member of a. Right? Now, I really don't want to think of offsetof appearing in default arguments or array lengths in function prototypes or even in template parameters. Types are not supposed to be defined in such contexts, but... should offsetof make an exception? Currently, we reject them, which is quite a relief, because otherwise it might appear in expressions in templates and that would be really really hairy ;-) > Incidentally, it would be nice to replace all the > type_definition_forbidden stuff with defining-type-specifier as per DR > 2141... (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50169) *nod* Is this in scope for GCC 8? It's not marked as a regression, but I guess I could try and tackle it if it's intended to make it anyway, given that I've got some context on this issue. LMK about the plans, and whether you envision any pitfalls. -- Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ You must be the change you wish to see in the world. -- Gandhi Be Free! -- http://FSFLA.org/ FSF Latin America board member Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer