Missing implicit cast when parsing C++ ?

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

Missing implicit cast when parsing C++ ?

Enea Zaffanella
According to the C++ standard, the operand of the logical negation
operator (!) is implicitly converted to type bool
(C++98/03 5.3.1p8, C++0x 5.3.1p9).

However, parsing this C++ code fragment using clang

bool foo() { return !1234; }

we obtain the following AST, with no implicit cast:

bool foo() (CompoundStmt 0x479b2f8 <ex.cc:1:12, col:28>
  (ReturnStmt 0x479b2d8 <col:14, col:22>
    (UnaryOperator 0x479b2b8 <col:21, col:22> '_Bool' prefix '!'
      (IntegerLiteral 0x479b290 <col:22> 'int' 1234))))

Usually, clang inserts all implicit casts in its AST.
Is the behavior above a _meant_ exception to this general rule?

(Side note: if the integer literal is replaced by some non-boolean
variable, an CK_LValueToRValue implicit cast is added, but again no cast
from the variable type to the Boolean type.)

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

Re: Missing implicit cast when parsing C++ ?

Abramo Bagnara-2
Il 06/04/2011 16:31, Enea Zaffanella ha scritto:

> According to the C++ standard, the operand of the logical negation
> operator (!) is implicitly converted to type bool
> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>
> However, parsing this C++ code fragment using clang
>
> bool foo() { return !1234; }
>
> we obtain the following AST, with no implicit cast:
>
> bool foo() (CompoundStmt 0x479b2f8 <ex.cc:1:12, col:28>
>   (ReturnStmt 0x479b2d8 <col:14, col:22>
>     (UnaryOperator 0x479b2b8 <col:21, col:22> '_Bool' prefix '!'
>       (IntegerLiteral 0x479b290 <col:22> 'int' 1234))))
>
> Usually, clang inserts all implicit casts in its AST.
> Is the behavior above a _meant_ exception to this general rule?
>
> (Side note: if the integer literal is replaced by some non-boolean
> variable, an CK_LValueToRValue implicit cast is added, but again no cast
> from the variable type to the Boolean type.)
I've attached a candidate patch to fix this. Ok to commit?

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

