This is the mail archive of the gcc@gcc.gnu.org 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: C constant expressions proposals


"Joseph S. Myers" <jsm@polyomino.org.uk> writes:

| On Sat, 14 Aug 2004, Gabriel Dos Reis wrote:
| 
| > | This looks more in the spirit of C++ than C (since, for example, C does 
| > | not include const variables in constant expressions).
| > 
| > It is true that C does not include const variables in constant
| > expressions, but I believe it should accept const variables with
| > either internal linkage or no linkage, initialized with integral
| > constant expressions, to be used in constant expressions.
| 
| I believe in this matter we should wait to be led by WG14 if they want to 
| expand the notion of constant expressions in C, as hitherto WG14 has not 
| chosen (with the example of C++ to hand, and they certainly considered 
| what C++ features might appropriately be added to C) rather than adding 
| const variables (which C treats as accessing the value of a (constant) 

"const" in C has a very interesting history -- as do many
functionalities designed for C with Classes, and that end up in C.
It was initialy designed as readonly/writeonly proposal for C by Bjarne
Stroustrup, long before X3J11 was formed.  It was voted by Bell Labs C
standards group with the amendment that "readonly" be spelled "const".
The semantics of "readonly" in that proposal effectively is close to
what C currently has for "const", e.g. the object is immuable.
However, it was clear from that proposal that if an object is immuable then
it can serve as a symbolic constant.  But the scope of the proposal
did not restrein itself to symbolic constants.  Further use 
experiences with C with Classes revealed that if the const object had
internal linkage, then the compiler had more opportunities to treat
them as effective symbolic constants.  Consequently, the semantics of
"const" was changed in C with Classes.  When X3J11 was formed, the
const proposal resurfaced and was adopted.  But the ANSI C committee did
not update the semantics to reflect practice and experience with C with
Classes. That was before we got C++ :-)

However, I'm not going to insist that you add those semantics.  I was
pointing what I think is a useful GNU C extension.  It is not like a
brand new invention that does not have real-word experience use and
standard practice.  Given my own position on extensions in GCC, I
wholeheartly agree with you that it is something that would benefit
from elaboration by WG14 before actual adoption in GCC, unless the GCC
manitainers agree that they want to have it no matter what WG14 decides.

| object rather than as being constants, and in C const does not affect 
| linkage) to the valid parts of constant expressions.  This question isn't 

I was not suggesting that you make "const" change linkage.  
Rather, I was saying that if you have a integral variable with
internal linkage or no linkage and initialized with a constant
expression then it can serve as a constant expression.  This 
mirrors what happens with constant folding and constant
propogations with other parts of GNU extensions with respect to "if
folding succeeds, then it is a constant" (discussed below).  Except
that, here, the semantics are defined unambiguously and are not
depending on success of folding and optimization level.

| fundamental to the spirit of C; WG14 could choose to change it in future; 
| but bearing in mind that such extensions don't have much benefit (C 
| programmers are used to using #define for constants, for all its faults) 
| and would tend to lead to people writing code with GCC that fails to be 

I don't understand this argument.  It would be a GNU extension. 

| portable to other compilers, I just think we don't need such an extension.  

We can construct argument against having a GNU extension, but I think
the portability argument above is not a valid one.

| (Without regard to the question of whether such an extension is within the 
| implementation latitude to add other forms of constant expression.)
| 
| In various cases when arithmetic is done on const variables we do 
| accidentally accept them in constant expressions, depending on 
| optimization and other random factors; this is bug 5675, plus a regression 

it strikes me as a useful GNU extension whose semantics would be be
very closely modelled on what happens in C++ :-)

| since 24 March (for which I haven't filed a separate bug or upgraded that 
| one, given that sort of regression clearly isn't going to block a 
| release).  One point of giving (and implementing) precise models is to 
| stop such random variation; it just so happens the C-like way of stopping 
| it means consistently treating const variables like non-const ones.

I'm all for formal models and I'm glad to see you're doign this for
this part of our implementation.  But the GNU extension semantics
emntioned above also can fit into that model and is not random
variation. 

| Since C has tentative definitions, you'd need the initializer to be 
| visible before the use in the constant expression. 

That is what I said by "initialized by a constant expression".

