T
Tim Rentsch
Harald van Dijk said:It would be plural both with your interpretation as with mine.
Actually singular is more usual if only the one category is
meant. Try it with 'function definition' - 'other forms of
function definition', not 'other forms of function definitions'.
It doesn't say that in the standard,
There's no disagreement about what words appear, but the question
is what elements are included under those words. For example, a
statement in the Standard might use the term 'declarations' but
would also apply to 'definitions', as (many) definitions are also
declarations. Inferring that a statement about 'declarations'
doesn't also apply to those 'definitions' just because the word
'definitions' isn't mentioned locally is obviously wrong-headed.
though I was already agreeing
that that seems to be what is intended. This would clearly not be the
intended interpretation for something like "signed integer types",
though: permission to extend the definition of "signed integer type"
should not implicitly allow implementations to extend the definition
of "standard signed integer type".[*]
This analogy seems too hypothetical and not closely analogous
enough to be relevant to the current discussion.
Without explicit permission to
redefine "integer constant expression", an implementer does not have
that luxury either.
You say this like it's an article of faith, but generally the
reverse is true: any statement about a broad category of items
also applies to more specialized subcategories unless a specific
exception is called out, like the 'declaration' and 'definition'
example above. For example, the Standard includes this text:
"Thus, * can be used only in function declarations that are not
definitions (see 6.7.5.3)." Unless you can cite some other
example passages from the Standard that support the "Without
explicit permission" theory, I don't see any reason to assume
it applies here.
I know, I've actually had the opportunity to modify one compiler to
accept extended forms of integer constant expressions: it was so
strict, that it was impossible to define offsetof as an i.c.e., even
though it was more than capable of simplifying the common forms of
offsetof at translation time. FWIW, I opted for a "literal" keyword to
mark the following expression as an extended constant expression, so
that you could do:
typedef char __char;
typedef size_t __size_t;
#pragma keyword __offsetof_magic for keyword literal
#define offsetof(s, m) (__offsetof_magic (__size_t) ((__char *) &((s
*) 0)->m - (__char *) 0))
-- please excuse possible typos -- which resulted in errors at a later
stage if the expression was too complex to simplify.
One point of 6.6p10 is that such goofiness is not necessary.
(I hasten to add that the 'goofiness' I'm talking about
here is not your design choice but the circumlocutions
needed if other forms of ICE's were not available under
6.6p10. The definitions above could be a perfectly
reasonable design choice even if the circumlocutions
were not necessary.)
Also, if you look at the description of 'constant expression' (as
opposed to the subcategories) all the restrictions on it are
either syntactic or constraints. Violating either of those would
necessitate a diagnostic message, in which case 6.6p10 would
serve no purpose, since the same result could be achieved by just
defining an extension.
6.6p10 would allow
char p[2];
int i = (int) p;
as an extension, because it would violate none of the relevant
"shall"s in 6.6: (int) p would be a constant expression of type int,
without being an integer constant expression. 6.7.8p4 requires a
constant expression, so without 6.6p10, it would be a constraint
violation.
No, 6.6p10 is not necessary for this. The expression '(int) p'
(provided it can be evaluated during translation) already qualifies
as a constant expression. The discussion in 3p1 and 6.1p1 make it
clear that the term "constant expression" is defined syntactically,
and '(int) p' already meets this definition. The "shall"s in 6.6p3,
6.6p4, and 6.6p7 (and following) are not part of the definition of
"constant expression". Failure to meet the "shall"s in 6.6p3 or
6.6p4 would require a diagnostic if a constant expression were
needed, but not meeting the "shall"s in 6.6p7 (and following) would
only be undefined behavior, not a constraint violation, and the
expression in question would still be a constant expression (provided
6.6p1 and 6.6p2 are satisfied) - no diagnostic required.
One could argue that 6.6p7 is defining a new category, "constant
expressions in initializers", but then under your theory 6.6p10
wouldn't apply to those either since it doesn't name them explicitly.
It is only on the "and does allow" that we disagreee.
If you think 6.6p10 is _meant_ to allow other forms of ICE, but
_doesn't_ allow other forms of ICE, does this mean you think
how you read the Standard differs from how the committee
reads the Standard?
Yes. Do you know of any constant expression of integer type that is
accepted in file scope initialisers, but not in enumeration constants?
Because I don't.
Yes. One version of gcc I use accepts
char x[1];
static long xlong = (long) x;
but doesn't accept '(long) x' as an integer constant expression.
(The expression '(long) x' has type 'long' rather than type 'int',
which may perforce disqualify it for enumeration constants, but it
also doesn't qualify as "just" an integer constant expression, where
which particular value it has doesn't matter as long as the type is
integral.) [The pun in the last sentence was not intentional!]
Older versions of gcc accepted many extended forms of
constant expressions in both contexts, current versions accept few if
any in either context.
I don't draw any conclusions from this other than that recently a
different decision was made about which forms to include (by
default?) in the conforming modes. Even what you're calling the
"older versions" of gcc have been around long enough so questions
about conformance should have been previously addressed; IIANM
the wording of 6.6p10 is unchanged since C90 (except of course
the section numbering was different).
[*] The "signed integer types" section is worded much better, and
clearly only allows implementation-defined "extended signed integer
types". I'm wondering how we would interpret the standard if it said
"There are five /standard signed integer types/, designated as signed
char, short
int, int, long int, and long long int. (These and other types may be
designated
in several additional ways, as described in 6.7.2.) There may also be
other
implementation-defined signed integer types."
Seems like sort of a strawman. I expect this wording would be
judged defective because it doesn't define the term 'signed
integer types', not to mention the term 'extended signed integer
types' which is used several times in other places in the
Standard.