On Sat, Mar 31, 2018 at 7:12 AM, Alexandre Oliva <aol...@redhat.com> wrote: > 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.
Agreed. The C definition talks in terms of a variable declaration static <type> t; so treating the type as an anonymous aggregate member of the class would be wrong; it can be a type member, but not an anonymous aggregate. > 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? The global namespace would be a rather arbitrary choice; it seems to me that using the current scope is a natural interpretation. About d in the example, I'm not sure how you mean the global namespace is the current scope; we should be pushed into a when parsing the initializer for a::z. But I would think we should reject the definition of d because a is already complete, so it's too late to add members to it. > 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 ;-) No, offsetof should not make an exception. >> 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. No, sorry, that's a relatively low priority cleanup. Jason