C++11 constexpr and initializer_list?

Hi.

While experimenting with a readable bitboard initialisation syntax, I stumbled
across the following code which works with GCC but is rejected by Clang:

#include <initializer_list>
#include <cstdint>

namespace chess {

enum class square: uint8_t {
  a1, b1, c1, d1, e1, f1, g1, h1,
  a2, b2, c2, d2, e2, f2, g2, h2,
  a3, b3, c3, d3, e3, f3, g3, h3,
  a4, b4, c4, d4, e4, f4, g4, h4,
  a5, b5, c5, d5, e5, f5, g5, h5,
  a6, b6, c6, d6, e6, f6, g6, h6,
  a7, b7, c7, d7, e7, f7, g7, h7,
  a8, b8, c8, d8, e8, f8, g8, h8
};

typedef std::initializer_list<square> square_initializer_list;

typedef std::uint64_t bitboard;

constexpr bitboard bb( square_initializer_list::const_iterator const &first
                     , square_initializer_list::const_iterator const &last
                     )
{ return first!=last ? ((1ULL << unsigned(*first)) | bb(first + 1, last)) : 0; }

constexpr bitboard bb(square_initializer_list const &init)
{ return bb(begin(init), end(init)); }

namespace start_position {
  namespace white {
    constexpr bitboard knights = bb({square::b1, square::g1});
  }
}

}

int main ()
{ return chess::start_position::white::knights; }

GCC 4.7 compiles this without any errors or warnings, and produces
assembly which indicates that indeed, the call to bb() was evaluated
at compile time. (it also places the initializer_list content into the
rodata section, which is at first sight illogical to me since it is
never used at run-time, but this is something else to wonder about.)

Clang complains:

cx.cpp:31:24: error: constexpr variable 'knights' must be initialized by a constant expression
    constexpr bitboard knights = bb({square::b1, square::g1});
                       ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

I am wondering, is this legal C++11? Is GCC treating it too liberal, or
does Clang's constexpr support miss things (I am using trunk)?

Note that the error message could be a little more helpful. As a user,
I am wondering *why* bb({}) is not considered a constant expression (given
that I explicitly declared it as such.)

Hi!

Hi.

While experimenting with a readable bitboard initialisation syntax, I stumbled
across the following code which works with GCC but is rejected by Clang:

#include <initializer_list>
#include

namespace chess {

enum class square: uint8_t {
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8
};

typedef std::initializer_list square_initializer_list;

typedef std::uint64_t bitboard;

constexpr bitboard bb( square_initializer_list::const_iterator const &first
, square_initializer_list::const_iterator const &last
)
{ return first!=last ? ((1ULL << unsigned(*first)) | bb(first + 1, last)) : 0; }

constexpr bitboard bb(square_initializer_list const &init)
{ return bb(begin(init), end(init)); }

namespace start_position {
namespace white {
constexpr bitboard knights = bb({square::b1, square::g1});
}
}

}

int main ()
{ return chess::start_position::white::knights; }

GCC 4.7 compiles this without any errors or warnings, and produces
assembly which indicates that indeed, the call to bb() was evaluated
at compile time. (it also places the initializer_list content into the
rodata section, which is at first sight illogical to me since it is
never used at run-time, but this is something else to wonder about.)

Clang complains:

cx.cpp:31:24: error: constexpr variable ‘knights’ must be initialized by a constant expression
constexpr bitboard knights = bb({square::b1, square::g1});
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

I am wondering, is this legal C++11? Is GCC treating it too liberal, or
does Clang’s constexpr support miss things (I am using trunk)?

This was not legal when C++11 was published, but since then, the library folks have made std::initializer_list a literal type, which makes this code legal. Clang does not yet support this: see llvm.org/PR15117

Note that the error message could be a little more helpful. As a user,
I am wondering why bb({}) is not considered a constant expression (given
that I explicitly declared it as such.)

Sorry about that. With libc++ (which also doesn’t have the initializer_list-as-literal-type change), we produce this:

:26:20: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
constexpr bitboard bb(square_initializer_list const &init)
^
:27:13: note: non-constexpr function ‘beginchess::square’ cannot be used in a constant expression
{ return bb(begin(init), end(init)); }
^
/usr/include/c++/v1/initializer_list:87:1: note: declared here
begin(initializer_list<_Ep> __il) _NOEXCEPT
^
:31:24: error: constexpr variable ‘knights’ must be initialized by a constant expression
constexpr bitboard knights = bb({square::b1, square::g1});
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:31:37: note: non-literal type ‘const square_initializer_list’ (aka ‘const initializer_listchess::square’) cannot be used in a constant expression
constexpr bitboard knights = bb({square::b1, square::g1});
^