Defect Report #040

Submission Date: 10 Dec 92
Submittor: WG14
Source: X3J11/91-062 (Derek M. Jones)
Question 1
Composite type
Rule for function parameter compatibility, subclause 6.7,1, page 82, lines 24-25:
void f(const int);
void f(int a)
{
a = 4;
}
In the above case what is the composite type of f? The legality of the assignment to a depends on the answer.
int f(int a[4]);
int f(int a[5]);
The parameters are compatible because they are converted to pointer to ..., but what is the composite type?
Response
void f(const int);
void f(int a)
{
a = 4;
}
What is the composite type of f?
Answer: void f(int). Defect Report #013, Question 1 describes the correct manner for constructing the composite type.
Is the assignment valid?
Answer: Yes. The type of a parameter is independent of the composite type of the function, so the assignment is valid (cf. subclause 6.7.1).
Another example:
int f(int a[4]);
int f(int a[5]);
The parameters are compatible because they are converted to pointer to ..., but what is the composite type?
Answer: The response to the Defect Report mentioned above answers this question as well.
Question 2
Is an implementation that fails to equal (or exceed) the value of an environmental limit conforming? Subclause 5.2.4 says that those in that subclause must be equalled in a conforming implementation. There is no such wording for the environmental limits in the Library (subclauses 7.9.2, 7.9.3, 7.9.4.4, 7.9.6.1, 7.10.2.1).
Correction
Add to subclause G.2, page 203:
- A call to a library function exceeds an environmental limit (7.9.2, 7.9.3, 7.9.4.4, 7.9.6.1, 7.10.2.1).
Question 3
Is an ``environmental constraint'' a constraint?
In subclause 7.6.1.1, page 118, lines 22-30, we have a set of environmental constraints on where setjmp may occur.
Does violating these rules require a constraint error to be flagged, or is it undefined behavior?
Some examples:
i = setjmp(a);
if (setjmp(a) == i)
...
Response

Must an implementation diagnose violations of environmental constraints?
Answer: Diagnostics are not required for constraint violations in clause 7, since subclause 5.1.1.3 refers to a constraint as defined in clause 3, which applies to language elements only.
Question 4
For the fragment
if (a**b||c++d)
;
Defect Report #017 Question 39 states that this is lexed as:

  1. {if} {(} {a} {<<} {b} {||} {c} {>>} {d} {)}
    not as:
  2. {if} {(} {a} {**b||c++} {d} {)}
    The rationale for this interpretation was that the constraint in subclause 6.1.7, page 32, lines 33-34 disallowed a header name preprocessing token anywhere except within a #include. Since the header name preprocessing token could not exist it was not lexed as such.
    It was pointed out that the ``longest possible token'' rule was not influenced by rules elsewhere in the C Standard, i.e. i+++++j is lexed as:
  3. {i} {++} {++} {+} {j}
    not as:
  4. {i} {++} {+} {++} {j}
Now (c) is a constraint violation by subclause 6.3.2.4, page 42, lines 38-39, the operand of the second ++ is not a modifiable lvalue. But this constraint does not require that the input be re-lexed to form the preprocessing tokens given in (d), which is conforming code.
As the UK C Panel saw it, the first example should be lexed as given in (b) and a diagnostic issued. Having violated a constraint, we are now into undefined behavior. An implementation could define the behavior in this circumstance to be a re-lex of the input to produce the preprocessing tokens given in (a).
As far as the user was concerned, they would get the expected behavior with the added value of a diagnostic being issued.
All those present felt that the interpretation was incorrect and recommended that the UK ask the Committee to reconsider its decision.
To summarize, there is no ambiguity in the C Standard and the original X3J11 interpretation is incorrect.
Response
Is a diagnostic required for an input such as
if (a**b||c++d)
because of a violation of the constraint specified in subclause 6.1.7, page 32, lines 33-34?
Answer: No. Our response to Defect Report #017 Question 39 addresses this issue.
Question 5
In the constraint for subclause 6.5.2, page 59, lines 2-4: What does the C Standard mean when it says ``set?''
Does it mean that the construct:
int int i;
violates a constraint?
It has been suggested that this wording was left vague to allow such constructs as long long (which is supported by some compilers) to fall into the undefined behavior category.
Would the Committee clarify the situation with regard to duplicate type specifiers? Do such constructs result in a constraint error or undefined behavior?
The related case static static is explicitly ruled out by the constraints in the previous subclause.
Additionally, volatile volatile is ruled out by the constraint in subclause 6.5.3.
Response
Example:
int int i;
Must this be diagnosed?
Answer: Yes. It is allowed to rearrange the order of type specifiers within a set, but not to duplicate them (cf. subclause 6.5.2). Thus int int is a constraint violation.
Question 6
The definition of the offsetof macro in subclause 7.1.6 does not cover all its possible occurrences:
  1. There are no restrictions on the structure being a completed type.
    struct t1 {
    char c;
    short s;
    int i[offsetof(struct t1, s)];
    }
    When discussing the use of incomplete types, recourse usually has to be made to the rules relating to where an object of unknown size may appear.
    Would the Committee agree that there are not any rules prohibiting the above construction?
  2. In this structure we are asked to find the offset of a field that has not yet been encountered:
    struct t2 {
    char c;
    union {
    int i[offsetof(struct t2, s)];
    short s;
    } u;
    };
    Would the Committee agree that there do not appear to be any rules that make this construct illegal?
  3. The following structure has infinitely many ``solutions:''
    struct t3 {
    char a[offsetof(struct t3, i)];
    int i;
    }
    since char has size 1, any size of array will be the same as the offsetof the field i.
  4. The following structure has no ``solutions:''
    struct t4 {
    int a[offsetof(struct t3, i)];
    int i;
    }
    int
    is always larger than 1.
