Re: [C++ PATCH, RFC] PR c++/63959, continued
On 03/06/2015 06:03 PM, Ville Voutilainen wrote: So.. just to clarify that we're on the same page.. making volatile-qualified types non-trivially copyable is ok, but making wrappers of volatile-qualified types non-trivially copyable is not ok? That's easily doable implementation-wise, but it makes me question the overall approach and its consistency. Indeed. This is a question for CWG; we may want to reconsider the first point as well. Is there a way to indicate that from the point of C++ a type is not trivially copyable without changing the complexness of a copy operation, ultimately without changing ABI? There are various hacks I can imagine, but I think I'd prefer to resolve the standard issue before trying to implement it. Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 6 March 2015 at 23:58, Jason Merrill ja...@redhat.com wrote: On 01/19/2015 11:28 AM, Ville Voutilainen wrote: * class.c (check_field_decls): If any field is volatile, make the class type have complex copy/move operations. Discussion on the cxx-abi list points out that this breaks ABI compatibility between C and C++, and is therefore unacceptable. So.. just to clarify that we're on the same page.. making volatile-qualified types non-trivially copyable is ok, but making wrappers of volatile-qualified types non-trivially copyable is not ok? That's easily doable implementation-wise, but it makes me question the overall approach and its consistency. Is there a way to indicate that from the point of C++ a type is not trivially copyable without changing the complexness of a copy operation, ultimately without changing ABI?
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 01/19/2015 11:28 AM, Ville Voutilainen wrote: * class.c (check_field_decls): If any field is volatile, make the class type have complex copy/move operations. Discussion on the cxx-abi list points out that this breaks ABI compatibility between C and C++, and is therefore unacceptable. Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 30 January 2015 at 23:06, Ville Voutilainen ville.voutilai...@gmail.com wrote: Let's drop libstdc++, this discussion is about a test that doesn't really concern them. On 30 January 2015 at 22:51, Jason Merrill ja...@redhat.com wrote: The patch changes all the static_assert strings to , which is not very useful; let's keep the macro. Ok. How about this one? It reuses the macro and keeps the YES/NO, but utilizes intermediate classes that perform the type transformations for the TRY macros in a non-surprising c++ manner. Just a slight alternative, use TRY in YES/NO as well. It doesn't change the diagnostics when such a check fails, apparently, but it's a tad neater. :) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1273064..ca01e5a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3727,6 +3727,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 915048d..d376a09 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7477,7 +7477,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (scalarish_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index afb57a3..7f84f00 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..71019a6 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -16,12 +16,23 @@ #include type_traits #define TRY(expr) static_assert (expr, #expr) -#define YES(type) TRY(std::is_trivialtype::value); \ - TRY(std::is_trivialtype[]::value); \ - TRY(std::is_trivialconst volatile type::value) -#define NO(type) TRY(!std::is_trivialtype::value); \ - TRY(!std::is_trivialtype[]::value); \ - TRY(!std::is_trivialconst volatile type::value) + +template class T struct Yes +{ + TRY(std::is_trivialT::value); + TRY(std::is_trivialT[]::value); + TRY(!std::is_trivialconst volatile T::value); +}; + +template class T struct No +{ + TRY(!std::is_trivialT::value); + TRY(!std::is_trivialT[]::value); + TRY(!std::is_trivialconst volatile T::value); +}; + +#define YES(expr) TRY(sizeof(decltype(Yesexpr( +#define NO(expr) TRY(sizeof(decltype(Noexpr( struct A; diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C index a5bac7b..35ef1f1 100644 --- a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C +++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C @@ -39,5 +39,16 @@ SA(!__is_trivially_copyable(volatile int)); struct E1 {const int val;}; SA(__is_trivially_copyable(E1)); +SA(!__is_trivially_copyable(volatile E1)); struct E2 {int val;}; SA(__is_trivially_copyable(E2)); +struct E3 {volatile int val;}; +SA(!__is_trivially_copyable(E3)); +struct E4 {A a;}; +SA(!__is_trivially_copyable(volatile E4)); +struct E5 {volatile A a;}; +SA(!__is_trivially_copyable(E5)); +SA(!__is_trivially_copyable(volatile E5)); +struct E6 : A {}; +SA(__is_trivially_copyable(E6)); +SA(!__is_trivially_copyable(volatile E6)); diff --git a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc b/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc index ea58a22..ab88c3a 100644 --- a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc +++
Re: [C++ PATCH, RFC] PR c++/63959, continued
Let's drop libstdc++, this discussion is about a test that doesn't really concern them. On 30 January 2015 at 22:51, Jason Merrill ja...@redhat.com wrote: The patch changes all the static_assert strings to , which is not very useful; let's keep the macro. Ok. How about this one? It reuses the macro and keeps the YES/NO, but utilizes intermediate classes that perform the type transformations for the TRY macros in a non-surprising c++ manner. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1273064..ca01e5a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3727,6 +3727,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 915048d..d376a09 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7477,7 +7477,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (scalarish_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index afb57a3..7f84f00 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..6df50d1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -16,12 +16,23 @@ #include type_traits #define TRY(expr) static_assert (expr, #expr) -#define YES(type) TRY(std::is_trivialtype::value); \ - TRY(std::is_trivialtype[]::value); \ - TRY(std::is_trivialconst volatile type::value) -#define NO(type) TRY(!std::is_trivialtype::value); \ - TRY(!std::is_trivialtype[]::value); \ - TRY(!std::is_trivialconst volatile type::value) + +template class T struct Yes +{ + TRY(std::is_trivialT::value); + TRY(std::is_trivialT[]::value); + TRY(!std::is_trivialconst volatile T::value); +}; + +template class T struct No +{ + TRY(!std::is_trivialT::value); + TRY(!std::is_trivialT[]::value); + TRY(!std::is_trivialconst volatile T::value); +}; + +#define YES(expr) static_assert(sizeof(decltype(Yesexpr())), ) +#define NO(expr) static_assert(sizeof(decltype(Noexpr())), ) struct A; diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C index a5bac7b..35ef1f1 100644 --- a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C +++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C @@ -39,5 +39,16 @@ SA(!__is_trivially_copyable(volatile int)); struct E1 {const int val;}; SA(__is_trivially_copyable(E1)); +SA(!__is_trivially_copyable(volatile E1)); struct E2 {int val;}; SA(__is_trivially_copyable(E2)); +struct E3 {volatile int val;}; +SA(!__is_trivially_copyable(E3)); +struct E4 {A a;}; +SA(!__is_trivially_copyable(volatile E4)); +struct E5 {volatile A a;}; +SA(!__is_trivially_copyable(E5)); +SA(!__is_trivially_copyable(volatile E5)); +struct E6 : A {}; +SA(__is_trivially_copyable(E6)); +SA(!__is_trivially_copyable(volatile E6)); diff --git a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc b/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc index ea58a22..ab88c3a 100644 --- a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc +++ b/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc @@ -31,30 +31,31 @@ void test01() using namespace __gnu_test; // Positive tests. - static_assert(test_categoryhas_trivial_copy_constructor, int(true), ); -
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 01/30/2015 03:05 PM, Ville Voutilainen wrote: -#define TRY(expr) static_assert (expr, #expr) The patch changes all the static_assert strings to , which is not very useful; let's keep the macro. Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 30 January 2015 at 21:59, Ville Voutilainen ville.voutilai...@gmail.com wrote: So, a new patch attached. The only change to the previous one is the change to the trivial1.C test. Oops. The No-template was borken and there was remnants of the macros in commented code. Let's try that again, shall we? :) Attached. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1273064..ca01e5a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3727,6 +3727,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 915048d..d376a09 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7477,7 +7477,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (scalarish_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index afb57a3..7f84f00 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..49dc26b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -15,31 +15,38 @@ #include type_traits -#define TRY(expr) static_assert (expr, #expr) -#define YES(type) TRY(std::is_trivialtype::value); \ - TRY(std::is_trivialtype[]::value); \ - TRY(std::is_trivialconst volatile type::value) -#define NO(type) TRY(!std::is_trivialtype::value); \ - TRY(!std::is_trivialtype[]::value); \ - TRY(!std::is_trivialconst volatile type::value) + +template class T struct Yes +{ + static constexpr bool value = std::is_trivialT::value + std::is_trivialT[]::value + !std::is_trivialconst volatile T::value; +}; + +template class T struct No +{ + static constexpr bool value = !std::is_trivialT::value + !std::is_trivialT[]::value + !std::is_trivialconst volatile T::value; +}; struct A; -YES(int); -YES(__complex int); -YES(void *); -YES(int A::*); +static_assert(Yesint::value, ); +static_assert(Yes__complex int::value, ); +static_assert(Yesvoid *::value, ); +static_assert(Yesint A::*::value, ); typedef int (A::*pmf)(); -YES(pmf); +static_assert(Yespmf::value, ); struct A { ~A(); }; -NO(A); +static_assert(NoA::value, ); struct F: public A { int i; }; -NO(F); +static_assert(NoF::value, ); struct G: public A { A a; }; -NO(G); +static_assert(NoG::value, ); struct M { A a; }; -NO(M); +static_assert(NoM::value, ); class B { @@ -50,15 +57,15 @@ class B int A::* pm; int (A::*pmf)(); }; -YES(B); +static_assert(YesB::value, ); struct D: public B { }; -YES(D); +static_assert(YesD::value, ); struct E: public B { int q; }; -YES(E); +static_assert(YesE::value, ); struct D2: public B { }; -YES(D2); +static_assert(YesD2::value, ); struct I: public D, public D2 { }; -YES(I); +static_assert(YesI::value, ); struct C { @@ -66,21 +73,21 @@ struct C private: int j; }; -YES(C); +static_assert(YesC::value, ); struct H: public C { }; -YES(H); +static_assert(YesH::value, ); struct N { C c; }; -YES(N); +static_assert(YesN::value, ); struct J { virtual void f(); }; struct J2: J { }; -NO(J); -NO(J2); +static_assert(NoJ::value, ); +static_assert(NoJ2::value, ); struct K { }; struct L: virtual K {}; -YES(K); -NO(L); +static_assert(YesK::value, ); +static_assert(NoL::value, ); // PR c++/41421 struct O { O(int); }; -NO(O); +static_assert(NoO::value, ); diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 30 January 2015 at 19:46, Jason Merrill ja...@redhat.com wrote: On 01/20/2015 09:27 AM, Ville Voutilainen wrote: +#define YES2(type) TRY(std::is_trivialtype::value); \ + TRY(std::is_trivialtype[]::value); \ TRY(std::is_trivialconst volatile type::value) +YES2(void *); +YES2(int A::*); Why would void *const volatile still be trivial? Ah. It isn't. YES and YES2 are macros, so YES2(void*) expands to is_trivialconst volatile void*::value, which is true, whereas is_trivialvoid* const volatile::value is false. I think it would be reasonable to convert these macros in that test into function templates, no? :)
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 01/20/2015 09:27 AM, Ville Voutilainen wrote: +#define YES2(type) TRY(std::is_trivialtype::value); \ + TRY(std::is_trivialtype[]::value); \ TRY(std::is_trivialconst volatile type::value) +YES2(void *); +YES2(int A::*); Why would void *const volatile still be trivial? Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 30 January 2015 at 20:25, Jason Merrill ja...@redhat.com wrote: On 01/30/2015 01:13 PM, Ville Voutilainen wrote: Why would void *const volatile still be trivial? Ah. It isn't. YES and YES2 are macros, so YES2(void*) expands to is_trivialconst volatile void*::value, which is true, whereas is_trivialvoid* const volatile::value is false. I think it would be reasonable to convert these macros in that test into function templates, no? :) Makes sense to me. :) Jason So, a new patch attached. The only change to the previous one is the change to the trivial1.C test. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1273064..ca01e5a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3727,6 +3727,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 915048d..d376a09 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7477,7 +7477,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (scalarish_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index afb57a3..7f84f00 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..5e574da 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -15,31 +15,49 @@ #include type_traits -#define TRY(expr) static_assert (expr, #expr) -#define YES(type) TRY(std::is_trivialtype::value); \ + +template class T struct Yes +{ + static constexpr bool value = std::is_trivialT::value + std::is_trivialT[]::value + !std::is_trivialconst volatile T::value; +}; + +template class T struct No +{ + static constexpr bool value = !std::is_trivialT[]::value + !std::is_trivialconst volatile T::value; +}; + +/* +#define Yes(type) TRY(std::is_trivialtype::value); \ + TRY(std::is_trivialtype[]::value); \ + TRY(!std::is_trivialconst volatile type::value) +#define Yes2(type) TRY(std::is_trivialtype::value); \ TRY(std::is_trivialtype[]::value); \ TRY(std::is_trivialconst volatile type::value) -#define NO(type) TRY(!std::is_trivialtype::value); \ +#define No(type) TRY(!std::is_trivialtype::value); \ TRY(!std::is_trivialtype[]::value); \ TRY(!std::is_trivialconst volatile type::value) +*/ struct A; -YES(int); -YES(__complex int); -YES(void *); -YES(int A::*); +static_assert(Yesint::value, ); +static_assert(Yes__complex int::value, ); +static_assert(Yesvoid *::value, ); +static_assert(Yesint A::*::value, ); typedef int (A::*pmf)(); -YES(pmf); +static_assert(Yespmf::value, ); struct A { ~A(); }; -NO(A); +static_assert(NoA::value, ); struct F: public A { int i; }; -NO(F); +static_assert(NoF::value, ); struct G: public A { A a; }; -NO(G); +static_assert(NoG::value, ); struct M { A a; }; -NO(M); +static_assert(NoM::value, ); class B { @@ -50,15 +68,15 @@ class B int A::* pm; int (A::*pmf)(); }; -YES(B); +static_assert(YesB::value, ); struct D: public B { }; -YES(D); +static_assert(YesD::value, ); struct E: public B { int q; }; -YES(E); +static_assert(YesE::value, ); struct D2: public B { }; -YES(D2); +static_assert(YesD2::value, ); struct I: public D, public D2 { }; -YES(I); +static_assert(YesI::value, ); struct C { @@ -66,21 +84,21 @@ struct C private: int j; }; -YES(C); +static_assert(YesC::value, ); struct H: public C { }; -YES(H);
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 01/30/2015 01:13 PM, Ville Voutilainen wrote: Why would void *const volatile still be trivial? Ah. It isn't. YES and YES2 are macros, so YES2(void*) expands to is_trivialconst volatile void*::value, which is true, whereas is_trivialvoid* const volatile::value is false. I think it would be reasonable to convert these macros in that test into function templates, no? :) Makes sense to me. :) Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 01/19/2015 06:06 PM, Ville Voutilainen wrote: + return (trivial_type_p (type1) + || (scalarish_type_p (type1) CP_TYPE_VOLATILE_P (type1)) + || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); I think we can drop the trivial_type_p check now, it's redundant. Jason
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 20 January 2015 at 15:06, Jason Merrill ja...@redhat.com wrote: On 01/19/2015 06:06 PM, Ville Voutilainen wrote: + return (trivial_type_p (type1) + || (scalarish_type_p (type1) CP_TYPE_VOLATILE_P (type1)) + || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); I think we can drop the trivial_type_p check now, it's redundant. Well, we can do even better, just check for scalarish_type instead of trivial || scalarish volatile. ;) Patch attached, changelog as before. I re-ran the tests that previously were failing in the first versions of the patch, didn't run the full suite again, as I unfortunately need to run. :) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index edb87fe..529a2bf 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3717,6 +3717,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 15b8d01..5856670 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7383,7 +7383,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (scalarish_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 80f2ce6..79be556 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..d0d7b46 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -18,6 +18,9 @@ #define TRY(expr) static_assert (expr, #expr) #define YES(type) TRY(std::is_trivialtype::value); \ TRY(std::is_trivialtype[]::value); \ + TRY(!std::is_trivialconst volatile type::value) +#define YES2(type) TRY(std::is_trivialtype::value); \ + TRY(std::is_trivialtype[]::value); \ TRY(std::is_trivialconst volatile type::value) #define NO(type) TRY(!std::is_trivialtype::value); \ TRY(!std::is_trivialtype[]::value); \ @@ -27,8 +30,8 @@ struct A; YES(int); YES(__complex int); -YES(void *); -YES(int A::*); +YES2(void *); +YES2(int A::*); typedef int (A::*pmf)(); YES(pmf); diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C index a5bac7b..35ef1f1 100644 --- a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C +++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C @@ -39,5 +39,16 @@ SA(!__is_trivially_copyable(volatile int)); struct E1 {const int val;}; SA(__is_trivially_copyable(E1)); +SA(!__is_trivially_copyable(volatile E1)); struct E2 {int val;}; SA(__is_trivially_copyable(E2)); +struct E3 {volatile int val;}; +SA(!__is_trivially_copyable(E3)); +struct E4 {A a;}; +SA(!__is_trivially_copyable(volatile E4)); +struct E5 {volatile A a;}; +SA(!__is_trivially_copyable(E5)); +SA(!__is_trivially_copyable(volatile E5)); +struct E6 : A {}; +SA(__is_trivially_copyable(E6)); +SA(!__is_trivially_copyable(volatile E6)); diff --git a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc b/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc index ea58a22..9cfe672 100644 --- a/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc +++ b/libstdc++-v3/testsuite/20_util/has_trivial_copy_constructor/value.cc @@ -31,30 +31,31 @@ void test01() using namespace __gnu_test; // Positive tests. -
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 19 January 2015 at 21:12, Ville Voutilainen ville.voutilai...@gmail.com wrote: On 19 January 2015 at 18:28, Ville Voutilainen ville.voutilai...@gmail.com wrote: When I patched the triviality test for volatile types, I missed two cases: 1) volatile members in a class should make the class non-trivial. 2) a volatile class type should itself be non-trivial. (based on [basic.types]/9, [class]/6, [class.copy]/12 and [class.copy]/25) I haven't completed testing this yet, I still need to run the full testsuite to make sure there are no regressions. I'm not sure whether this can go into gcc5, since we're at stage 4. Not quite done yet, some tests need adjusting, I will fix them shortly. Ok, this ended up being a tad more involved than I hoped. Tested on Linux-x64. I'm copying libstdc++ as well, since I'm mucking with the library tests as well here. The changes in the library tests from using test_category to using the traits directly isn't the prettiest thing I've ever done, but the issue is that no volatile type is trivially_anything, except trivially_destructible, so test_category is unsuitable. Please double-check that I didn't miss any test failures, as this got rather involved, as I said. /cp 2015-01-20 Ville Voutilainen ville.voutilai...@gmail.com PR c++/63959 * class.c (check_field_decls): If any field is volatile, make the class type have complex copy/move operations. * semantics.c (trait_expr_value): For __has_trivial_destructor, allow types that are not trivial, but are scalarish and volatile. * tree.c (trivially_copyable_p): Check CP_TYPE_VOLATILE_P for class types too. * tree.c (trivial_type_p): Check CP_TYPE_VOLATILE_P. /testsuite 2015-01-20 Ville Voutilainen ville.voutilai...@gmail.com PR c++/63959 * g++.dg/cpp0x/trivial1.C: Adjust. * g++.dg/ext/is_trivially_constructible1.C: Adjust. /testsuite 2015-01-20 Ville Voutilainen ville.voutilai...@gmail.com PR c++/63959 * 20_util/has_trivial_copy_constructor/value.cc: Adjust. * 20_util/has_trivial_default_constructor/value.cc: Adjust. * 20_util/is_pod/value.cc: Adjust. * 20_util/is_trivial/value.cc: Adjust. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index edb87fe..529a2bf 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3717,6 +3717,16 @@ check_field_decls (tree t, tree *access_decls, if (DECL_INITIAL (x) cxx_dialect cxx14) CLASSTYPE_NON_AGGREGATE (t) = true; + /* If any field is volatile, the structure type has complex copy +and move operations. */ + if (CP_TYPE_VOLATILE_P (type)) + { + TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1; + TYPE_HAS_COMPLEX_COPY_CTOR (t) = 1; + TYPE_HAS_COMPLEX_MOVE_CTOR (t) = 1; + } + /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 15b8d01..67152cd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7383,7 +7383,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE + return (trivial_type_p (type1) + || (scalarish_type_p (type1) CP_TYPE_VOLATILE_P (type1)) + || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 80f2ce6..79be556 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3211,7 +3211,8 @@ trivially_copyable_p (const_tree t) (!TYPE_HAS_COPY_ASSIGN (t) || !TYPE_HAS_COMPLEX_COPY_ASSIGN (t)) !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) -TYPE_HAS_TRIVIAL_DESTRUCTOR (t)); +TYPE_HAS_TRIVIAL_DESTRUCTOR (t) +!CP_TYPE_VOLATILE_P (t)); else return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } @@ -3228,7 +3229,7 @@ trivial_type_p (const_tree t) return (TYPE_HAS_TRIVIAL_DFLT (t) trivially_copyable_p (t)); else -return scalarish_type_p (t); +return !CP_TYPE_VOLATILE_P (t) scalarish_type_p (t); } /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/trivial1.C b/gcc/testsuite/g++.dg/cpp0x/trivial1.C index 3fed570..d0d7b46 100644 --- a/gcc/testsuite/g++.dg/cpp0x/trivial1.C +++ b/gcc/testsuite/g++.dg/cpp0x/trivial1.C @@ -18,6 +18,9 @@ #define TRY(expr) static_assert (expr, #expr) #define YES(type) TRY(std::is_trivialtype::value); \ TRY(std::is_trivialtype[]::value); \ + TRY(!std::is_trivialconst volatile type::value) +#define YES2(type) TRY(std::is_trivialtype::value); \ + TRY(std::is_trivialtype[]::value); \ TRY(std::is_trivialconst volatile type::value) #define NO(type)
Re: [C++ PATCH, RFC] PR c++/63959, continued
On 19 January 2015 at 18:28, Ville Voutilainen ville.voutilai...@gmail.com wrote: When I patched the triviality test for volatile types, I missed two cases: 1) volatile members in a class should make the class non-trivial. 2) a volatile class type should itself be non-trivial. (based on [basic.types]/9, [class]/6, [class.copy]/12 and [class.copy]/25) I haven't completed testing this yet, I still need to run the full testsuite to make sure there are no regressions. I'm not sure whether this can go into gcc5, since we're at stage 4. Not quite done yet, some tests need adjusting, I will fix them shortly.