On 3/19/19 9:33 PM, Jeff Law wrote:
On 3/19/19 8:22 PM, Joseph Myers wrote:
On Tue, 19 Mar 2019, Jeff Law wrote:

I'll note that our documentation clearly states that attributes can be
applied to functions, variables, labels, enums, statements and types.

A key thing here is that they can be applied to fields - that is, they can
be properties of a FIELD_DECL.  Referring to a field either requires an
expression referring to that field, or some other custom syntax that uses
both a type name and a field name (like in __builtin_offsetof).

Thanks for chiming in, your opinions on this kind of thing are greatly
appreciated.

Understood WRT applying to fields, and I think that's consistent with
some of what Jakub has expressed elsewhere -- specifically that we
should consider allowing COMPONENT_REFs as the exception, returning the
attributes of the associated FIELD_DECL in that case.

Is there a need to call out BIT_FIELD_REFs where we can't actually get
to the underlying DECL?  And if so, how do we do that in the end user
documentation that is clear and consistent?

Is it possible to see a BIT_FIELD_REF here?  I couldn't find a way.


One of the big worries I've got here is that documenting when an
expression as an argument to __builtin_has_attribute (or any attribute
query) can be expected to work.  It's always easier on our end users to
loosen semantics of extensions over time than it is to tighten them.

I wonder if a part of the issue isn't due to a mismatch between
the C terminology and what GCC uses internally.  Every argument
to the built-in that's not a type (and every argument to attribute
copy which doesn't accept types) must be a C expression:

1) either an identifier naming a function or variable, or
2) some other expression like a member reference via . or ->,
   an array subscript, or the indirection expression *.

But GCC distinguishes three kinds of arguments:

1) a DECL,
2) some sort of a reference like ARRAY_REF, COMPONENT_REF or
   INDIRECT_REF
3) an expression that satisfies the EXPR_P() predicate (e.g.,
   (struct S*)0, or (struct S){ 1 })

Jeff, you seem to want the built-in to accept just (1) on the GCC
list above and reject (3) (and seem to be waffling on (2)).

How would such an argument be described in a way that users
unfamiliar with GCC internals could easily understand?

All sorts of expressions can be used to refer to fields.  Given
the type definition 'struct A { int b[2]; };' besides
FUNCTION_DECL, PARM_DECL, and VAR_DECL we might expect to commonly
see arguments like:

COMPONENT_REF:
  ((struct A*)0)->b
  (*((struct A*)0)).b
  ((struct A*)0)[0].b

INDIRECT_REF:
  *((struct A*)0)[0].b

ARRAY_REF:
  ((struct A*)0)[0].b[0]

To users, they're all just expressions.

Fields aside, the expressions below seem quite plausible to me
too, especially when the built-in argument is the result of macro
expansion:

CALL_EXPR:
  foo ()

COMPOUND_LITERAL_EXPR:
  (struct A){ ... }

COND_EXPR:
  (0 ? a0 : a1)

COMPOUND_EXPR:
  ((void)0, a)

NON_LVALUE_EXPR:
  (struct A)a

etc.  In these cases the built-in could be passed the result of
__typeof__ instead, but if the built-in itself is part of a macro
that can be invoked either with one of the arguments on the _REF
list or with one of these expressions, it would only work as
expected for half of them.

Using __typeof__ doesn't work for the copy attribute because it
only takes expressions as arguments and not types.

Martin

Reply via email to