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

Reply via email to