On Tue, Apr 3, 2018 at 11:25 PM, Alexandre Oliva <aol...@redhat.com> wrote: > On Apr 3, 2018, Alexandre Oliva <aol...@redhat.com> wrote: > >> On Apr 2, 2018, Jason Merrill <ja...@redhat.com> wrote: >>> On Sat, Mar 31, 2018 at 7:12 AM, Alexandre Oliva <aol...@redhat.com> wrote: >>>> 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; > >>>> 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. > >> I was just describing observed behavior. The code above compiles. > >> The explanation is in do_pushtag. It starts with a loop that, among >> other things, skips COMPLETE_TYPE_P class scopes. we then record the >> new type in the namespace named by the resulting scope. As the comment >> says, this is meant to allow for types to be introduced in initializers >> of static data members in spite of the class being already complete. > >> The problem, as I see it, is that we don't adjust the context to match, >> so we introduce the type in one scope, but claim it to belong to >> another. Which sort of works for named types, but comes down in flames >> (err, reenters like Tiangong-1? ;-) if the type is anonymous. > >>> 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. > >> The existing code in GCC sort of disagrees with your proposal, so, for >> the sake of avoiding breaking code that we used to compile (like the >> definition 'd e' above), I'll insist on something along the lines of the >> following patch: > > That patch breaks various cases of lambdas in data member initializers > that reference members of the class containing the data member. > > This suggested to me that we already have infrastructure for and > expectations of introducing types within a class after the class is > complete. Using similar infrastructure to make types introduced within > __builtin_offsetof, or even in type-casts under the extension I > attempted to adjust in the proposed patch (the extension that Nathan > mentioned he also ran into). > > I still think we could attempt to retain the extension as it is, parsing > types introduced in data member initializers within the scope of the > class containing the data member, like we do, but, when the class is > already complete, recording it if not in TYPE_FIELDS, in some additional > field consulted for name mangling purposes and, in order to retain > compatibility, if the type is not a closure or anonymous, also recording > it in the enclosing namespace, so that it is found by lookup as in the > quoted snippet. > > Is that a terrible idea?
It sounds like a lot of work to support a very questionable pattern. Perhaps we should just disallow defining a type in offsetof if the current scope is a class. Jason