This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Prefix attributes vs. grammar
- To: "Joseph S. Myers" <jsm28 at cam dot ac dot uk>
- Subject: Re: Prefix attributes vs. grammar
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Tue, 24 Jul 2001 18:46:36 -0700
- cc: "gcc at gcc dot gnu dot org" <gcc at gcc dot gnu dot org>
> Start from the principle that the corresponding program without attributes
> must be well-formed if the program with attributes is to be well-formed.
That probably already breaks some usages. People seem to expect that
types with different attributes are different types, for example.
Concretely, your example isn't a description of what G++ currently
accepts; G++ 3.0 accepts:
void f (int __attribute__((__mode__(__DI__))) x) {}
void f (long long x) {}
which it should not if the attribute makes the type equivalent to long
long. So, perhaps the exception you offerred is not required?
Your rule, without the exception, would be a very good start.
> x;".) Given an example where problems arise, a listing of all relevant
> paragraphs of ISO 14882 and an explanation of how they interact and how
> attributes cause problems, I'll attempt to work out a plausible answer.
You're being helpful, but I know that you understand that this is the
upside-down way from how it is supposed to go. Both you and I agree
that this stuff should be worked out first, not afterwards.
Just for fun, here's a question. Consider:
template <typename T> size_t f() { return sizeof (T); }
What does `f<int __attribute__((__mode__(__DI__))>' return?
What about `f<int>'? (Use a `typedef' if you think that attributes
require a declarator to which to bind.)
Without the attributes:
int g() {
return f<int> () * f<int> ();
}
is certainly legal and returns 2 * sizeof (int). This, however, doesn't
make sense with attributes. So, we have two choices: this is ill-formed
(no diagnostic required, the functions might be in different translation
units), or this is well-formed. If well-formed, we need to invent
manglings for attributes. If ill-formed, people get very subtly burned;
the linker will merge the two versions of `f', but only one call-site
will get the value it expected. Neat, because this can happen even if
one definition is in a library, so you can unit-test your code all you
want, and still have it fail when linking with someone else's code due
to this issue.
> Given an understanding of the standard declarator syntax (i.e., having
> memorised the relevant parts of the standard's syntax and description of
> semantics), the meaning of attributes as part of nested declarators (as
> opposed to prefix and postfix attributes on declarations) is natural and
> obvious.
Not to me, and I'm pretty standards-fluent.
For example, is it an invariant that attributes in a declaration always
apply to the declarator, and not to some part of the type of the
declarator? If so, then there are types that you can only talk about with
typedefs (because trying to name them any other way yields modification of
the declarator). If not, then `void (stdcall * f) ()' and `void (*stdcall
f)' are different (where `stdcall' is shorthand for the appropriate
attribute stuff). According to Stan's proposal, these mean the same thing,
which is OK with me, but certainly not obvious!
Can you cast to a type that involves attributes? If not, why not? That
would be an example where the declarator is abstract.
It is a huge mistake to implement these things without working through the
issues first. We end up having to support things for backwards
compatibility without even knowing what they mean. I wish I had known
about this before its release; then I would have argued to remove this
functionality until we figured out what it meant. Now we are stuck,
according to Stan, who believes there to be lots of code using these
features.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com