| You should also exclude volatile const variables.

If the model is based on existing semantics in C++, there is no
exclusion of const volatile.  I think Mark Mitchell recently applied a
patch to the C++ front-end to that effect.

| > problem.  I formulated the rules pretty much in the spirit of what
| > CFront did to inline functions a very long time ago: use of an inline
| > function before it is defined is a hard error.  That requirement is
| 
| That certainly simplifies the use of inline functions!  C99 says that a 

Yes, it simplifies the use and handling of inline functions.  It even
provided opportunities for interesting ABI improvement concerning
passing structs in registers.  
The C++ committee decided to relax that requirement (contrary to the
C++ ARM) and some opportunities were lost.

| call to an inline function can use either the definition in that 
| translation unit (which may be before or after the call), or the 
| non-inline definition in another translation unit, but not an inline 
| definition from another translation unit.  All these definitions may be 
| distinct; C99 deliberately (discussed in the Rationale) did not adopt the 
| ODR.

Indeed.

| > For the GNU C part, shouldn't we be more precise about:
| > 
| >    g) Built-in functions starting __builtin_ may be used in certain
| >       circumstances in constant expressions: if the compiler can fold
| >       them to an integer constant, floating constant or address
| >       constant then they are treated as an integer constant
| >       expression, arithmetic constant expression or address constant,
| >       respectively.  The exact circumstances in which they are folded
| >       are unspecified, may depend on optimisation levels and are
| >       subject to change.  
| > 
| > I would prefer we don't make the "constantness" depend on optimization
| > level.  The reason is that we should not make a program valid
| > depending on the optimization level -- users should be able to switch
| > from "-g -O2" to "-g -O0" or vice versa.
| 
| The situation is that a precise specification is difficult - some 
| functions may not result in a constant with constant arguments, while 
| non-integer arguments may quite legitimately result in integer constants 
| in some cases.

I don't follow.  If a call results into a constant expression at
optimization level N and is not a constant at optimization level M < N,
then we can:

  (1) declare that the call is never a constant expressions (even
      though internally it might be); or
  (2) or declare that it is always a constant expressions - this means
      we have a list all transformation we do at optimization level N
      and decide to apply them for the appropriate categories of
      functions and arguments.

If the purpose of your model is to remove random variations, I think
it makes sense to adopt either (1) or (2).

|  I also suspect real code is using such cases, beyond those 
| documented, in constant expressions in initializers.  Thus I discourage 
| use in constant expressions, while expressly noting those cases such as 
| __builtin_nan for which we have made guarantees that they can be used as 
| such in standard headers. 

Yes, those __builtin_xxx were specifically designed and implemented as
yielding constant expressions regardless of optimization levels.  That
should remain the case.

| Effectively this leaves a "window onto the 
| implementation", albeit much smaller than at present, where we have never 
| specified constancy but some users may reasonably be using it.  To make 
| things more precise we'd either say "never constant, except for this short 
| list of functions" (and take the user complaints), or else keep updating a 
| list of precisely which mathematical functions (for example) we fold, and 

The reason I mentioned the "constant-valued function" proposal is
precisely that it gives a general rule of what users may expect or
consider a constant expression.  It needs not  a long list of special
functions we would have to update as we go.

| when (and we fold some only for particular arguments).  When folding 
| arithmetic constant expressions, FENV_ACCESS complicates matters as well 
| (i.e. except in static initializers we can't fold, but VLA constraints 
| expect us to, and there was a view in the UK C Panel that the problem 
| there might be that the expression was still considered constant in the 
| presence of FENV_ACCESS rather than in the VLA constraints).  As the 

If FENV_ACCESS is OFF, the compile-time evaluation is permitted.
Otherwise, the evaluation is "as-if" done at run time.  Precisely how
was the other view derived?

| standard is of course silent on __builtin_ function calls, there's no 
| great value in arbitrarily annoying users by restricting them.

Agreed.  And I think we should make this guarantee irrespective of the
optimization level.

| VLAs in structures form another underspecified case, although there 
| because I think deprecating them is the right solution; I think their 
| semantics are full of holes that we don't want to try to fill, and they 
| don't work reliably as shown by many bug reports past and present.

Again, 100% agreed.

Thanks,

-- Gaby


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