[cfe-commits] r151992 - in /cfe/trunk: docs/LanguageExtensions.html docs/ReleaseNotes.html lib/Lex/PPMacroExpansion.cpp test/CXX/special/class.copy/p11.0x.copy.cpp test/CXX/special/class.copy/p11.0x.move.cpp test/CodeGenCXX/cxx11-unrestricted-union.cpp test/Lexer/has_feature_cxx0x.cpp test/SemaCXX/cxx0x-nontrivial-union.cpp test/SemaCXX/discrim-union.cpp www/cxx_status.html

Richard Smith richard-llvm at metafoo.co.uk
Sat Mar 3 15:51:05 PST 2012


Author: rsmith
Date: Sat Mar  3 17:51:05 2012
New Revision: 151992

URL: http://llvm.org/viewvc/llvm-project?rev=151992&view=rev
Log:
Add a pile of tests for unrestricted unions, and advertise support for them.

Added:
    cfe/trunk/test/CodeGenCXX/cxx11-unrestricted-union.cpp
    cfe/trunk/test/SemaCXX/discrim-union.cpp
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/docs/ReleaseNotes.html
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp
    cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp
    cfe/trunk/test/Lexer/has_feature_cxx0x.cpp
    cfe/trunk/test/SemaCXX/cxx0x-nontrivial-union.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Sat Mar  3 17:51:05 2012
@@ -814,7 +814,7 @@
 
 <h4 id="cxx_unrestricted_unions">C++11 unrestricted unions</h4>
 
-<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled. Clang does not currently support this feature.</p>
+<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled.</p>
 
 <h4 id="cxx_user_literals">C++11 user-defined literals</h4>
 

Modified: cfe/trunk/docs/ReleaseNotes.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ReleaseNotes.html?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/docs/ReleaseNotes.html (original)
+++ cfe/trunk/docs/ReleaseNotes.html Sat Mar  3 17:51:05 2012
@@ -123,6 +123,7 @@
   <li>Generalized constant expressions</li>
   <li>Lambda expressions</li>
   <li>Generalized initializers</li>
+  <li>Unrestricted unions</li>
 </ul>
 
 <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Sat Mar  3 17:51:05 2012
@@ -667,7 +667,7 @@
            .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
            .Case("cxx_trailing_return", LangOpts.CPlusPlus0x)
            .Case("cxx_unicode_literals", LangOpts.CPlusPlus0x)
-         //.Case("cxx_unrestricted_unions", false)
+           .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus0x)
          //.Case("cxx_user_literals", false)
            .Case("cxx_variadic_templates", LangOpts.CPlusPlus0x)
            // Type traits

Modified: cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp Sat Mar  3 17:51:05 2012
@@ -4,6 +4,9 @@
   NonTrivial(const NonTrivial&);
 };
 
+// A defaulted copy constructor for a class X is defined as deleted if X has:
+
+// -- a variant member with a non-trivial corresponding constructor
 union DeletedNTVariant { // expected-note{{here}}
   NonTrivial NT;
   DeletedNTVariant();
@@ -20,6 +23,9 @@
 DeletedNTVariant2 DV2a;
 DeletedNTVariant2 DV2b(DV2a); // expected-error{{call to implicitly-deleted copy constructor}}
 
+// -- a non-static data member of class type M (or array thereof) that cannot be
+//    copied because overload resolution results in an ambiguity or a function
+//    that is deleted or inaccessible
 struct NoAccess {
   NoAccess() = default;
 private:
@@ -63,6 +69,25 @@
 Deleted Da;
 Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}}
 
