Doubts about constructor calls (and functional casts).

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

Doubts about constructor calls (and functional casts).

Enea Zaffanella
Hello.

I am a bit confused regarding the AST that is generated by clang++ when
handling implicit/explicit calls to constructors. I would be grateful if
someone would clarify a few points by going through the following examples.


Let us consider the following struct definition:
==============
struct S {
   S(int);
};
==============
which is dumped by clang++ as follows (no surprise here):
==============
struct S {
public:
     struct S;
     S(int);
     inline S(struct S const &);
     inline struct S &operator=(struct S const &);
     inline void ~S();
};
=============


If I construct an S object using direct initialization
     S s1(1);
I get the following (which is what I am expecting):
=============
   (DeclStmt 0x1d5eba0 <line:6:3, col:10>
     0x1d5ea60 "struct S s1 =
       (CXXConstructExpr 0x1d5eb30 <col:5, col:8> 'struct S''void (int)'
         (IntegerLiteral 0x1d5eac0 <col:8> 'int' 1))"
=============


If I now try with this variant
      S s2 = 2;
I get the following ... again, this is more or less what I was expecting:
=============
   (DeclStmt 0x1d5f1c0 <line:7:3, col:11>
     0x1d5f000 "struct S s2 =
       (CXXConstructExpr 0x1d5f150 <col:5, col:10> 'struct S''void
(struct S const &)' elidable
         (ImplicitCastExpr 0x1d5f110 <col:10> 'struct S'
<ConstructorConversion>
           (CXXConstructExpr 0x1d5f0a0 <col:10> 'struct S''void (int)'
             (IntegerLiteral 0x1d5f060 <col:10> 'int' 2))))"
=============
I guess that the implicit cast between the two constructor calls is
meant to convert the plain S type into a "const S&" type, so that it can
be passed as an argument to the (elidable) copy constructor.
Am I correct?


But then I get to the following case
     S s3 = S(3);
for which I get the following AST:
=============
   (DeclStmt 0x1d5f430 <line:8:3, col:14>
     0x1d5f1f0 "struct S s3 =
       (ImplicitCastExpr 0x1d5f3f0 <col:10, col:13> 'struct S'
<ConstructorConversion>
         (CXXConstructExpr 0x1d5f380 <col:10, col:13> 'struct S''void
(struct S const &)' elidable
           (ImplicitCastExpr 0x1d5f340 <col:10, col:13> 'struct S const'
<NoOp>
             (CXXFunctionalCastExpr 0x1d5f300 <col:10, col:13> 'struct
S' functional cast to struct S
               (CXXConstructExpr 0x1d5f290 <col:10, col:12> 'struct
S''void (int)'
                 (IntegerLiteral 0x1d5f250 <col:12> 'int' 3))))))"
=============

Here there are two things that I do not understand.

First, I cannot see why the result of the inner CXXConstructorExpr call
should be fed to a CXXFunctionalCastExpr. I may agree that the
initializer of s3 is a functional cast expression ... but then I would
expect that the argument of this functional cast is the integer literal,
not the struct S object returned by the constructor.
In other words, to my eyes, the presence of the functional cast should
exclude the presence of the inner constructor call, or vice versa.
Is my reasoning missing some important point?

Second, I cannot see why the result of the external (elidable) copy
constructor call is (again) implicitly cast before being used as an
initializer for s3. There seems to be no reason for such an implicit
cast and, as a matter of fact, such a cast was not used in the previous
example (when initializing s2).

I would be grateful if someone either confirm my doubts or show to me
where is the gap in my reasoning.

Regards,
Enea Zaffanella.

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

Re: Doubts about constructor calls (and functional casts).

Enea Zaffanella
Hello.

I have seen no answer to this post:

http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-February/008049.html


I know people is busy due to the release ... this is just a reminder.

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

Re: Doubts about constructor calls (and functional casts).

John McCall
In reply to this post by Enea Zaffanella

On Feb 27, 2010, at 12:06 AM, Enea Zaffanella wrote:

> Hello.
>
> I am a bit confused regarding the AST that is generated by clang++ when
> handling implicit/explicit calls to constructors. I would be grateful if
> someone would clarify a few points by going through the following examples.
>
>
> Let us consider the following struct definition:
> ==============
> struct S {
>   S(int);
> };
> ==============
> which is dumped by clang++ as follows (no surprise here):
> ==============
> struct S {
> public:
>     struct S;
>     S(int);
>     inline S(struct S const &);
>     inline struct S &operator=(struct S const &);
>     inline void ~S();
> };
> =============
>
>
> If I construct an S object using direct initialization
>     S s1(1);
> I get the following (which is what I am expecting):
> =============
>   (DeclStmt 0x1d5eba0 <line:6:3, col:10>
>     0x1d5ea60 "struct S s1 =
>       (CXXConstructExpr 0x1d5eb30 <col:5, col:8> 'struct S''void (int)'
>         (IntegerLiteral 0x1d5eac0 <col:8> 'int' 1))"
> =============
>
>
> If I now try with this variant
>      S s2 = 2;
> I get the following ... again, this is more or less what I was expecting:
> =============
>   (DeclStmt 0x1d5f1c0 <line:7:3, col:11>
>     0x1d5f000 "struct S s2 =
>       (CXXConstructExpr 0x1d5f150 <col:5, col:10> 'struct S''void
> (struct S const &)' elidable
>         (ImplicitCastExpr 0x1d5f110 <col:10> 'struct S'
> <ConstructorConversion>
>           (CXXConstructExpr 0x1d5f0a0 <col:10> 'struct S''void (int)'
>             (IntegerLiteral 0x1d5f060 <col:10> 'int' 2))))"
> =============
> I guess that the implicit cast between the two constructor calls is
> meant to convert the plain S type into a "const S&" type, so that it can
> be passed as an argument to the (elidable) copy constructor.
> Am I correct?
>
>
> But then I get to the following case
>     S s3 = S(3);
> for which I get the following AST:
> =============
>   (DeclStmt 0x1d5f430 <line:8:3, col:14>
>     0x1d5f1f0 "struct S s3 =
>       (ImplicitCastExpr 0x1d5f3f0 <col:10, col:13> 'struct S'
> <ConstructorConversion>
>         (CXXConstructExpr 0x1d5f380 <col:10, col:13> 'struct S''void
> (struct S const &)' elidable
>           (ImplicitCastExpr 0x1d5f340 <col:10, col:13> 'struct S const'
> <NoOp>
>             (CXXFunctionalCastExpr 0x1d5f300 <col:10, col:13> 'struct
> S' functional cast to struct S
>               (CXXConstructExpr 0x1d5f290 <col:10, col:12> 'struct
> S''void (int)'
>                 (IntegerLiteral 0x1d5f250 <col:12> 'int' 3))))))"
> =============
>
> Here there are two things that I do not understand.
>
> First, I cannot see why the result of the inner CXXConstructorExpr call
> should be fed to a CXXFunctionalCastExpr. I may agree that the
> initializer of s3 is a functional cast expression ... but then I would
> expect that the argument of this functional cast is the integer literal,
> not the struct S object returned by the constructor.
> In other words, to my eyes, the presence of the functional cast should
> exclude the presence of the inner constructor call, or vice versa.
> Is my reasoning missing some important point?

This is a strange representation, and it looks even stranger when the functional cast is actually invoking a user-defined conversion.  CodeGen aggressively elides the constructor calls (in most cases; I don't enough about that corner of the standard to know if it's missing legal elisions), so it's just an internal-representation issue rather than also being a performance issue.  Still, it's not a good representation, and if the elision optimization is disabled (which is a supported configuration, I think) it might mean we make too many copies.

> Second, I cannot see why the result of the external (elidable) copy
> constructor call is (again) implicitly cast before being used as an
> initializer for s3. There seems to be no reason for such an implicit
> cast and, as a matter of fact, such a cast was not used in the previous
> example (when initializing s2).

I don't understand this either.

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: Doubts about constructor calls (and functional casts).

Anders Carlsson-2

On Mar 12, 2010, at 10:55 AM, John McCall wrote:


On Feb 27, 2010, at 12:06 AM, Enea Zaffanella wrote:

But then I get to the following case
   S s3 = S(3);
for which I get the following AST:
=============
 (DeclStmt 0x1d5f430 <line:8:3, col:14>
   0x1d5f1f0 "struct S s3 =
     (ImplicitCastExpr 0x1d5f3f0 <col:10, col:13> 'struct S'
<ConstructorConversion>
       (CXXConstructExpr 0x1d5f380 <col:10, col:13> 'struct S''void
(struct S const &)' elidable
         (ImplicitCastExpr 0x1d5f340 <col:10, col:13> 'struct S const'
<NoOp>
           (CXXFunctionalCastExpr 0x1d5f300 <col:10, col:13> 'struct
S' functional cast to struct S
             (CXXConstructExpr 0x1d5f290 <col:10, col:12> 'struct
S''void (int)'
               (IntegerLiteral 0x1d5f250 <col:12> 'int' 3))))))"
=============

Here there are two things that I do not understand.

First, I cannot see why the result of the inner CXXConstructorExpr call
should be fed to a CXXFunctionalCastExpr. I may agree that the
initializer of s3 is a functional cast expression ... but then I would
expect that the argument of this functional cast is the integer literal,
not the struct S object returned by the constructor.
In other words, to my eyes, the presence of the functional cast should
exclude the presence of the inner constructor call, or vice versa.
Is my reasoning missing some important point?

This is a strange representation, and it looks even stranger when the functional cast is actually invoking a user-defined conversion.  CodeGen aggressively elides the constructor calls (in most cases; I don't enough about that corner of the standard to know if it's missing legal elisions), so it's just an internal-representation issue rather than also being a performance issue.  Still, it's not a good representation, and if the elision optimization is disabled (which is a supported configuration, I think) it might mean we make too many copies.


Actually, it's not that strange :)

The CXXFunctionalCastExpr is just the syntactical representation, and the inner CXXConstructExpr has all the constructor information - which constructor to call, default arguments etc.

Anders

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

Re: Doubts about constructor calls (and functional casts).

John McCall

On Mar 12, 2010, at 11:00 AM, Anders Carlsson wrote:


On Mar 12, 2010, at 10:55 AM, John McCall wrote:


On Feb 27, 2010, at 12:06 AM, Enea Zaffanella wrote:

But then I get to the following case
   S s3 = S(3);
for which I get the following AST:
=============
 (DeclStmt 0x1d5f430 <line:8:3, col:14>
   0x1d5f1f0 "struct S s3 =
     (ImplicitCastExpr 0x1d5f3f0 <col:10, col:13> 'struct S'
<ConstructorConversion>
       (CXXConstructExpr 0x1d5f380 <col:10, col:13> 'struct S''void
(struct S const &)' elidable
         (ImplicitCastExpr 0x1d5f340 <col:10, col:13> 'struct S const'
<NoOp>
           (CXXFunctionalCastExpr 0x1d5f300 <col:10, col:13> 'struct
S' functional cast to struct S
             (CXXConstructExpr 0x1d5f290 <col:10, col:12> 'struct
S''void (int)'
               (IntegerLiteral 0x1d5f250 <col:12> 'int' 3))))))"
=============

Here there are two things that I do not understand.

First, I cannot see why the result of the inner CXXConstructorExpr call
should be fed to a CXXFunctionalCastExpr. I may agree that the
initializer of s3 is a functional cast expression ... but then I would
expect that the argument of this functional cast is the integer literal,
not the struct S object returned by the constructor.
In other words, to my eyes, the presence of the functional cast should
exclude the presence of the inner constructor call, or vice versa.
Is my reasoning missing some important point?

This is a strange representation, and it looks even stranger when the functional cast is actually invoking a user-defined conversion.  CodeGen aggressively elides the constructor calls (in most cases; I don't enough about that corner of the standard to know if it's missing legal elisions), so it's just an internal-representation issue rather than also being a performance issue.  Still, it's not a good representation, and if the elision optimization is disabled (which is a supported configuration, I think) it might mean we make too many copies.


Actually, it's not that strange :)

The CXXFunctionalCastExpr is just the syntactical representation, and the inner CXXConstructExpr has all the constructor information - which constructor to call, default arguments etc.

Okay, so you're saying that a CXXFunctionalCastExpr always contains a CastExpr as its immediate sub-expressions, and that that CastExpr is what actually conveys the semantics of the cast?  I'm not thrilled with that, but it's probably better than duplicating the cast logic N times over.

That said, can you similarly justify this representation for conversion operators?  It looks like we get an extra, unelidable CXXConstructExpr.

struct S { S(unsigned); S(const S &value); };
struct T { operator S() const; };
void test() {
  T t;
  S x = S(t);
}

void test() (CompoundStmt 0x103618f20 </tmp/red.cpp:10:13, line:13:1>
  (DeclStmt 0x103618b60 <line:11:3, col:6>
    0x103618b10 "T t"
  (DeclStmt 0x103617d10 <line:12:3, col:13>
    0x103617080 "S x =
      (ImplicitCastExpr 0x103618ef0 <col:9, col:12> 'struct S' <ConstructorConversion>
        (CXXConstructExpr 0x103618ea0 <col:9, col:12> 'struct S''void (struct S const &)' elidable
          (ImplicitCastExpr 0x103618e70 <col:9, col:12> 'struct S const' <NoOp>
            (CXXFunctionalCastExpr 0x103618e30 <col:9, col:12> 'struct S' functional cast to struct S
              (CXXConstructExpr 0x103618de0 <col:9, col:11> 'struct S''void (struct S const &)'
                (ImplicitCastExpr 0x103618db0 <col:11> 'struct S const' <NoOp>
                  (ImplicitCastExpr 0x103618d80 <col:11> 'struct S' <UserDefinedConversion>
                    (CXXMemberCallExpr 0x103618d40 <col:11> 'struct S'
                      (MemberExpr 0x103618d00 <col:11, <invalid sloc>> 'struct S (void) const' .operator S 0x103618590
                        (ImplicitCastExpr 0x103618cd0 <col:11> 'struct T const' <NoOp> lvalue
                          (DeclRefExpr 0x103618be0 <col:11> 'struct T' Var='t' 0x103618b10)))))))))))")

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: Doubts about constructor calls (and functional casts).

Zhongxing Xu
In reply to this post by Enea Zaffanella
This strangeness looks to be cured:

code:

  A x = 3;
  A y = A(3);

now is parsed to:

(DeclStmt 0x32815f0 <line:10:3, col:10>
    0x32814e0 "A x =
      (CXXConstructExpr 0x3281580 <col:5, col:9> 'class A''void (class A const &)' elidable
        (ImplicitCastExpr 0x3281540 <col:9> 'class A' <ConstructorConversion>
          (CXXConstructExpr 0x3282760 <col:9> 'class A''void (int)'
            (IntegerLiteral 0x32827b0 <col:9> 'int' 3))))"
  (DeclStmt 0x3281640 <line:11:3, col:13>
    0x3280660 "A y =
      (ImplicitCastExpr 0x3281d60 <col:9, col:12> 'class A' <ConstructorConversion>
        (CXXConstructExpr 0x3281cf0 <col:9, col:12> 'class A''void (class A const &)' elidable
          (ImplicitCastExpr 0x3281cb0 <col:9, col:12> 'class A const' <NoOp>
            (CXXFunctionalCastExpr 0x3281c70 <col:9, col:12> 'class A' functional cast to class A
              (CXXConstructExpr 0x3281c20 <col:9, col:11> 'class A''void (int)'
                (IntegerLiteral 0x3281b60 <col:11> 'int' 3))))))")


2010/2/27 Enea Zaffanella <[hidden email]>
Hello.

I am a bit confused regarding the AST that is generated by clang++ when
handling implicit/explicit calls to constructors. I would be grateful if
someone would clarify a few points by going through the following examples.


Let us consider the following struct definition:
==============
struct S {
  S(int);
};
==============
which is dumped by clang++ as follows (no surprise here):
==============
struct S {
public:
    struct S;
    S(int);
    inline S(struct S const &);
    inline struct S &operator=(struct S const &);
    inline void ~S();
};
=============


If I construct an S object using direct initialization
    S s1(1);
I get the following (which is what I am expecting):
=============
  (DeclStmt 0x1d5eba0 <line:6:3, col:10>
    0x1d5ea60 "struct S s1 =
      (CXXConstructExpr 0x1d5eb30 <col:5, col:8> 'struct S''void (int)'
        (IntegerLiteral 0x1d5eac0 <col:8> 'int' 1))"
=============


If I now try with this variant
     S s2 = 2;
I get the following ... again, this is more or less what I was expecting:
=============
  (DeclStmt 0x1d5f1c0 <line:7:3, col:11>
    0x1d5f000 "struct S s2 =
      (CXXConstructExpr 0x1d5f150 <col:5, col:10> 'struct S''void
(struct S const &)' elidable
        (ImplicitCastExpr 0x1d5f110 <col:10> 'struct S'
<ConstructorConversion>
          (CXXConstructExpr 0x1d5f0a0 <col:10> 'struct S''void (int)'
            (IntegerLiteral 0x1d5f060 <col:10> 'int' 2))))"
=============
I guess that the implicit cast between the two constructor calls is
meant to convert the plain S type into a "const S&" type, so that it can
be passed as an argument to the (elidable) copy constructor.
Am I correct?


But then I get to the following case
    S s3 = S(3);
for which I get the following AST:
=============
  (DeclStmt 0x1d5f430 <line:8:3, col:14>
    0x1d5f1f0 "struct S s3 =
      (ImplicitCastExpr 0x1d5f3f0 <col:10, col:13> 'struct S'
<ConstructorConversion>
        (CXXConstructExpr 0x1d5f380 <col:10, col:13> 'struct S''void
(struct S const &)' elidable
          (ImplicitCastExpr 0x1d5f340 <col:10, col:13> 'struct S const'
<NoOp>
            (CXXFunctionalCastExpr 0x1d5f300 <col:10, col:13> 'struct
S' functional cast to struct S
              (CXXConstructExpr 0x1d5f290 <col:10, col:12> 'struct
S''void (int)'
                (IntegerLiteral 0x1d5f250 <col:12> 'int' 3))))))"
=============

Here there are two things that I do not understand.

First, I cannot see why the result of the inner CXXConstructorExpr call
should be fed to a CXXFunctionalCastExpr. I may agree that the
initializer of s3 is a functional cast expression ... but then I would
expect that the argument of this functional cast is the integer literal,
not the struct S object returned by the constructor.
In other words, to my eyes, the presence of the functional cast should
exclude the presence of the inner constructor call, or vice versa.
Is my reasoning missing some important point?

Second, I cannot see why the result of the external (elidable) copy
constructor call is (again) implicitly cast before being used as an
initializer for s3. There seems to be no reason for such an implicit
cast and, as a matter of fact, such a cast was not used in the previous
example (when initializing s2).

I would be grateful if someone either confirm my doubts or show to me
where is the gap in my reasoning.

Regards,
Enea Zaffanella.

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


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