This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [tree-ssa] where to fix this?

On Wed, 7 Jan 2004, Jan Hubicka wrote:

> I was refering more to things like that fabs (a)<-1 is not a constant
> expression in C, but GCC mistakely accept it as it's folder is too
> smart.  For purposes of parsing we need to somehow disable this
> smartness.

It's not simply a matter of disabling smartness; you need to keep track of
several flags for each subexpression to determine whether the containing
expression is a constant expression, and what sort of constant expression
if so.  I don't think trees are the right place to keep these flags (which
are purely parser state, which at the parsing stage can determine the
types of expressions but afterwards have no effect on semantics) in trees;  
C++ keeps its (simpler than C99) constant expression state in separate
parser structures.  Keeping this state separate from the trees does mean
you can optimize them all you like as long as you do the required constant
folding (for the checking of constraints on integer and arithmetic
constant expressions), though I suspect it might well be better to leave
all the nonrequired folding until after the full expressions have been
built anyway.

Below is a slightly revised and expanded version of an analysis of the
problems with constant expressions I previously sent to the UK C Panel
mailing list.  (Of course it deals only with C99; GCC when doing this
properly needs to implement the (simpler) semantics in C90 as well.)  If
you think you understand the requirements on constant expressions in C99,
you probably don't; I suspect I still haven't found all the subtleties

(Despite the lack of anything approaching a proper implementation of
either C90 or C99 constant expression semantics in GCC, GCC has reportedly
managed to pass third-party C90 testsuites in the past (some bugs detected
in the compiler by these were fixed in the run-up to some cpplib changes
<>); this just
indicates the limitations of those testsuites.  It would of course be
dishonest now to claim C90 conformance for GCC given this and various
other known reported conformance bugs.)

Problems with constant expressions in C99

(1) There are the problems in DR#261 the UK C Panel submitted a couple
of years ago.  This is where the Oxford minutes say "DR 261.  Clive
had potential sticking points and will converse with interested
parties." and "ACTION: CF to draft words describing the four uses of
the term constant to be considered in the response to DR 261. DONE
merged in here or a separate document?  I don't have them.".

The actual wording we proposed in that DR about "translation-time values"
is problematic because expressions with translation-time values don't seem
to be restricted to those that would be *integer* constant expressions.
Null pointer constants require *integer* constant expressions.  Arrays
require *integer* constant expressions not to be VLAs, but *any* type of
constant expression suffices to require the constraint on the size being >
0 to be checked (this is probably a defect, but should be separately noted
if being fixed in the course of fixing another defect).

  int x[(int)(double)1.0];

is a VLA while

  int x[(int)(double)0.0];
  int y[(int)-1.0];

are both constraint violations, although the expressions are only
arithmetic constant expressions.

(2) We (UK C Panel) couldn't agree a couple of years ago about whether
the changes in C99 (where comma expressions appear in an unevaluated
subexpression outside sizeof - including possibly in the preprocessor)
were intended or not (so that draft DR didn't get submitted).  This
may not be a defect, but the effect is that there are in effect
several flags on subexpressions (and on types appearing within
expressions) that must maintained by an implementation in order to
determine whether an expression is a constant expression and, if so,
what sort of constant expression it is; some non-constant
subexpressions are OK in integer constant expressions if they are
within an unevaluated subexpression, while some are only OK within
sizeof.  Furthermore, a sizeof expression whose result is not an
integer constant may be OK within an unevaluated part of an arithmetic
constant expression - as long as it does not contain a cast of
prohibited form - but not within an unevaluated part of an integer
constant expression.  It isn't even immediately obvious from the
definitions that all integer constant expressions are also arithmetic
constant expressions.

(3) Address constants can contain casts to variably modified types, which
might be a defect <>.
If you cast to such a type (while keeping the expression in fact a
constant), any nonconstants directly in the sequence of tokens for the
type (as opposed to in a typedef) are also subject to the constraints
on what may only appear in unevaluated subexpressions, and probably to
those on permitted operands (see also item 5 below).

(4) When exactly can "other forms" of constant expressions (6.6
paragraph 10) be accepted?  It seems (common view on comp.std.c) that
they can't be accepted as integer constant expressions (or one of the
other types enumerated), only as some type in addition to those, that
can be accepted in initializers (or, I suppose, allowed in constraint
checking for VLAs having positive size), and that any such forms must
follow the Syntax, Description and Constraints sections of 6.6, but
this could be made much clearer.

(5) What are the "operands" (6.6 paragraphs 6 and 8) of a constant
expression?  Presumably it means the "ultimate" operands in some sense,
recursing down various operators to their operands, but this isn't
specififed.  Presumably compound literals such as (const int){ 0 } are not
meant to be constant expressions (being references to anonymous
variables), but it is hardly clear from the text that 0 isn't the operand

(6) We know from paragraph 2 that sizeof of a non-VLA is an
integer constant.  Is it also the case that sizeof of a VLA is *never* an
integer constant, or indeed never counts as a constant?  Can it be shown
from the standard that sizeof(int [(int)(double)1.0]) isn't an arithmetic
constant expression - or is it?

(7) May address constants use array indices that are arithmetic
constant expressions but not integer constant expressions?

(8) 6.6 paragraph 7 says that a constant expression in an initializer
"shall be, or evaluate to" one of four possibilities.  When does "be"
apply, and when does "evaluate to" apply?  (Expressions *are* expressions
(pieces of source code), but *evaluate to* values (something more
abstract, but with no intersection with pieces of source code), so only
one can apply in each case.)

* an arithmetic constant expression - this is a type of expression, so
"be" applies.

* a null pointer constant - a type of expression, so "be" applies.

* an address constant - a type of value (with some associated restrictions
on the expression behind the value), so "evaluate to" applied.

* an address constant for an object type plus or minus an integer constant
expression - some sort of hybrid to which neither applies.

What of

static int x[10];
static int *p = 1 + x + 9 - 0 + 0;

?  Is this valid?  Pointing one past the end of an array, it clearly falls
outside the definition of "address constant".  But the syntax doesn't make
it clearly syntactically of the form (address constant) +/- (integer
constant expression).  What about the null pointer (void *)(void *)(int)0?
That's created by casting an integer constant expression to pointer type -
but the rules for address constants refer to "an integer *constant* cast
to pointer type".

I think a proper fix for this last issue is to specify all standard types
of constant expression syntactically, with a more precise (unified?)
definition of the last two.

Joseph S. Myers

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]