15172 – [3.3/3.4 regression] Copy constructor optimization in aggregate initialization (original) (raw)
| Description Michael Spencer 2004-04-27 16:59:35 UTC gcc configured with: --with-gnu-as --with-gnu-ld A class member of an aggregate appears to be initialized in temporary storage then byte-copied to its final location, as this code shows: int printf (const char *format, ...); struct A { A * _this; A () : _this (this) { printf ("A () : this = %p, _this = %p\n", this, _this); } ~ A () { printf ("~ A () : this = %p, _this = %p\n", this, _this); } void print () { printf ("print () : this = %p, _this = %p\n", this, _this); } A (const A & a) : _this (this) { printf ("A (const A &) : this = %p, _this = %p\n", this, _this); } }; struct B { A a; }; B b = { A () }; int main () { b.a.print (); } When run, the program produces: A () : this = ffbeae00, _this = ffbeae00 print () : this = 20e2c, _this = ffbeae00 ~ A () : this = 20e2c, _this = ffbeae00 I expected to see the "_this" member compare with "this" in all cases. In gcc 2.95 this is true. 12.6.1p2 of the Standard states that class members of aggregates are copy-initialized in this context. Comment 1 Drea Pinski 2004-04-27 17:24:17 UTC From 12.6.1p2: "each such member is copy-initialized (see 8.5)" From 8.5p14: "The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy- initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8. " What 12.8 says is that it does not have call the copy constructor at all but it still can. Well that this case so this is invalid. Comment 2 Michael Spencer 2004-04-27 18:30:09 UTC (In reply to comment #1) > What 12.8 says is that it does not have call the copy constructor at all but it still can. > Well that this case so this is invalid. 12.8p15: ... when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy. The problem here is that the temporary is *not* constructed into the target of the omitted copy. If this were the case, I'd expect to see something like the following (this is the run of the same program built with gcc 2.95): A () : this = 27794, _this = 27794 print () : this = 27794, _this = 27794 ~ A () : this = 27794, _this = 27794 Comment 3 Giovanni Bajo 2004-04-28 10:50:26 UTC I will agree it makes sense, it's a code pessimization regression if it works in 2.95. Comment 4 Drea Pinski 2004-06-03 22:57:00 UTC Confirmed. Comment 5 Ali Cehreli 2004-10-16 22:57:31 UTC I don't think the paragraphs from the standard that are mentioned above are completely relevant. There isn't an opportunity for optimization in this case. This is aggregate initialization. I found the following paragraphs to be describing this case exactly: 8.5.1/1 8.5.1/13 12.6.1/2 The first example under 12.6.1/2 is directly relevant: [Example: complex v[6] = { 1,complex(1,2),complex(),2 }; Here, complex::complex(double) is called for the initialization of v[0] and v [3], complex::complex(double,double) is called for the initialization of v[1], complex::complex() is called for the initialization v[2], v[4], and v[5]. Comment 6 Wolfgang Bangerth 2004-10-16 23:28:22 UTC Something is definitely wrong with this testcase. I think that storing and printing the _this pointer is only obstructing the view of the problem somehow, so consider this example here: -------------------- int printf (const char *format, ...); struct A { A () { printf ("A::A () : this = %p\n", this); } A (const A & a) { printf ("A::A (const A&) : this = %p\n", this); } ~ A () { printf ("A::~A () : this = %p\n", this); } void print () { printf ("print () : this = %p\n", this); } }; struct B { A a; }; B b = { A () }; int main () { b.a.print (); } ------------------------ I think we all agree that we always have to have matching calls to (copy) constructors and destructors for a this pointer, but we really get this here: g/x> c++ x.cc g/x> ./a.out A::A () : this = 0xbfffeaa0 print () : this = 0x80499c8 A::~A () : this = 0x80499c8 I don't think this can ever be right. This used to work in gcc2.95, but is broken between 3.2 and 3.4. It works fine in mainline again, though, so this is a 3.3/3.4 branch regression only. W. Comment 7 Wolfgang Bangerth 2004-10-16 23:34:35 UTC The reason, btw, why I believe that this is wrong code is that the this pointer of the object being constructed can escape, like here: ------------------------------------ extern "C" int printf (const char *format, ...); struct A; void register_A (const A* a) {printf ("registering %p\n", a); } void deregister_A (const A* a) {printf ("deregistering %p\n", a); } struct A { A () { register_A(this); } A (const A & a) { register_A(this); } ~ A () { deregister_A(this); } }; struct B { A a; }; B b = { A () }; int main () {} ------------------------------------ It is certainly more than just a nuisance ("missed optimization") that the calls to register and deregister don't match! g/x> c++ x.cc g/x> ./a.out g/x> c++ x.cc g/x> ./a.out registering 0xbfffeaa0 deregistering 0x8049990 W. Comment 8 Ali Cehreli 2004-10-17 01:01:55 UTC We've seen the problem in 2.95.3 and 3.4.2. There is a recent posting to comp.lang.c++.moderated about the same problem, with the subject "Bitwise copy during aggregate initialization (a compiler bug?)". Ali Comment 9 Giovanni Bajo 2004-10-17 11:21:06 UTC > There is a recent posting to comp.lang.c++.moderated about the same problem, > with the subject "Bitwise copy during aggregate initialization (a compiler > bug?)". ... which is here: http://tinyurl.com/4hpdn Comment 10 Eric Botcazou 2004-10-26 08:30:52 UTC Is this problem specific to SPARC? If no, I'd suggest to change the triplets. Comment 11 Eric Botcazou 2004-10-27 17:59:37 UTC Reproducible on x86 too. Comment 12 Benoît Dejean 2004-10-29 15:15:21 UTC and ppc32 Comment 13 Mark Mitchell 2004-10-31 01:58:05 UTC The problem here is that expand_expr_real creates a temporary variable and stores the CONSTRCUTOR corresponding to the brace-enclosed initializer there. Then, it copies the temporary to the global variable. Comment 14 Mark Mitchell 2004-10-31 19:02:35 UTC Working on a fix. Comment 17 Mark Mitchell 2004-11-01 00:14:03 UTC Fixed in GCC 3.4.3. | | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |