<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, May 21, 2026 at 10:51 AM Jakub Jelinek <<a href="mailto:jakub@redhat.com">jakub@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Thu, May 21, 2026 at 10:31:25AM +0200, Tomasz Kaminski wrote:<br>
> Even with this patch, I still see a difference between the foo and bar<br>
> functions.<br>
> as defined below:<br>
> #include <memory><br>
> #include <cassert><br>
> #include <string><br>
> <br>
> template <typename T, size_t N><br>
> struct FixedVector {<br>
> union { T storage[N]; };<br>
> size_t size = 0;<br>
> <br>
> constexpr FixedVector () { std::start_lifetime (storage); }<br>
> <br>
> constexpr ~FixedVector() { std::destroy(storage, storage + size); }<br>
> <br>
> constexpr FixedVector(std::initializer_list<T> il)<br>
> {<br>
> assert(il.size() < N);<br>
> std::start_lifetime (storage);<br>
> std::uninitialized_copy(il.begin(), il.end(), storage);<br>
> size = il.size();<br>
> }<br>
> <br>
> constexpr void push_back(T const& v) { ::new (storage + size) T(v);<br>
> ++size; }<br>
> };<br>
> <br>
> FixedVector<char, 4> foo()<br>
> {<br>
> return {'a', 'b', 'c'};<br>
> }<br>
> <br>
> FixedVector<char, 4> bar()<br>
> {<br>
> constexpr FixedVector<char, 4> res{'a', 'b', 'c'};<br>
> return res;<br>
> }<br>
> <br>
> After compiling the above with -O2 I see:<br>
<br>
This boils down to the differences in C with -O2 on:<br>
struct S { unsigned char a[4]; unsigned long b; };<br>
<br>
struct S foo () { static const unsigned char c[3] = { 97, 98, 99 }; struct S r; __builtin_memcpy (&r.a, &c, 3); r.b = 3; return r; }<br>
struct S bar () { struct S r; r.a[0] = 97; r.a[1] = 98; r.a[2] = 99; r.b = 3; return r; }<br>
struct S baz () { static const unsigned char c[4] = { 97, 98, 99, 100 }; struct S r; __builtin_memcpy (&r.a, &c, 4); r.b = 4; return r; }<br>
struct S qux () { struct S r; r.a[0] = 97; r.a[1] = 98; r.a[2] = 99; r.a[3] = 100; r.b = 4; return r; }<br>
<br>
Note, baz and qux emit the same<br>
movl $4, %edx<br>
movl $1684234849, %eax<br>
while<br>
movzbl .LC0+1(%rip), %edx<br>
movzbl .LC0(%rip), %eax<br>
salq $8, %rdx<br>
orq %rax, %rdx<br>
movzbl .LC0+2(%rip), %eax<br>
salq $16, %rax<br>
orq %rdx, %rax<br>
movl $3, %edx<br>
ret<br>
vs.<br>
movl $3, %edx<br>
movl $6513249, %eax<br>
ret<br>
I guess worth filing a PR, but I'm afraid we have plenty of prior PRs<br>
about this too (and some attempt to improve it but not really successful;<br>
it is about the returning of uninitialized bits in registers).<br></blockquote><div>That what I assumed with current inplace_vector, that zeroes all elements</div><div>of array at compile time. But with the start_lifetime, constexpr FixedVector<char, 4> res{'a', 'b', 'c'};</div><div>It also contains the same out of lifetime element, as return {'a', 'b', 'c'} would.</div><div><br></div><div>I think the expecation from <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124121" rel="noreferrer" target="_blank">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124121</a></div><div>is that `return FixedVector<char, 4>{'a', 'b', 'c'}` would constant-fold creation of </div><div>fixed vector, and be equivalent to `constexpr FixedVector<char, 4> res{'a', 'b', 'c'}; return res;`.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Jakub<br>
<br>
</blockquote></div></div>