https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83307
Bug ID: 83307 Summary: Miscompilation of range_for with initializer_list<class-type> in constructors on MacOS (works on Linux) Product: gcc Version: 7.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: greenc at fnal dot gov Target Milestone: --- Verified on G++ 6.3.0, 6.4.0 and 7.2.0 to work on Linux (RHEL7-ish) but fail on Mac OS (at least El Capitan and Sierra), the test code *should* produce the output: s.x = 0. s.x = 1. s.x = 2. s.x = 3. Count = 4. S.x = 4. S.x = 5. S.x = 6. S.x = 7. Xount = 4. Final ... S.x = 4. S.x = 5. S.x = 6. S.x = 7. Xount = 4. On MacOS as specified above however, it produces: Count = 0. S.x = 4. S.x = 5. S.x = 6. S.x = 7. Xount = 4. Final ... S.x = 4. S.x = 5. S.x = 6. S.x = 7. Xount = 4. instead. When the contents of the brace-enclosed initializer list are of basic type (e.g. int or char const *) then the behavior of the range for in the constructor is the same as that in the member function. Changing the brace-enclosed initializer list to : std::initializer_list<B> { ... } with -DTRY=1 makes no difference; changing it to: std::vector<B> { ... } however (with -DTRY=2), solves the problem. It's possible this is a library rather than a C++ issue, but given the constructor / non-constructor context dependence, and the OS dependence, and the interaction between a brace-enclosed initializer list and std::initializer_list, I flagged it as the latter. Note also that optimizer level is irrelevant, as is language standard provided it is C++11 or later, of course. Test code: // Compile with (e.g.): // g++ -DTRY=[012] -Wall -Wextra -Werror -pedantic -std=c++14 -O3 -g -o test-ilist{,.cc} #include <iostream> #if (!defined TRY) || TRY == 0 #define CTYPE #elif TRY == 1 #include <initializer_list> #define CTYPE std::initializer_list<B> #elif TRY == 2 #include <vector> #define CTYPE std::vector<B> #else #error "Uncrecognized value of TRY" #define CTYPE #endif struct A { A(); void f(); }; struct B { B(int i) : x(i) { } int x; }; A::A() { std::size_t count = 0ull; for ( auto const & s : CTYPE { B(0), B(1), B(2), B(3) } ) { std::cerr << "s.x = " << s.x << ".\n"; ++count; } std::cerr << "Count = " << count << ".\n"; f(); } void A::f() { std::size_t xount = 0ull; for ( auto const & S : CTYPE { B(4), B(5), B(6), B(7) } ) { std::cerr << "S.x = " << S.x << ".\n"; ++xount; } std::cerr << "Xount = " << xount << ".\n"; } int main() { A a; std::cerr << "Final ...\n"; a.f(); }