+// -- a direct or virtual base class B that cannot be copied because overload
+//    resolution results in an ambiguity or a function that is deleted or
+//    inaccessible
+struct AmbiguousCopyBase : Ambiguity { // expected-note {{here}}
+  NonConst NC;
+};
+extern AmbiguousCopyBase ACBa;
+AmbiguousCopyBase ACBb(ACBa); // expected-error {{deleted copy constructor}}
+
+struct DeletedCopyBase : AmbiguousCopyBase {}; // expected-note {{here}}
+extern DeletedCopyBase DCBa;
+DeletedCopyBase DCBb(DCBa); // expected-error {{deleted copy constructor}}
+
+struct InaccessibleCopyBase : NoAccess {}; // expected-note {{here}}
+extern InaccessibleCopyBase ICBa;
+InaccessibleCopyBase ICBb(ICBa); // expected-error {{deleted copy constructor}}
+
+// -- any direct or virtual base class or non-static data member of a type with
+//    a destructor that is deleted or inaccessible
 struct NoAccessDtor {
 private:
   ~NoAccessDtor();
@@ -83,6 +108,12 @@
 HasAccessDtor HADa;
 HasAccessDtor HADb(HADa);
 
+struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{here}}
+};
+extern HasNoAccessDtorBase HNADBa;
+HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
+
+// -- a non-static data member of rvalue reference type
 struct RValue { // expected-note{{here}}
   int && ri = 1;
 };

Modified: cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp Sat Mar  3 17:51:05 2012
@@ -4,6 +4,9 @@
   NonTrivial(NonTrivial&&);
 };
 
+// A defaulted move constructor for a class X is defined as deleted if X has:
+
+// -- a variant member with a non-trivial corresponding constructor
 union DeletedNTVariant {
   NonTrivial NT;
   DeletedNTVariant(DeletedNTVariant&&);
@@ -18,6 +21,9 @@
 };
 DeletedNTVariant2::DeletedNTVariant2(DeletedNTVariant2&&) = default; // expected-error{{would delete}}
 
+// -- a non-static data member of class type M (or array thereof) that cannot be
+//    copied because overload resolution results in an ambiguity or a function
+//    that is deleted or inaccessible
 struct NoAccess {
   NoAccess() = default;
 private:
@@ -38,6 +44,43 @@
 };
 HasAccess::HasAccess(HasAccess&&) = default;
 
+struct Ambiguity {
+  Ambiguity(const Ambiguity&&);
+  Ambiguity(volatile Ambiguity&&);
+};
+
+struct IsAmbiguous {
+  Ambiguity A;
+  IsAmbiguous(IsAmbiguous&&);
+};
+IsAmbiguous::IsAmbiguous(IsAmbiguous&&) = default; // expected-error{{would delete}}
+
+struct Deleted {
+  IsAmbiguous IA;
+  Deleted(Deleted&&);
+};
+Deleted::Deleted(Deleted&&) = default; // expected-error{{would delete}}
+
+// -- a direct or virtual base class B that cannot be moved because overload
+//    resolution results in an ambiguity or a function that is deleted or
+//    inaccessible
+struct AmbiguousMoveBase : Ambiguity {
+  AmbiguousMoveBase(AmbiguousMoveBase&&);
+};
+AmbiguousMoveBase::AmbiguousMoveBase(AmbiguousMoveBase&&) = default; // expected-error{{would delete}}
+
+struct DeletedMoveBase : AmbiguousMoveBase {
+  DeletedMoveBase(DeletedMoveBase&&);
+};
+DeletedMoveBase::DeletedMoveBase(DeletedMoveBase&&) = default; // expected-error{{would delete}}
+
+struct InaccessibleMoveBase : NoAccess {
+  InaccessibleMoveBase(InaccessibleMoveBase&&);
+};
+InaccessibleMoveBase::InaccessibleMoveBase(InaccessibleMoveBase&&) = default; // expected-error{{would delete}}
+
+// -- any direct or virtual base class or non-static data member of a type with
+//    a destructor that is deleted or inaccessible
 struct NoAccessDtor {
   NoAccessDtor(NoAccessDtor&&);
 private:
@@ -57,12 +100,21 @@
 };
 HasAccessDtor::HasAccessDtor(HasAccessDtor&&) = default;
 
+struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{here}}
+};
+extern HasNoAccessDtorBase HNADBa;
+HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
+
+// The restriction on rvalue reference members applies to only the copy
+// constructor.
 struct RValue {
   int &&ri = 1;
   RValue(RValue&&);
 };
 RValue::RValue(RValue&&) = default;
 
