Cast to type with side effects

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Cast to type with side effects

Abramo Bagnara-2

int g();

int main() {
  //  enum { x = (g(), 0) };
  enum { x = (int)(int(*)[g()])0 };
  return 0;
}

Constant expression evaluator seems to (wrongly IMHO) believe that types
cannot have side effects.

Do you confirm we have a bug here?
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Cast to type with side effects

Douglas Gregor

On Sep 22, 2010, at 8:13 AM, Abramo Bagnara wrote:

>
> int g();
>
> int main() {
>  //  enum { x = (g(), 0) };
>  enum { x = (int)(int(*)[g()])0 };
>  return 0;
> }
>
> Constant expression evaluator seems to (wrongly IMHO) believe that types
> cannot have side effects.
>
> Do you confirm we have a bug here?

I don't think this was meant to be well-formed C99, although it seems like there is a gap in the C99 standard here. In particular, C99 6.7.5.2p2 says:

  An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope.

Now, we're in a type-name (C99 6.7.6), so there is no identifier... however, the general view of type-names is that they are declarators without the identifier, which implies that C99 6.7.5p2 applies in this case. C99 6.7.7p3 strengthens our case somewhat, even though it is about typedefs, because it says:

        Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution.

There is no way to reach an enumerator constant in the order of execution, so it doesn't make sense to have a VLA there.

Oh, and EDG rejects this code in C99 mode.

Long story short: yes, there is a bug here, which is that Clang accepts this ill-formed program. It should reject the use of a variably-modified type in a cast.

        - Doug

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Cast to type with side effects

Abramo Bagnara-2
Il 22/09/2010 17:55, Douglas Gregor ha scritto:

>
> On Sep 22, 2010, at 8:13 AM, Abramo Bagnara wrote:
>
>>
>> int g();
>>
>> int main() {
>>  //  enum { x = (g(), 0) };
>>  enum { x = (int)(int(*)[g()])0 };
>>  return 0;
>> }
>>
>> Constant expression evaluator seems to (wrongly IMHO) believe that types
>> cannot have side effects.
>>
>> Do you confirm we have a bug here?
>
> I don't think this was meant to be well-formed C99, although it seems like there is a gap in the C99 standard here. In particular, C99 6.7.5.2p2 says:
>
>   An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope.
>
> Now, we're in a type-name (C99 6.7.6), so there is no identifier... however, the general view of type-names is that they are declarators without the identifier, which implies that C99 6.7.5p2 applies in this case. C99 6.7.7p3 strengthens our case somewhat, even though it is about typedefs, because it says:
>
> Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution.
>
> There is no way to reach an enumerator constant in the order of execution, so it doesn't make sense to have a VLA there.
>
> Oh, and EDG rejects this code in C99 mode.
>
> Long story short: yes, there is a bug here, which is that Clang accepts this ill-formed program. It should reject the use of a variably-modified type in a cast.

I believe this conclusion is far too strict:

int x = (int)(int(*)[g()])0;

I think this is perfectly ok and it has side effects that have to be
executed (and clang behave as expected).

The clang problem is *not* to accept VM types in cast, but it is to
ignore their inner side effects in constant evaluation.

I'm missing something?

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Cast to type with side effects

Douglas Gregor

On Sep 22, 2010, at 9:08 AM, Abramo Bagnara wrote:

Il 22/09/2010 17:55, Douglas Gregor ha scritto:

On Sep 22, 2010, at 8:13 AM, Abramo Bagnara wrote:


int g();

int main() {
//  enum { x = (g(), 0) };
enum { x = (int)(int(*)[g()])0 };
return 0;
}

Constant expression evaluator seems to (wrongly IMHO) believe that types
cannot have side effects.

Do you confirm we have a bug here?

I don't think this was meant to be well-formed C99, although it seems like there is a gap in the C99 standard here. In particular, C99 6.7.5.2p2 says:

 An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope.

Now, we're in a type-name (C99 6.7.6), so there is no identifier... however, the general view of type-names is that they are declarators without the identifier, which implies that C99 6.7.5p2 applies in this case. C99 6.7.7p3 strengthens our case somewhat, even though it is about typedefs, because it says:

Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution.

There is no way to reach an enumerator constant in the order of execution, so it doesn't make sense to have a VLA there.

Oh, and EDG rejects this code in C99 mode.

Long story short: yes, there is a bug here, which is that Clang accepts this ill-formed program. It should reject the use of a variably-modified type in a cast.

I believe this conclusion is far too strict:

int x = (int)(int(*)[g()])0;

I think this is perfectly ok and it has side effects that have to be
executed (and clang behave as expected).

Yes, good point. This is well-formed; I maintain that the original example is still ill-formed.

The clang problem is *not* to accept VM types in cast, but it is to
ignore their inner side effects in constant evaluation.

I'm missing something?

The import issue here is that the value of an enumeration-constant is a constant-expression, and an expression involving a VLA type is not a constant expression. That's why EDG rejects the original example but not your revised example, because the call to g() makes the enumerator's value non-constant. In particular, C99 6.6p6:

Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.

So it's a (different) accepts-valid bug in Clang than the one I was thinking of.

- Doug


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev