This small program takes over a minute to compile and produces a 160 meg object file. sizeof(Bar) is large and it looks like the compiler wants to write down a precompiled version of it to the object file for the benefit of Bar's constructor. There are no static variables or anything like that so the object file really should be modest in size. % cat test.cc constexpr int size = 10000000; class Foo { int a = 10; int b = 11; int c = 12; int d = 13; }; class Bar { Foo foo[size]; }; void somefunc(const Bar *); int main() { Bar *bar = new Bar(); somefunc(bar); } % time g++ -O2 -c test.cc real 1m9.696s user 1m6.486s sys 0m2.806s % ls -l test.o -rw-rw-r-- 1 kosak kosak 160001760 Oct 22 01:41 test.o
Confirmed. I believe we have dups of this bug.
Yes, there are dups. IIRC the problem is that every element of the array introduces a new try/finally block so that if one of the Foo objects throws an exception, all the earlier elements in the array get destroyed. That shouldn't be needed here, because Foo can never throw on construction.
PR 70277 is the one I was thinking of, and there's PR 55402 too.
To my eye it doesn't seem to be related to exceptions or initializer lists, so I don't think it's the same bug, but you all would know better than me. When I look at the .s file I see a giant sequence of the form .LC0: .long 10 .long 11 .long 12 .long 13 .long 10 .long 11 .long 12 .long 13 .long 10 .long 11 .long 12 .long 13 ... and then the constructor uses .LC0 to initialize the object with a single memcpy. Which might be a fine strategy for objects of reasonable size, but maybe there should be a size cutoff.
I believe this bug (and other existing dups) are about the C++ FE for array initializers not emitting a loop for initialization but an initializer for each element. It does that via ;; Function constexpr Bar::Bar() (null) ;; enabled by -tree-original { <<cleanup_point <<< Unknown tree: expr_stmt (void) (((struct Bar *) this)->foo = <<< Unknown tree: vec_init_expr D.2381 >>>) >>>>>; } which eventually is gimplified to Bar::Bar (struct Bar * const this) { this->foo[0].a = 10; this->foo[0].b = 11; this->foo[0].c = 12; this->foo[0].d = 13; this->foo[1].a = 10; this->foo[1].b = 11; ... via cp_gimplify_expr.
Also very similar to PR 92385.
Yes this is fixed after the patch which fixes PR 92385. We get now: .LC0: .long 10 .long 11 .long 12 .long 13 _3 = operator new (160000000); MEM[(struct Bar *)_3] = {}; MEM <vector(4) int> [(int *)_3] = { 10, 11, 12, 13 }; vectp.6_7 = _3 + 16; ivtmp.12_16 = (unsigned long) vectp.6_7; _9 = (unsigned long) _3; _13 = _9 + 160000000; <bb 3> [local count: 106300463076]: # ivtmp.12_18 = PHI <ivtmp.12_17(3), ivtmp.12_16(2)> _8 = (void *) ivtmp.12_18; MEM <vector(4) int> [(int *)_8] = { 10, 11, 12, 13 }; ivtmp.12_17 = ivtmp.12_18 + 16; if (_13 == ivtmp.12_17) goto <bb 4>; [1.00%] else goto <bb 3>; [99.00%] *** This bug has been marked as a duplicate of bug 92385 ***