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

Reply via email to