mardi 1 décembre 2015

Clash when using trivially copy/move-assignable union in constexpr

Considering the following code

struct S
{
    constexpr S() { ; }
    constexpr S(S const &) { ; }
    constexpr S(S &) { ; }
    constexpr S(S &&) { ; }
#if 1
    S & operator = (S const &) = default;
    S & operator = (S &) = default;
    S & operator = (S &&) = default;
#else
    constexpr S & operator = (S const &) = default;
    constexpr S & operator = (S &) = default;
    constexpr S & operator = (S &&) = default;
#endif
    ~S() = default;
};

struct U
{
    union
    {
        S s;
    };
    constexpr U() : s{} { ; }
};

inline constexpr bool test()
{
    U v;
    U w;
    v = w;
    return true;
}

static_assert(test());

I found out that there is contradiction.

I want to use union (or euqally union-like class) in constexpr.

Version #if 1 gives an error:

main.cpp:31:23: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
inline constexpr bool test()
                      ^
main.cpp:35:7: note: non-constexpr function 'operator=' cannot be used in a constant expression
    v = w;
      ^
main.cpp:19:8: note: declared here
struct U
       ^
main.cpp:39:15: error: static_assert expression is not an integral constant expression
static_assert(test());
              ^~~~~~
main.cpp:35:7: note: non-constexpr function 'operator=' cannot be used in a constant expression
    v = w;
      ^
main.cpp:39:15: note: in call to 'test()'
static_assert(test());
              ^
main.cpp:19:8: note: declared here
struct U
       ^
2 errors generated.

But version #if 0 also give an error (error: defaulted definition of copy assignment operator is not constexpr):

main.cpp:12:5: error: defaulted definition of copy assignment operator is not constexpr
    constexpr S & operator = (S const &) = default;
    ^
main.cpp:13:5: error: defaulted definition of copy assignment operator is not constexpr
    constexpr S & operator = (S &) = default;
    ^
main.cpp:14:5: error: defaulted definition of move assignment operator is not constexpr
    constexpr S & operator = (S &&) = default;
    ^
main.cpp:35:7: error: object of type 'U' cannot be assigned because its copy assignment operator is implicitly deleted
    v = w;
      ^
main.cpp:24:11: note: copy assignment operator of 'U' is implicitly deleted because field 's' has no copy assignment operator
        S s;
          ^
4 errors generated.

LIVE EXAMPLE

All above is for version of clang 3.7.0, but newer version clang 3.8.0 (trunk 253951) nothing says about constexpr S & operator = (S const &) = default;, but consequences are the same.

For trivial copy/move-constructors, but user-provided assignment operators analogous code (construction) compiles fine.

Aucun commentaire:

Enregistrer un commentaire