ISO/ IEC JTC1/SC22/WG14 N676

                    Document Number:  WG14 N676/X3J11 97-039

                    General wording issues (clauses 1 to 6)


Abstract
========

This document is an attempt to identify all the minor issues I can find
in clauses 1 to 6 of the Standard. I am using draft 9 pre 3 as my
starting point.

It omits those items which I have previously proposed, or have been
addressed in a DR. It also omits a couple of matters which I am handling
separately.

There will be one or more companion papers for subclause 7 and the
annexes.

I hope it is unnecessary to produce formal proposals for all of these,
but I will attempt to identify the issue and have usually generated new
wording (I hope that, in at least some cases, the new wording will make
the problem obvious).

=======================================================================

Item 1:

The term "access" is not well defined. From context, it sometimes
appears to mean "read the value", and sometimes "read or write the
value". This ambiguity sometimes makes it hard to understand what is
actually meant.

There needs to be a definition in clause 3, and all uses of the term
need to be checked for the read-only / read-write problem. Probably the
best approach is to define it as "read or write", and to find and fix
the places where "read" is meant.

====

Item 2:

Change the first part of paragraph 1 of subclause 5.1.2.2.1 to:

    The function called at program startup is named /main/. The
    implementation declares no prototype for this function. It shall be
    defined either with no parameters:

    ...

        int main (int argc, char *argv[]) { /* ... */ }

    or equivalent [*], or in some other implementation-defined manner.

    [*] Thus /int/ can be replaced by a typedef-name defined as /int/,
    or the type of argv can be written as /char **argv/, and so on.

This will make it clear that, while these are the only permitted
strictly conforming alternatives, extensions are allowed but must be
documented.

====

Item 3:

Examples 2 and 6 in subclause 5.1.2.3 need rewording. At present they
use the term "exception" to mean something like an overflow trap,
whereas 6.3 makes it clear that an "exception" occurs on overflow even
when the result is silently wrapped.

====

Item 4:

In 5.2.1 paragraph 2, delete the final "literal". The zero character
terminates strings, but does not occur in a string literal (which is a
syntactic construct).

====

Item 5:

Subclause 6.1.2 treats the term "identifier" as representing the
sequence of characters. On the other hand, subclause 6.1.2.1 treats the
term as representing that sequence within a given scope. Thus in:

    {
        int fred;       /* fred-1 */
        {
            int fred;   /* fred-2 */
        }
    }

6.1.2 paragraph 8 treats fred-1 and fred-2 as being the same identifier,
while 6.1.2.1 treats them as different.

The term "lexically identical identifiers" appears in 6.1.2.1 paragraph
3. This should be used whenever the meaning of 6.1.2 is intended (this
applies in several places throughout the Standard, not just in 6.1.2).

====

Item 6:

In 6.1.2.5, delete the last sentence of paragraph 2 and append to
paragraph 11:

    The implementation shall define /char/ to have the same range,
    representation, and behaviour as one of /signed char/ and /unsigned
    char/. [*]

    [*] CHAR_MIN, defined in <limits.h>, will have one of the values 0
    or SCHAR_MIN, and this can be used to distinguish the two options.
    Irrespective of the choice made, /char/ is a separate type from the
    other two, and is not compatible with either.

This clarifies that there are only two differently-behaving types, not
three.

====

Item 7:

The rules for composite type handle an incomplete array meeting a
complete one, but not the equivalent situation with an incomplete
structure or union.

Replace subclause 6.1.2.6 paragraph 3, first bullet point, with:

    - If one type is complete and the other type is incomplete, the
      composite type is a complete type.

====

Item 8:

Add the following to the end of subclause 6.2.2.3:

    An integer may be converted to any pointer type. The result is
    implementation-defined, and might not be a pointer to an object
    of that type. [59]

    Any pointer type may be converted to an integral type; the result is
    implementation-defined, and need not be in the range of values of
    any integral type. If the resulting value cannot be represented in
    the destination type, the behaviour is undefined. [*]

    [*] Thus if the conversion is to /unsigned int/ but yields a
    negative value, the behaviour is undefined.

    A pointer to a complete or incomplete object type may be converted
    to a pointer to a different complete or incomplete object type. If
    the resulting pointer is not correctly aligned for the pointed to
    type, the behaviour is undefined. Otherwise, when converted back
    again, the result shall compare equal to the original pointer. [*]

    [*] All pointers to character types are correctly aligned. In
    general, the concept "correctly aligned" is transitive: if a pointer
    to type A is correctly aligned for a pointer to type B, which in
    turn is correctly aligned for a pointer to type C, then a pointer to
    type A is correctly aligned for a pointer to type C.

    A pointer to a function ... [this paragraph, taken from 6.3.4,
    remains unchanged].

Note: the idea that implementation-defined behaviour can be required to
be undefined is a rather unsettling one. Given the existence of the
types intptr_t and uintptr_t in subclause 7.4.4, it may be worth
replacing the second of these new paragraphs by:

    Any pointer type may be converted to an integral type; the result is
    implementation-defined, but will be in the range of the signed
    integral type /intptr_t/. If the destination type is any other
    integral type, the value is converted to /intptr_t/ and then to the
    destination type.

and omitting the relevant footnote.

Delete 6.3.4 paragraph 4, and add the following paragraph to the
constraints (after paragraph 2):

    Conversions that involve pointers, other than where permitted by the
    constraints of 6.3.16.1, shall be specified by means of an explicit
    cast.

====

Item 9:

In 6.3.2.3 paragraph 5, replace:

    With one exception, if a member of a union object is accessed after
    a value has been stored in a different member of the object, the
    behaviour is implementation-defined. [54] One special guarantee is
    made ...