+// -- a non-static data member or direct or virtual base class with a type that
+//    does not have a move constructor and is not trivially copyable
 struct CopyOnly {
   CopyOnly(const CopyOnly&);
 };

Added: cfe/trunk/test/CodeGenCXX/cxx11-unrestricted-union.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-unrestricted-union.cpp?rev=151992&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-unrestricted-union.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx11-unrestricted-union.cpp Sat Mar  3 17:51:05 2012
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - | FileCheck %s
+
+struct A {
+  A(); A(const A&); A(A&&); A &operator=(const A&); A &operator=(A&&); ~A();
+};
+struct B {
+  B(); B(const B&); B(B&&); B &operator=(const B&); B &operator=(B&&); ~B();
+};
+
+union U {
+  U();
+  U(const U &);
+  U(U &&);
+  U &operator=(const U&);
+  U &operator=(U&&);
+  ~U();
+
+  A a;
+  int n;
+};
+
+// CHECK-NOT: _ZN1A
+U::U() {}
+U::U(const U&) {}
+U::U(U&&) {}
+U &U::operator=(const U&) { return *this; }
+U &U::operator=(U &&) { return *this; }
+U::~U() {}
+
+struct S {
+  S();
+  S(const S &);
+  S(S &&);
+  S &operator=(const S&);
+  S &operator=(S&&);
+  ~S();
+
+  union {
+    A a;
+    int n;
+  };
+  B b;
+  int m;
+};
+
+// CHECK: _ZN1SC2Ev
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S() {}
+
+// CHECK-NOT: _ZN1A
+
+// CHECK: _ZN1SC2ERKS_
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S(const S&) {}
+
+// CHECK-NOT: _ZN1A
+
+// CHECK: _ZN1SC2EOS_
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S(S&&) {}
+
+// CHECK-NOT: _ZN1A
+// CHECK-NOT: _ZN1B
+S &S::operator=(const S&) { return *this; }
+
+S &S::operator=(S &&) { return *this; }
+
+// CHECK: _ZN1SD2Ev
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BD1Ev
+S::~S() {}
+
+// CHECK-NOT: _ZN1A

Modified: cfe/trunk/test/Lexer/has_feature_cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/has_feature_cxx0x.cpp?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/test/Lexer/has_feature_cxx0x.cpp (original)
+++ cfe/trunk/test/Lexer/has_feature_cxx0x.cpp Sat Mar  3 17:51:05 2012
@@ -235,3 +235,12 @@
 
 // CHECK-0X: has_generalized_initializers
 // CHECK-NO-0X: no_generalized_initializers
+
+#if __has_feature(cxx_unrestricted_unions)
+int has_unrestricted_unions();
+#else
+int no_unrestricted_unions();
+#endif
+
+// CHECK-0X: has_unrestricted_unions
+// CHECK-NO-0X: no_unrestricted_unions

Modified: cfe/trunk/test/SemaCXX/cxx0x-nontrivial-union.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-nontrivial-union.cpp?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-nontrivial-union.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-nontrivial-union.cpp Sat Mar  3 17:51:05 2012
@@ -10,6 +10,12 @@
 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;
@@ -29,3 +35,90 @@
 // 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*() const { 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>();
+  }
+}

