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();
}

Reply via email to