LNot-casts.patch (952 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Missing implicit cast when parsing C++ ?

Eli Friedman
In reply to this post by Enea Zaffanella
On Wed, Apr 6, 2011 at 7:31 AM, Enea Zaffanella <[hidden email]> wrote:

> According to the C++ standard, the operand of the logical negation
> operator (!) is implicitly converted to type bool
> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>
> However, parsing this C++ code fragment using clang
>
> bool foo() { return !1234; }
>
> we obtain the following AST, with no implicit cast:
>
> bool foo() (CompoundStmt 0x479b2f8 <ex.cc:1:12, col:28>
>  (ReturnStmt 0x479b2d8 <col:14, col:22>
>    (UnaryOperator 0x479b2b8 <col:21, col:22> '_Bool' prefix '!'
>      (IntegerLiteral 0x479b290 <col:22> 'int' 1234))))
>
> Usually, clang inserts all implicit casts in its AST.
> Is the behavior above a _meant_ exception to this general rule?

Probably nobody noticed... the C definition of "!x" is "x==0", and in
practice that's the same as the definition in C++.

-Eli

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

Re: Missing implicit cast when parsing C++ ?

Enea Zaffanella
Il 06/04/2011 20:44, Eli Friedman ha scritto:

> On Wed, Apr 6, 2011 at 7:31 AM, Enea Zaffanella <[hidden email]> wrote:
>> According to the C++ standard, the operand of the logical negation
>> operator (!) is implicitly converted to type bool
>> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>>
>> However, parsing this C++ code fragment using clang
>>
>> bool foo() { return !1234; }
>>
>> we obtain the following AST, with no implicit cast:
>>
>> bool foo() (CompoundStmt 0x479b2f8 <ex.cc:1:12, col:28>
>>  (ReturnStmt 0x479b2d8 <col:14, col:22>
>>    (UnaryOperator 0x479b2b8 <col:21, col:22> '_Bool' prefix '!'
>>      (IntegerLiteral 0x479b290 <col:22> 'int' 1234))))
>>
>> Usually, clang inserts all implicit casts in its AST.
>> Is the behavior above a _meant_ exception to this general rule?
>
> Probably nobody noticed... the C definition of "!x" is "x==0", and in
> practice that's the same as the definition in C++.
>
> -Eli

Yes, it might be the case that this can never affect traditional clients
such as code generators.
However, it could affect source-based tools that have to check for and,
e.g., forbid some implicit conversions.

The "problem" is put into greater evidence by the following code:
================
struct S {
  operator int() const { return 1234; }
} s;

bool bar1() { return !s.operator int(); }
bool bar2() { return !s; }
================

Here the dump shows that the argument of ! in bar1() is not converted to
bool, while this is the case for the argument of ! in bar2(), where the
int() conversion operator is called implicitly:

================
bool bar1() (CompoundStmt 0x36db030 <lnot.cc:5:13, col:41>
  (ReturnStmt 0x36db010 <col:15, col:38>
    (UnaryOperator 0x36daff0 <col:22, col:38> '_Bool' prefix '!'
      (CXXMemberCallExpr 0x36daf80 <col:23, col:38> 'int'
        (MemberExpr 0x36daf48 <col:23, col:34> 'int (void) const'
.operator int 0x36dac70
          (ImplicitCastExpr 0x36dafd8 <col:23> 'const struct S' lvalue
<NoOp>
            (DeclRefExpr 0x36daf10 <col:23> 'struct struct S':'struct S'
lvalue Var 0x36dadc0 's' 'struct struct S':'struct S')))))))


bool bar2() (CompoundStmt 0x36db230 <lnot.cc:6:13, col:26>
  (ReturnStmt 0x36db210 <col:15, col:23>
    (UnaryOperator 0x36db1f0 <col:22, col:23> '_Bool' prefix '!'
      (ImplicitCastExpr 0x36db1d8 <col:23> '_Bool' <IntegralToBoolean>
        (CXXMemberCallExpr 0x36db1b0 <col:23> 'int'
          (MemberExpr 0x36db178 <col:23, <invalid sloc>> 'int (void)
const' .operator int 0x36dac70
            (ImplicitCastExpr 0x36db160 <col:23> 'const struct S' lvalue
<NoOp>
              (DeclRefExpr 0x36db100 <col:23> 'struct struct S':'struct
S' lvalue Var 0x36dadc0 's' 'struct struct S':'struct S'))))))))
================

If you agree, we will commit the patch sent by Abramo (it passes all of
the tests in clang).

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

Re: Missing implicit cast when parsing C++ ?

Eli Friedman
In reply to this post by Abramo Bagnara-2
On Wed, Apr 6, 2011 at 9:43 AM, Abramo Bagnara <[hidden email]> wrote:

> Il 06/04/2011 16:31, Enea Zaffanella ha scritto:
>> According to the C++ standard, the operand of the logical negation
>> operator (!) is implicitly converted to type bool
>> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>>
>> However, parsing this C++ code fragment using clang
>>
>> bool foo() { return !1234; }
>>
>> we obtain the following AST, with no implicit cast:
>>
>> bool foo() (CompoundStmt 0x479b2f8 <ex.cc:1:12, col:28>
>>   (ReturnStmt 0x479b2d8 <col:14, col:22>
>>     (UnaryOperator 0x479b2b8 <col:21, col:22> '_Bool' prefix '!'
>>       (IntegerLiteral 0x479b290 <col:22> 'int' 1234))))
>>
>> Usually, clang inserts all implicit casts in its AST.
>> Is the behavior above a _meant_ exception to this general rule?
>>
>> (Side note: if the integer literal is replaced by some non-boolean
>> variable, an CK_LValueToRValue implicit cast is added, but again no cast
>> from the variable type to the Boolean type.)
>
> I've attached a candidate patch to fix this. Ok to commit?

Does this affect -O0 code generation for constructs like "if (!foo)"?

For references to the C++ standard, we generally prefer to use
"[expr.unary.op]" over "5.3.1", to make it easier to find in future
versions which might renumber the headings.

Otherwise, it should be fine.

-Eli

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

Re: Missing implicit cast when parsing C++ ?

John McCall
In reply to this post by Enea Zaffanella
On Apr 6, 2011, at 7:31 AM, Enea Zaffanella wrote:
> According to the C++ standard, the operand of the logical negation
> operator (!) is implicitly converted to type bool
> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>
> However, parsing this C++ code fragment using clang
>
> bool foo() { return !1234; }
>
> we obtain the following AST, with no implicit cast:

We consistently insert these implicit conversions everywhere else
in C++ that converts to bool;  this isn't an intentional oversight.

Instead of going through an expensive re-analysis, since you
already know that we're converting a scalar to a bool (which
always suceeds), you can just switch on getScalarTypeKind() to
find the appropriate cast kind.  Feel free to extract the logic from
SemaExprCXX.cpp:2187 out into its own function for this purpose.

Also, I'm not really sure that there's a good reason for us to not
represent these explicitly in C, except for the design questions
around operands that are already of type 'int'.

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

Re: Missing implicit cast when parsing C++ ?

Abramo Bagnara-2
Il 07/04/2011 08:57, John McCall ha scritto:

> On Apr 6, 2011, at 7:31 AM, Enea Zaffanella wrote:
>> According to the C++ standard, the operand of the logical negation
>> operator (!) is implicitly converted to type bool
>> (C++98/03 5.3.1p8, C++0x 5.3.1p9).
>>
>> However, parsing this C++ code fragment using clang
>>
>> bool foo() { return !1234; }
>>
>> we obtain the following AST, with no implicit cast:
>
> We consistently insert these implicit conversions everywhere else
> in C++ that converts to bool;  this isn't an intentional oversight.
>
> Instead of going through an expensive re-analysis, since you
> already know that we're converting a scalar to a bool (which
> always suceeds), you can just switch on getScalarTypeKind() to
> find the appropriate cast kind.  Feel free to extract the logic from
> SemaExprCXX.cpp:2187 out into its own function for this purpose.

Committed in r129066.

>
> Also, I'm not really sure that there's a good reason for us to not
> represent these explicitly in C, except for the design questions
> around operands that are already of type 'int'.

This would be incongruent with C99 6.5.3.3p5.

Think also for:

int f(void* p) {
  return !p;
}

if we put an implicit cast around p we'd be forced to change logical not
argument type and to violate the standard.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Missing implicit cast when parsing C++ ?

John McCall
On Apr 7, 2011, at 2:31 AM, Abramo Bagnara wrote:
Il 07/04/2011 08:57, John McCall ha scritto:
Also, I'm not really sure that there's a good reason for us to not
represent these explicitly in C, except for the design questions
around operands that are already of type 'int'.

This would be incongruent with C99 6.5.3.3p5.

I'm not that interested in the AST being slavishly obedient to the
standard down to the types of operands after implicit conversion.
The conversion's cast kind pretty clearly identifies what's going on.

But I don't much care either way.

John.

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