with:

    With one exception, if the value of a member of a union object is
    used when the most recent store to the object was to a different
    member, the behaviour is implementation-defined. [54] One special
    guarantee is made ...

Alternatively, since some implementations apparently have problems with
this clause, replace it with:

    With two exceptions, if the value of a member of a union object is
    used when the most recent store to the object was to a member whose
    type does not have the same alignment and representation, the
    behaviour is undefined. If either member has character type or is
    an array of character type, the behaviour is implementation-defined.
    [54]. Furthermore, one special guarantee is made ...


====

Item 10:

Replace subclause 6.5.2 paragraph 4 by:

    Each of the comma-separated sets designate the same type, except
    that for bit-fields, it is implementation-defined whether the
    specifier /int/ (or no specifier) is the same type as /signed int/
    or is the same type as /unsigned int/.

Replace subclause 6.5.2.1 paragraph 8 by:

    A bit-field shall have a type that is a qualified or unqualified
    version of /signed int/ or /unsigned int/. A bit field is
    interpreted as a signed or unsigned integral type consisting of the
    specified number of bits. [*]

    [*] As specified in 6.5.2 above, if the actual type specifier used
    is /int/ or there is no type specifier, or is a typedef-name defined
    using either of these, then it is implementation-defined whether the
    bit-field is signed or unsigned.

This eliminates the duplicate wording in these two places, and also
makes it clear that there is not a potential third signedness of
bitfield.

If my proposals for representation of types are accepted, there may need
to be further wording adjustments in the second alteration.

====

Item 11:

In subclause 6.5.2.1, change paragraph 3 to read:

    ... shall not exceed the number of bits in an object of the type
    that would be specified if the colon and expression had been
    omitted. If the value is zero ...

The current wording doesn't say *what* the type is compatible with.

====

Item 12:

Subclause 6.5.2.2 allows an enumerated type (say /enum e/) to be
compatible with /long/ or even /unsigned long long/. On the other hand,
subclause 6.2.1.1 states that the type converts to /int/ or /unsigned
int/ as part of the integral promotions. This produces the apparent
contradiction that two compatible types promote differently !

There are two alternative approaches to solving this.

(A) Replace subclause 6.5.2.2 paragraph 4 by:

    Each enumerated type shall be compatible with one of the following
    types:
        signed char             unsigned char
        signed short            unsigned short
        signed int              unsigned int
    The choice of type is inplementation-defined, but shall be capable
    of representing the values of all the members of the enumeration.

(B) Replace subclause 6.2.1.1 first paragraph by:

    A /char/, a /short int/, or an /int/ bit-field, or their signed or
    unsigned versions, may be used in an expression wherever an /int/ or
    /unsigned int/ may be used. If an /int/ can represent all values of
    the original type, the value is converted to an /int/; otherwise, it
    is converted to an /unsigned int/. These are called the /integral
    promotions/.

    An enumeration type may be used in an expression wherever the type
    that it is compatible with may be used. The integral promotions
    cause the value to be converted in the same way as that compatible
    type would be.

    All other arithmetic types are unchanged by the integral promotions.

and in subclause 6.5.2.2, change the first sentence of paragraph 4 to:

    Each enumerated type shall be compatible with some signed or
    unsigned integral type.

[At present, enumerated types *are* integral types; the intent is
clearly to make them compatible with one of the 10 types named in
6.1.2.5.]

====

Item 13:

Delete subclause 6.5.7 paragraph 2:

    There shall be no more initializers in an initializer list than
    there are objects to be initialized.

Compare example 11.

Change paragraph 12 to read:

    ... the first named member of a union. ...

[This isn't strictly necessary, but makes things clearer.]

====

Item 14:

If implicit int is to be removed from the Standard, then there is no
longer a good rationale for allowing functions with an object return
type to execute a return statement without an expression.

Change subclause 6.6.6.4 as follows. Add to paragraph 1 (Constraints):

    A /return/ statement without an expression shall only appear in a
    function whose return type is /void/.

Delete from paragraph 2:

    with and without expressions

Replace paragraph 4 by:

    If the } that terminates a function is reached, and the value of the
    function call is used by the caller, the behaviour is undefined.

Alternatively and preferably, delete paragraph 4 entirely and insert the
following paragraph in the Constraints, after paragraph 1:

    In a function whose return type is not /void/, the last statement
    before the terminating } shall have one of the following forms:
    - a /return/ statement with an expression;
    - a /goto/ statement;
    - a block in which the last statement before the terminating } is,
      recursively, one of these forms;
    - an /if/ statement with an /else/, in which each substatement is,
      recursively, one of these forms;
    - a /switch/ statement which is not the smallest enclosing /switch/
      or iteration statement of a /break/ statement, and in which the
      switch body is, recursively, one of these forms;
    - an iteration statement which is not the smallest enclosing
      /switch/ or iteration statement of a /break/ statement, and in
      which the controlling expression (/expression-2/ for a /for/
      statement) is, or is replaced by, a non-zero constant expression.

and delete the last sentence of subclause 5.1.2.2.3.

If this latter text is not adopted, the last word of 5.1.2.2.3 should be
changed to "unspecified" - the concept of undefined value is carefully
avoided elsewhere.

-- 
Clive D.W. Feather    | Associate Director  | Director
Tel: +44 181 371 1138 | Demon Internet Ltd. | CityScape Internet Services Ltd.
Fax: +44 181 371 1150 | <[email protected]>   | <[email protected]>
Written on my laptop - please reply to the Reply-To address <[email protected]>