llvm/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp

// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s

struct non_trivial {
  non_trivial();
  non_trivial(const non_trivial&);
  non_trivial& operator = (const non_trivial&);
  ~non_trivial();
};

union u {
  non_trivial nt;
};
union u2 {
  non_trivial nt;
  int k;
  u2(int k) : k(k) {}
  u2() : nt() {}
};

union static_data_member {
  static int i;
};
int static_data_member::i;

union bad {
  int &i; // expected-error {{union member 'i' has reference type 'int &'}}
};

struct s {
  union {
    non_trivial nt;
  };
};

// Don't crash on this.
struct TemplateCtor { template<typename T> TemplateCtor(T); };
union TemplateCtorMember { TemplateCtor s; };

template<typename T> struct remove_ref { typedef T type; };
template<typename T> struct remove_ref<T&> { typedef T type; };
template<typename T> struct remove_ref<T&&> { typedef T type; };
template<typename T> T &&forward(typename remove_ref<T>::type &&t);
template<typename T> T &&forward(typename remove_ref<T>::type &t);
template<typename T> typename remove_ref<T>::type &&move(T &&t);

using size_t = decltype(sizeof(int));
void *operator new(size_t, void *p) noexcept { return p; }

namespace disabled_dtor {
  template<typename T>
  union disable_dtor {
    T val;
    template<typename...U>
    disable_dtor(U &&...u) : val(forward<U>(u)...) {}
    ~disable_dtor() {}
  };

  struct deleted_dtor {
    deleted_dtor(int n, char c) : n(n), c(c) {}
    int n;
    char c;
    ~deleted_dtor() = delete;
  };

  disable_dtor<deleted_dtor> dd(4, 'x');
}

namespace optional {
  template<typename T> struct optional {
    bool has;
    union { T value; };

    optional() : has(false) {}
    template<typename...U>
    optional(U &&...u) : has(true), value(forward<U>(u)...) {}

    optional(const optional &o) : has(o.has) {
      if (has) new (&value) T(o.value);
    }
    optional(optional &&o) : has(o.has) {
      if (has) new (&value) T(move(o.value));
    }

    optional &operator=(const optional &o) {
      if (has) {
        if (o.has)
          value = o.value;
        else
          value.~T();
      } else if (o.has) {
        new (&value) T(o.value);
      }
      has = o.has;
    }
    optional &operator=(optional &&o) {
      if (has) {
        if (o.has)
          value = move(o.value);
        else
          value.~T();
      } else if (o.has) {
        new (&value) T(move(o.value));
      }
      has = o.has;
    }

    ~optional() {
      if (has)
        value.~T();
    }

    explicit operator bool() const { return has; }
    T &operator*() { return value; }
  };

  optional<non_trivial> o1;
  optional<non_trivial> o2{non_trivial()};
  optional<non_trivial> o3{*o2};
  void f() {
    if (o2)
      o1 = o2;
    o2 = optional<non_trivial>();
  }
}

namespace pr16061 {
  struct X { X(); };

  template<typename T> struct Test1 {
    union {
      struct {
        X x;
      };
    };
  };

  template<typename T> struct Test2 {
    union {
      struct {  // expected-note-re {{default constructor of 'Test2<pr16061::X>' is implicitly deleted because variant field 'struct (anonymous struct at{{.+}})' has a non-trivial default constructor}}
        T x;
      };
    };
  };

  Test2<X> t2x;  // expected-error {{call to implicitly-deleted default constructor of 'Test2<X>'}}
}

namespace GH48416 {

struct non_trivial_constructor {
    constexpr non_trivial_constructor() : x(100) {}
    int x;
};


union U1 {
    int a;
    non_trivial_constructor b; // expected-note {{has a non-trivial default constructor}}
};

union U2 {
    int a{1000};
    non_trivial_constructor b;
};

union U3 {
    int a;
    non_trivial_constructor b{};
};

union U4 {
    int a{}; // expected-note {{previous initialization is here}}
    non_trivial_constructor b{}; // expected-error {{initializing multiple members of union}}
};

U1 u1; // expected-error {{call to implicitly-deleted default constructor}}
U2 u2;
U3 u3;
U4 u4;

static_assert(U2().a == 1000, "");
static_assert(U3().a == 1000, "");
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
// expected-note@-2 {{read of member 'a' of union with active member 'b'}}
static_assert(U2().b.x == 100, "");
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
// expected-note@-2 {{read of member 'b' of union with active member 'a'}}
static_assert(U3().b.x == 100, "");

} // namespace GH48416