Response
  1. Example:
    struct t1 {
    char c;
    short s;
    int i[offsetof(struct t1, s)];
    };
    This is not a valid use of the offsetof macro. The hypothetical static type t; declaration required for offsetof (cf. subclause 7.1.6) could not have validly appeared prior to the invocation of offsetof because the type struct t1 is incomplete (cf. subclause 6.7.2); therefore the offsetof invocation is not strictly conforming.
  2. The answer is the same as (a) above. In addition, the members mentioned in these invocations are not in scope.
  3. The answer is the same as (a) above. In addition, the members mentioned in these invocations are not in scope.
  4. The answer is the same as (a) above. In addition, the members mentioned in these invocations are not in scope.
Question 7
sizeof various identifiers (subclause 7.1.6)
a)
void f(int c, char a[sizeof(c)]);
b)
int i;
struct {
int i;
char a[sizeof(i)];
};
Now the argument to sizeof must be an expression or a type.
In (a) is c an expression? I think not because:
expression -> object -> has storage in execution envrionment
and c does not have storage allocated to it. So (a) violates a semantic ``shall'' and is undefined behavior.
Now in (b) the field i is obviously not an expression. But is it visible? Like the outer i, it has file scope. However, it is in a different namespace. There are no rules for namespace resolution in the sizeof subclause.
So is (b) legal or undefined behavior?
Response
  1. Example:
    void f(int c, char a[sizeof(c)]);
    The reference to c is an expression because the previosly declared identifier designates a function parameter (cf. subclause 6.5.4.3), which is an object (subclause 3.15), thus meeting the requirement in subclause 6.3.1.
  2. Another example:
    int i;
    struct {
    int i;
    char a[sizeof(i)];
    };
    In C, this is okay. Subclause 6.1.2.3, Name spaces of identifiers, requires that i in the sizeof expression refers to the external i, not the member.
    Question 8
    Refer to subclause 6.1.2.5, page 22, lines 32-36:

  3. char c = 7; /* implementation defined behavior, since 7 need not
    be a member of the basic execution character set
    */
  4. c = 'a'; /* ok */
    c++; /*
    implementation defined */
    c)
    c = '1'; /* ok */
    c++; /*
    ok? */
    It has been suggested that the above constructs are not implementation defined.
    Subclause 6.1.3.4, page 29, lines 30-33:
  5. c = '\07'; /* what is in the source/execution character set is
    given in subclause 5.2.1. Anything else is an extension.
    */
    e)
    c = '$';
    It has been suggested that characters may be added to the basic source/execution character set without implementation defined behavior being invoked. (I guess my position on this item can be deduced from the text.)
Response
  1. Subclause 6.1.2.5 says ``An object declared as type char is large enough to store any member of the basic execution character set... If other quantities are stored in a char object, the behavior is implementation-defined: the values are treated as either signed or nonnegative integers.'' Consider this example:
    char c = 7;
    The assignment c = 7 is not implementation-defined because, from a reasonable reading of subclause 6.1.2.5, it is clear that the only implementation-defined behavior here is the signedness of the value of the char object.
  2. Another example:
    c = 'a';
    c++;

    The increment of c after assigning an 'a' to it is defined by the implementation because the numeric encoding of 'a' is defined by the implementation. If 'a' were equal to CHAR_MAX, the increment could even cause an overflow (cf. subclause 5.2.1).
  3. Another example:
    c = '1';
    c++;

    The increment of c after assigning a '1' to it is not implementation-defined because the characters '0' through '9' are required to be a contiguous range (cf. subclause 5.2.1). Thus, the result is '2'.
  4. Another example:
    c = '\07';
    The value of the character constant '\07' is defined by the C Standard (cf. subclause 6.1.3.4, page 29, line 10-13). The implementation-defined behavior of some escape sequences, described on page 29, lines 30-33, is clarified in the example on page 30, lines 8-14.
  5. Another example:
    c = '$';
    If $ is in the execution character set, the value of '$' is locale-specific and so must be defined by the implementation (cf. subclause 5.2.1).
Question 9
re: UK request for interpretation cai027 ( Defect Report #017 Question 27)
X3J11 refs: 90-056, 90-083
It has been pointed out, and the UK C panel agreed at its last meeting, that the request for interpretation was unnecessary. The C Standard was clear and unambiguous as is.
To make matters worse, X3J11 appears to have given an interpretation that is the opposite of what the C Standard says.
The UK would like to withrdaw this request for interpretation and ask the Committee to reconsider its position.
Response
We reaffirm the previous interpretation.
Previous Defect Report < - > Next Defect Report