Bug 66476 - Erroneous initializer_list lifetime extension from temporary initializer_list
Summary: Erroneous initializer_list lifetime extension from temporary initializer_list
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-06-09 16:49 UTC by Ed Catmur
Modified: 2018-05-24 11:16 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-06-09 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Catmur 2015-06-09 16:49:52 UTC
#include <stdio.h>
#include <initializer_list>
struct S { S(int) { puts("S(int)"); } ~S() { puts("~S()"); } };
int main() {
  std::initializer_list<S> ss({42});  // note extra parentheses
  puts("main");
}

Expected output (clang 3.7, MSVC 18.00.21005.1):
S(int)
~S()
main

Observed output (gcc 5.1.0):
S(int)
main
~S()

The same behaviour is observed when the temporary initializer_list is made explicit:
  std::initializer_list<S> ss = std::initializer_list<S>{42};


Again, gcc lifetime-extends the backing array; MSVC and clang do not.
Comment 1 Jason Merrill 2018-05-23 03:00:08 UTC
11.6.4 [dcl.init.list] paragraph 6:

The array has the same lifetime as any other temporary object (15.2), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary.

So the array shares the lifetime of the initializer_list.
Comment 2 Ed Catmur 2018-05-24 08:50:00 UTC
Yes... but the initializer_list that the array backs is itself temporary; it has lifetime only for the duration of the call to the copy constructor. 

From https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48562#c6 :

> I think that a warning against "({...})" would be useful too
>    // fine
>    initializer_list<int> a{1, 2, 3};
>    // this is bad
>    initializer_list<int> b({1, 2, 3});
> Second one is bad because it will destroy the array after initializing 'b', 
> and won't lengthen the lifetime (because it will use the copy/move
> constructor).
Comment 3 Ed Catmur 2018-05-24 11:16:08 UTC
Ah wait, guaranteed copy elision since C++17 should fix this, right? So g++ is actually correct now, even if it was wrong before.