Added: cfe/trunk/test/SemaCXX/discrim-union.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/discrim-union.cpp?rev=151992&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/discrim-union.cpp (added)
+++ cfe/trunk/test/SemaCXX/discrim-union.cpp Sat Mar  3 17:51:05 2012
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -fcxx-exceptions
+
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+template<typename T> struct remove_reference<T&&> { typedef T type; };
+
+template<typename T> constexpr T &&forward(typename remove_reference<T>::type &t) noexcept { return static_cast<T&&>(t); }
+template<typename T> constexpr T &&forward(typename remove_reference<T>::type &&t) noexcept { return static_cast<T&&>(t); }
+template<typename T> constexpr typename remove_reference<T>::type &&move(T &&t) noexcept { return static_cast<typename remove_reference<T>::type&&>(t); }
+
+template<typename T> T declval() noexcept;
+
+namespace detail {
+  template<unsigned N> struct select {}; // : integral_constant<unsigned, N> {};
+  template<typename T> struct type {};
+
+  template<typename...T> union either_impl;
+
+  template<> union either_impl<> {
+    void get(...);
+    void destroy(...) { throw "logic_error"; }
+  };
+
+  template<typename T, typename...Ts> union either_impl<T, Ts...> {
+  private:
+    T val;
+    either_impl<Ts...> rest;
+    typedef either_impl<Ts...> rest_t;
+
+  public:
+    constexpr either_impl(select<0>, T &&t) : val(move(t)) {}
+
+    template<unsigned N, typename U>
+    constexpr either_impl(select<N>, U &&u) : rest(select<N-1>(), move(u)) {}
+
+    constexpr static unsigned index(type<T>) { return 0; }
+    template<typename U>
+    constexpr static unsigned index(type<U> t) {
+      return decltype(rest)::index(t) + 1;
+    }
+
+    void destroy(unsigned elem) {
+      if (elem)
+        rest.destroy(elem - 1);
+      else
+        val.~T();
+    }
+
+    constexpr const T &get(select<0>) { return val; }
+    template<unsigned N> constexpr const decltype(static_cast<const rest_t&>(rest).get(select<N-1>{})) get(select<N>) {
+      return rest.get(select<N-1>{});
+    }
+  };
+}
+
+template<typename T>
+struct a {
+  T value;
+  template<typename...U>
+  constexpr a(U &&...u) : value{forward<U>(u)...} {}
+};
+template<typename T> using an = a<T>;
+
+template<typename T, typename U> T throw_(const U &u) { throw u; }
+
+template<typename...T>
+class either {
+  unsigned elem;
+  detail::either_impl<T...> impl;
+  typedef decltype(impl) impl_t;
+
+public:
+  template<typename U>
+  constexpr either(a<U> &&t) :
+    elem(impl_t::index(detail::type<U>())),
+    impl(detail::select<impl_t::index(detail::type<U>())>(), move(t.value)) {}
+
+  // Destruction disabled to allow use in a constant expression.
+  // FIXME: declare a destructor iff any element has a nontrivial destructor
+  //~either() { impl.destroy(elem); }
+
+  constexpr unsigned index() noexcept { return elem; }
+
+  template<unsigned N> using const_get_result =
+    decltype(static_cast<const impl_t&>(impl).get(detail::select<N>{}));
+
+  template<unsigned N>
+  constexpr const_get_result<N> get() {
+    // Can't just use throw here, since that makes the conditional a prvalue,
+    // which means we return a reference to a temporary.
+    return (elem != N ? throw_<const_get_result<N>>("bad_either_get")
+                      : impl.get(detail::select<N>{}));
+  }
+
+  template<typename U>
+  constexpr const U &get() {
+    return get<impl_t::index(detail::type<U>())>();
+  }
+};
+
+typedef either<int, char, double> icd;
+constexpr icd icd1 = an<int>(4);
+constexpr icd icd2 = a<char>('x');
+constexpr icd icd3 = a<double>(6.5);
+
+static_assert(icd1.get<int>() == 4, "");
+static_assert(icd2.get<char>() == 'x', "");
+static_assert(icd3.get<double>() == 6.5, "");
+
+struct non_triv {
+  constexpr non_triv() : n(5) {}
+  int n;
+};
+constexpr either<const icd*, non_triv> icd4 = a<const icd*>(&icd2);
+constexpr either<const icd*, non_triv> icd5 = a<non_triv>();
+
+static_assert(icd4.get<const icd*>()->get<char>() == 'x', "");
+static_assert(icd5.get<non_triv>().n == 5, "");

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=151992&r1=151991&r2=151992&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Sat Mar  3 17:51:05 2012
@@ -249,7 +249,7 @@
     <tr>
       <td>Unrestricted unions</td>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf">N2544</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Local and unnamed types as template arguments</td>





More information about the cfe-commits mailing list