On 2/29/2012 04:42, Robbert Krebbers wrote:
> thanks for your extensive reply.
>
> On 02/28/2012 10:26 PM, Shao Miller wrote:
>> No. I believe that the type of the expression is evaluated in this
>> circumstance.
> Well, in this particular circumstance (with the sizeof), I believe you
> are right. But in general, if we have
>
> 1 ? 0 : (int (*)[foo(42)]) 0
>
If there was a semi-colon before and after that, it would constitute a
"void expression."[6.3.2.2p1] Such an expression is evaluated for its
side-effects.
Similarly to what I mentioned else-thread to Mr. Jens Gustedt, the Value
Of The Conditional-Expression could be optimized away if it doesn't
involve any side-effects. There aren't any accesses of 'volatile'
objects, for example. The cast-expression doesn't involve any
side-effects, except for the call to 'foo' while computing the type-name
operand... So there _is_ a side-effect.
> I don't see any reason why an implementation _should_ evaluate the
> not-taken-branch. An implementation may very well ignore the types
> completely (e.g. if each pointer has the same representation regardless
> of its type).
I'm not so sure about that. A function call is a side-effect, so if
it's involved in the determination of a type, I don't see a license to
omit it.
void some_func(void) {
typedef int (* never_used_type)[foo(42)];
return;
}
Here the 'never_used_type' type is never used. Not only that, we don't
even have a "void expression," since this is a "declaration." That
means we don't have to worry about discarding or optimizing any value
computation away for some "expression-statement." But in order to
determine the type that 'never_used_type' will be, we have to call 'foo'.
>> /* Just like the following */
>> T * tmp;
>> /* 6.5.16.1p1 "both operands are pointers
>> * pointers to qualified or unqualified
>> * versions of compatible types" which means
>> * Keith's 6.7.6.2p6 applies (I think)
>> */
>> tmp = &a;
> I am not convinced here. Let me quote 6.7.6.2p6.
>
> For two array types to be compatible, both shall have
> compatible element types, and if both size specifiers
> are present, and are integer constant expressions,
> then both size specifiers shall have the same constant
> value. If the two array types are used in a context
> which requires them to be compatible, it is undefined
> behavior if the two size specifiers evaluate to unequal
> values.
>
> Since it is not the case that both size specifiers are present, we have
> that int(*)[] and int(*)[7] are compatible.
Ok. I had to look at 6.2.7p3 before I was able to read the quote above
as "For two array types to be compatible, both shall have compatible
element types. Stop. Furthermore, if both size specifiers are present
and both are integer constant expressions, then both size specifiers for
two compatible array types shall have the same constant value. Stop.
Furthermore, if both size specifiers are present and the two array types
are used in a context which requires them to be compatible, it is
undefined behaviour if the two size specifiers evaluate to unequal values."
This reminds me of using a function type with no parameter information.
int some_func(int w, int x, int y, int z) {
typedef int arr_unknown[];
typedef int func_unknown();
typedef int arr_4[4];
typedef int func_4(int, int, int, int);
typedef int arr_2[2];
typedef int func_2(int, int);
arr_unknown * a_u;
func_unknown * f_u;
arr_4 * some_arr = &(arr_4){w, x, y, z};
arr_2 * a_2;
func_2 * f_2;
a_2 = a_u = some_arr;
f_2 = f_u = some_func;
return 0;
}
> So, statically, it is all fine.
>
Newly-found agreement. :) So it seems that your example code doesn't
invoke UB where I thought it did.
However that doesn't change my opinion that the return-type of that
function does not depend on the function being called, but only on its
declaration.
> Now, if they are used in a context which requires them to be compatible,
> it is merely undefined behavior _if the two size specifiers_ evaluate to
> unequal values. But there are no two size specifiers, so I do not
> believe that this clause applies.
Ok.
>> I don't follow why that is. It seems to me that 'foo' is clearly
>> defined to return a pointer to the incomplete object type 'T'. I do not
>> believe that the 'return' (see below) has any influence on the type of
>> 'foo' or its return-type.
> Ah, I think I am confused with conditional operator whose resulting type
> is the composite type (which is int(*)[7] in the above case). For an
> assignment (and a function call) this is not to be the case, indeed.
Ok. Nice discussion. :)