diff options
| -rw-r--r-- | clang/docs/LanguageExtensions.html | 2 | ||||
| -rw-r--r-- | clang/docs/ReleaseNotes.html | 1 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 2 | ||||
| -rw-r--r-- | clang/test/CXX/special/class.copy/p11.0x.copy.cpp | 31 | ||||
| -rw-r--r-- | clang/test/CXX/special/class.copy/p11.0x.move.cpp | 52 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp | 76 | ||||
| -rw-r--r-- | clang/test/Lexer/has_feature_cxx0x.cpp | 9 | ||||
| -rw-r--r-- | clang/test/SemaCXX/cxx0x-nontrivial-union.cpp | 93 | ||||
| -rw-r--r-- | clang/test/SemaCXX/discrim-union.cpp | 118 | ||||
| -rw-r--r-- | clang/www/cxx_status.html | 2 | 
10 files changed, 383 insertions, 3 deletions
| diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index 23aa4fe9b92..9f271900cb9 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -814,7 +814,7 @@ support for Unicode string literals is enabled.</p>  <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> diff --git a/clang/docs/ReleaseNotes.html b/clang/docs/ReleaseNotes.html index 60a3f73fe59..2a1e62fd162 100644 --- a/clang/docs/ReleaseNotes.html +++ b/clang/docs/ReleaseNotes.html @@ -123,6 +123,7 @@ following are now considered to be of production quality:    <li>Generalized constant expressions</li>    <li>Lambda expressions</li>    <li>Generalized initializers</li> +  <li>Unrestricted unions</li>  </ul>  <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = --> diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 56ce407c186..99f2b23dff1 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -667,7 +667,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {             .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 diff --git a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp index 65fd9859247..cbe62b41cbf 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp @@ -4,6 +4,9 @@ struct NonTrivial {    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 @@ struct DeletedNTVariant2 { // expected-note{{here}}  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 @@ struct Deleted { // expected-note{{here}}  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 @@ struct HasAccessDtor {  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;  }; diff --git a/clang/test/CXX/special/class.copy/p11.0x.move.cpp b/clang/test/CXX/special/class.copy/p11.0x.move.cpp index 402bc31d5ee..5315b060a03 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.move.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.move.cpp @@ -4,6 +4,9 @@ struct NonTrivial {    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 @@ struct DeletedNTVariant2 {  };  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 @@ struct HasAccess {  };  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 @@ struct HasAccessDtor {  };  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&);  }; diff --git a/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp b/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp new file mode 100644 index 00000000000..0397775b7e3 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp @@ -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 diff --git a/clang/test/Lexer/has_feature_cxx0x.cpp b/clang/test/Lexer/has_feature_cxx0x.cpp index d520208d2ea..40d651dff53 100644 --- a/clang/test/Lexer/has_feature_cxx0x.cpp +++ b/clang/test/Lexer/has_feature_cxx0x.cpp @@ -235,3 +235,12 @@ int no_generalized_initializers();  // 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 diff --git a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp index e706d7346d9..0e4add84955 100644 --- a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp +++ b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp @@ -10,6 +10,12 @@ struct 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; @@ -29,3 +35,90 @@ struct s {  // 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>(); +  } +} diff --git a/clang/test/SemaCXX/discrim-union.cpp b/clang/test/SemaCXX/discrim-union.cpp new file mode 100644 index 00000000000..15c9a225ed9 --- /dev/null +++ b/clang/test/SemaCXX/discrim-union.cpp @@ -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, ""); diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index ea1992a5771..d5405e24c97 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -249,7 +249,7 @@ with clang; other versions have not been tested.</p>      <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> | 

