This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Proposed semantics for attributes in C++ (and in C?)
- From: Geoffrey Keating <geoffk at apple dot com>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: "Joseph S. Myers" <joseph at codesourcery dot com>, gcc at gcc dot gnu dot org
- Date: 15 Oct 2006 18:33:13 -0700
- Subject: Re: Proposed semantics for attributes in C++ (and in C?)
- References: <4532B25F.9090207@codesourcery.com>
Mark Mitchell <mark@codesourcery.com> writes:
> We have a number of C++ PRs open around problems with code like this:
>
> struct S {
> void f();
> virtual void g();
> };
>
> typedef __attribute__((...)) struct S T;
>
> If the attribute makes any substantive change to S (e.g., changes its
> size, alignment, etc.) then bad things happen. For example, the
> member functions of "S" have expectations about the layout of "S" that
> are not satisfied if they are called with a "T". Depending on the
> attribute and circumstances, we do all manner of bad things, including
> ICE, generate wrong code, etc.
>
> For a while now, I've been promising to propose semantics for these
> constructs. Here is a sketch of the semantics that I think we should
> have. (I say a sketch because I have not attempted to write
> standardese.)
>
> All attributes must be classified as either "semantic" or
> "non-semantic" attributes. A "semantic" attribute is one which might
> affect code-generation in any way. A "non-semantic" attribute cannot
> affect code-generation. For example, "used" and "deprecated" are
> non-semantic attributes; there is no way to observe, by looking at an
> object file, whether or not a class has been marked with one of these
> attributes. In contrast, "packed" is a semantic attribute; the size
> of a class is different depending on whether or not it is "packed".
>
> Any attribute may be applied at the point of definition of a
> class. These attributes (whether semantic or non-semantic) apply to
> the class. For example, if the class is packed, then the member
> functions expect the "this" pointer to point to the packed class.
>
> A typedef declaration which adds only non-semantic attributes is
> always valid. As with other typedefs, the typedef declaration creates
> a new name for an existing type. The type referred to by that name is
> the same type as the original type. However, the *name* has
> additional properties, implied by the (non-semantic) attributes. For
> example, using a "deprecated" name for a type results in a deprecation
> warning. But, a function declared to take a parameter with the
> non-deprecated name may be passed a parameter with the "deprecated"
> name.
>
> A typedef declaration which adds semantic attributes to a class type,
> other than POD classes with no explicitly declared members other than
> data members, to arrays of such classes, to arrays of such arrays,
> etc., is invalid. (POD-ness alone is not satisfactory, as PODs may
> contain function members, and I think dealing with static data members
> and typedef members is not worth the trouble.)
>
> A typedef declaration which adds semantic attributes to a POD class
> type with no function members is valid, but creates an entirely new
> type, different from all other types except others formed by adding
> the same combination of semantic attributes to the same original class
> type. In the example above, if the typedef adds a semantic attribute,
> you may not pass an "S" to a function expecting a "T" or vice versa.
> Neither may you pass an "S*" to a function expecting a "T*", without
> an explicit reinterpret_cast. The name of "T", for linkage purposes,
> is "T", and there is no implicit "T::S" type; instead, however, there
> is a "T::T" type. (Various consequences follow; for example,
> typeid(T) gives you a type_info object that indicates that the name of
> the type is "T".) References to the original type from within the
> types of the members of the class still refer to the original class.
> For example, in:
>
> struct S {
> char c;
> S* next;
> };
> typedef __attribute__((packed)) S T;
>
> the data member T::next has type "S*", not "T*".
>
> A typedef declaration which adds semantic attributes to a non-class
> type is valid, but again creates an entirely new type. (We might want
> a special exception to the "entirely new type" rule for the "mode"
> attribute, declaring that "typedef __attribute__((mode(DI))) int LL"
> is equivalent to "typedef long long LL;" on platforms where "long
> long" has DImode.) So,
>
> typedef S* P;
> typedef __attribute__((...)) P Q;
>
> creates a type "Q" that is incompatible with "S*" if the attribute is
> semantic. However, the type of "*Q" is still "S". It is invalid to
> do anything that would require either type_info or a mangled name for
> "Q", including using it as an argument to typeid, thowing an exception
> of a type involving "Q", or declaring a template to take a parameter
> of a type involving "Q". (We could relax some of these restrictions
> in future, if we add mangling support for attributes.)
Declaring a function which takes a 'Q' also requires the mangled name of 'Q'.
> A variable declaration involving attributes, like:
>
> __attribute__((...)) S v;
>
> is treated as syntactic sugar for:
>
> typedef __attribute__((...)) S T;
> T v;
>
> where T is some invented type name different from all others in the program.
>
> For example given:
>
> __attribute__((packed)) S v;
>
> the type of "&v" is "__attribute__((packed)) S *", and cannot be
> passed to a function expecting an "S*", but can of course be passed to
> a function expecting an "__attribute__((packed)) S *", or a typedef
> for such a type.
... except that there can't be any such functions. You could assign
it to another variable of the same type, or a field of a class with
that type.