Mark Mitchell <[EMAIL PROTECTED]> 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.