On 2 November 2015 at 17:19, Paolo Carlini <paolo.carl...@oracle.com> wrote: > Anyway, so far the only detail which makes me a little nervous is the > following: > > + template <typename _Tp> > + struct __is_implicitly_default_constructible > + : public integral_constant<bool, > + (is_default_constructible<_Tp>::value > + && > __is_implicitly_default_constructible_safe<_Tp>::value)> > > > I think we want to use __and_ (note that there isn't a single logical && in > the whole type_traits, outside macros).
Yep. New patch, tested on Linux-PPC64. Minor typo fixes for the changelog. Ok for trunk? 2015-11-01 Ville Voutilainen <ville.voutilai...@gmail.com> Make the default constructors of tuple and pair conditionally explicit. * include/std/type_traits ( __do_is_implicitly_default_constructible_impl, __is_implicitly_default_constructible_impl, __is_implicitly_default_constructible_safe, __is_implicitly_default_constructible): New. * include/bits/stl_pair.h (pair::pair()): Use it. * include/std/tuple (tuple<_T1, _T2>::tuple): Use it. * include/std/tuple (_ImplicitlyDefaultConstructibleTuple): New. * include/std/tuple (tuple<_Types...>::tuple()): Use it. * testsuite/20_util/declval/requirements/1_neg.cc: Adjust. * testsuite/20_util/is_implicitly_default_constructible/requirements/explicit_instantiation.cc: New. * testsuite/20_util/is_implicitly_default_constructible/requirements/typedefs.cc: Likewise. * testsuite/20_util/is_implicitly_default_constructible/value.cc: Likewise. * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust. * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Likewise. * testsuite/20_util/pair/cons/explicit_construct.cc: Likewise. * testsuite/20_util/tuple/cons/explicit_construct.cc: Likewise.
diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index a5a7898..dfcd357 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -141,13 +141,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _U1 = _T1, typename _U2 = _T2, typename enable_if<__and_< - is_default_constructible<_U1>, - is_default_constructible<_U2>> + __is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>> ::value, bool>::type = true> #endif _GLIBCXX_CONSTEXPR pair() : first(), second() { } +#if __cplusplus >= 201103L + template <typename _U1 = _T1, + typename _U2 = _T2, + typename enable_if<__and_< + is_default_constructible<_U1>, + is_default_constructible<_U2>, + __not_< + __and_<__is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>>>> + ::value, bool>::type = false> + explicit constexpr pair() + : first(), second() { } +#endif + /** Two objects may be passed to a @c pair constructor to be copied. */ #if __cplusplus < 201103L pair(const _T1& __a, const _T2& __b) diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 8af01f4..e6c32b3 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -551,16 +551,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __and_<is_default_constructible<_Elements>...>::value; } + static constexpr bool _ImplicitlyDefaultConstructibleTuple() + { + return __and_<__is_implicitly_default_constructible<_Elements>...> + ::value; + } }; public: template<typename _Dummy = void, typename enable_if<_TC2<_Dummy>:: - _DefaultConstructibleTuple(), + _ImplicitlyDefaultConstructibleTuple(), bool>::type = true> constexpr tuple() : _Inherited() { } + template<typename _Dummy = void, + typename enable_if<_TC2<_Dummy>:: + _DefaultConstructibleTuple() + && + !_TC2<_Dummy>:: + _ImplicitlyDefaultConstructibleTuple(), + bool>::type = false> + explicit constexpr tuple() + : _Inherited() { } + // Shortcut for the cases where constructors taking _Elements... // need to be constrained. template<typename _Dummy> using _TCC = @@ -837,13 +852,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _U1 = _T1, typename _U2 = _T2, typename enable_if<__and_< - is_default_constructible<_U1>, - is_default_constructible<_U2>> + __is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>> ::value, bool>::type = true> constexpr tuple() : _Inherited() { } + template <typename _U1 = _T1, + typename _U2 = _T2, + typename enable_if< + __and_< + is_default_constructible<_U1>, + is_default_constructible<_U2>, + __not_< + __and_<__is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>>>> + ::value, bool>::type = false> + + explicit constexpr tuple() + : _Inherited() { } + // Shortcut for the cases where constructors taking _T1, _T2 // need to be constrained. template<typename _Dummy> using _TCC = diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e08131b..6e11f17 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1337,6 +1337,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public is_trivially_constructible<_Tp>::type { }; + struct __do_is_implicitly_default_constructible_impl + { + template <typename _Tp> + static void __helper(const _Tp&); + + template <typename _Tp> + static true_type __test(const _Tp&, + decltype(__helper<const _Tp&>({}))* = 0); + + static false_type __test(...); + }; + + template<typename _Tp> + struct __is_implicitly_default_constructible_impl + : public __do_is_implicitly_default_constructible_impl + { + typedef decltype(__test(declval<_Tp>())) type; + }; + + template<typename _Tp> + struct __is_implicitly_default_constructible_safe + : public __is_implicitly_default_constructible_impl<_Tp>::type + { }; + + template <typename _Tp> + struct __is_implicitly_default_constructible + : public integral_constant<bool, + (__and_<is_default_constructible<_Tp>, + __is_implicitly_default_constructible_safe<_Tp> + >::value)> + { }; + /// is_trivially_copy_constructible template<typename _Tp> struct is_trivially_copy_constructible diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc index 2723e5c..e3a33ae 100644 --- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc +++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc @@ -19,7 +19,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-error "static assertion failed" "" { target *-*-* } 2209 } +// { dg-error "static assertion failed" "" { target *-*-* } 2241 } #include <utility> diff --git a/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/explicit_instantiation.cc new file mode 100644 index 0000000..acc9f37 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/explicit_instantiation.cc @@ -0,0 +1,27 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <type_traits> + +namespace std +{ + typedef short test_type; + template struct std::__is_implicitly_default_constructible<test_type>; +} diff --git a/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/typedefs.cc new file mode 100644 index 0000000..234b06c --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/requirements/typedefs.cc @@ -0,0 +1,32 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <type_traits> + + +void test01() +{ + // Check for required typedefs + typedef std::__is_implicitly_default_constructible<int> test_type; + typedef test_type::value_type value_type; + typedef test_type::type type; + typedef test_type::type::value_type type_value_type; + typedef test_type::type::type type_type; +} diff --git a/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/value.cc new file mode 100644 index 0000000..aff4955 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_implicitly_default_constructible/value.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <type_traits> + +struct ExplicitDefault +{ + explicit ExplicitDefault() {} +}; + +struct ExplicitDefaultDefault +{ + explicit ExplicitDefaultDefault() = default; +}; + +void test01() +{ + using std::__is_implicitly_default_constructible; + // Positive tests. + static_assert(__is_implicitly_default_constructible<int>::value, ""); + // Negative tests. + static_assert(!__is_implicitly_default_constructible<int&>::value, ""); + static_assert(!__is_implicitly_default_constructible< + ExplicitDefault>::value, ""); + static_assert(!__is_implicitly_default_constructible< + ExplicitDefaultDefault>::value, ""); +} diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc index 507930d..3a3f6b5 100644 --- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc @@ -48,4 +48,4 @@ void test01() // { dg-error "required from here" "" { target *-*-* } 40 } // { dg-error "required from here" "" { target *-*-* } 42 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1874 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1906 } diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc index 608fd1a..79fea75 100644 --- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc @@ -48,5 +48,5 @@ void test01() // { dg-error "required from here" "" { target *-*-* } 40 } // { dg-error "required from here" "" { target *-*-* } 42 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1770 } -// { dg-error "declaration of" "" { target *-*-* } 1727 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1802 } +// { dg-error "declaration of" "" { target *-*-* } 1759 } diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc index 50edda9..ac1dc7e 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc @@ -26,6 +26,16 @@ struct Explicit explicit Explicit(int) {} }; +struct ExplicitDefault +{ + explicit ExplicitDefault() {} +}; + +struct ExplicitDefaultDefault +{ + explicit ExplicitDefaultDefault() = default; +}; + std::pair<int, int> f1() {return {1,2};} std::pair<Explicit, Explicit> f2() {return {1,2};} // { dg-error "explicit" } @@ -72,6 +82,20 @@ void f6(std::pair<Explicit, Explicit>) {} void f7(std::pair<long, long>) {} +std::pair<ExplicitDefault, int> f8() +{ + return {}; // { dg-error "explicit" } +} + +std::pair<ExplicitDefaultDefault, int> f9() +{ + return {}; // { dg-error "explicit" } +} + +void f10(std::pair<ExplicitDefault, int>) {} + +void f11(std::pair<ExplicitDefaultDefault, int>) {} + void test_arg_passing() { f6(v0); // { dg-error "could not convert" } @@ -84,6 +108,10 @@ void test_arg_passing() f7({1,2}); f7(std::pair<int, int>{}); f7(std::pair<long, long>{}); + f10({}); // { dg-error "explicit" } + f11({}); // { dg-error "explicit" } + f10(std::pair<ExplicitDefault, int>{}); + f11(std::pair<ExplicitDefaultDefault, int>{}); } struct MoveOnly diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc index 114a490..4d97cfb 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc @@ -28,13 +28,26 @@ struct Explicit explicit Explicit(int) {} }; +struct ExplicitDefault +{ + explicit ExplicitDefault() {} +}; + +struct ExplicitDefaultDefault +{ + explicit ExplicitDefaultDefault() = default; +}; + std::tuple<int> f1a() {return {1};} std::tuple<int, int> f1b() {return {1,2};} std::tuple<int, int, int> f1c() {return {1,2,3};} -std::tuple<Explicit> f2_a() {return {1};} // { dg-error "explicit" } -std::tuple<Explicit, Explicit> f2_b() {return {1,2};} // { dg-error "explicit" } -std::tuple<Explicit, Explicit, Explicit> f2_c() {return {1,2,3};} // { dg-error "explicit" } +std::tuple<Explicit> f2_a() +{return {1};} // { dg-error "explicit" } +std::tuple<Explicit, Explicit> f2_b() +{return {1,2};} // { dg-error "explicit" } +std::tuple<Explicit, Explicit, Explicit> f2_c() +{return {1,2,3};} // { dg-error "explicit" } std::tuple<long> f3_a() {return std::tuple<int>{1};} std::tuple<long, long> f3_b() {return std::tuple<int, int>{1,2};} @@ -57,6 +70,24 @@ std::tuple<long> f5_a() {return {1};} std::tuple<long, long> f5_b() {return {1,2};} std::tuple<long, long, long> f5_c() {return {1,2,3};} +std::tuple<ExplicitDefault> f6_a() +{return {};} // { dg-error "explicit" } +std::tuple<ExplicitDefault, ExplicitDefault> f6_b() +{return {};} // { dg-error "explicit" } +std::tuple<ExplicitDefault, ExplicitDefault, ExplicitDefault> f6_c() +{return {};} // { dg-error "explicit" } +std::tuple<ExplicitDefault, int> f6_d() +{return {};} // { dg-error "explicit" } + +std::tuple<ExplicitDefaultDefault> f7_a() +{return {};} // { dg-error "explicit" } +std::tuple<ExplicitDefaultDefault, ExplicitDefaultDefault> f7_b() +{return {};} // { dg-error "explicit" } +std::tuple<ExplicitDefaultDefault, + ExplicitDefaultDefault, + ExplicitDefaultDefault> f7_c() +{return {};} // { dg-error "explicit" } + std::tuple<int, int> fp1() {return std::pair<int, int>{1,2}; } std::tuple<long, long> fp2() {return std::pair<int, int>{1,2}; } std::tuple<Explicit, Explicit> fp3() @@ -163,7 +194,7 @@ std::tuple<long, long, long> v31_c{std::allocator_arg, std::allocator<int>{}, 1,2,3}; std::tuple<Explicit> v32_a - = {std::allocator_arg, std::allocator<int>{}, 1}; // { dg-error "explicit" } + = {std::allocator_arg, std::allocator<int>{ }, 1}; // { dg-error "explicit" } std::tuple<Explicit, Explicit> v32_b = {std::allocator_arg, std::allocator<int>{}, 1, 2}; // { dg-error "explicit" } std::tuple<Explicit, Explicit, Explicit> v32_c @@ -199,7 +230,19 @@ std::tuple<int, int> v42 = {std::allocator_arg, std::allocator<int>{}, v20}; std::tuple<long, long> v43 = {std::allocator_arg, std::allocator<int>{}, v20}; std::tuple<Explicit, Explicit> v44 -= {std::allocator_arg, std::allocator<int>{}, v20}; // { dg-error "explicit" } += {std::allocator_arg, std::allocator<int>{ }, v20}; // { dg-error "explicit" } +std::tuple<ExplicitDefault> v45_a{}; +std::tuple<ExplicitDefault, int> v45_b{}; + +std::tuple<ExplicitDefault> v46_a = {}; // { dg-error "explicit" } +std::tuple<ExplicitDefault, int> v46_b = {}; // { dg-error "explicit" } + +std::tuple<ExplicitDefaultDefault> v47_a{}; +std::tuple<ExplicitDefaultDefault, int> v47_b{}; + +std::tuple<ExplicitDefaultDefault> v48_a = {}; // { dg-error "explicit" } +std::tuple<ExplicitDefaultDefault, int> v48_b = { }; // { dg-error "explicit" } + struct DeletedCopy { @@ -225,58 +268,73 @@ std::tuple<int, int, Sanity> v50(std::allocator_arg, std::allocator<Sanity>{}, 3, 4, {42}); -void f6_a(std::tuple<Explicit>) {} -void f6_b(std::tuple<Explicit, Explicit>) {} -void f6_c(std::tuple<Explicit, Explicit, Explicit>) {} +void f8_a(std::tuple<Explicit>) {} +void f8_b(std::tuple<Explicit, Explicit>) {} +void f8_c(std::tuple<Explicit, Explicit, Explicit>) {} + +void f9_a(std::tuple<long>) {} +void f9_b(std::tuple<long, long>) {} +void f9_c(std::tuple<long, long, long>) {} + +void f10_a(std::tuple<ExplicitDefault>) {} +void f10_b(std::tuple<ExplicitDefault, int>) {} -void f7_a(std::tuple<long>) {} -void f7_b(std::tuple<long, long>) {} -void f7_c(std::tuple<long, long, long>) {} +void f11_a(std::tuple<ExplicitDefaultDefault>) {} +void f11_b(std::tuple<ExplicitDefaultDefault, int>) {} void test_arg_passing() { - f6_a(v0_a); // { dg-error "could not convert" } - f6_b(v0_b); // { dg-error "could not convert" } - f6_c(v0_c); // { dg-error "could not convert" } - f6_b(v20); // { dg-error "could not convert" } - - f6_a(v1_a); - f6_b(v1_b); - f6_c(v1_c); - - f6_a({1}); // { dg-error "explicit" } - f6_b({1,2}); // { dg-error "explicit" } - f6_c({1,2,3}); // { dg-error "explicit" } - - f6_a(std::tuple<Explicit>{}); - f6_b(std::tuple<Explicit, Explicit>{}); - f6_c(std::tuple<Explicit, Explicit, Explicit>{}); - - f6_a(std::tuple<int>{}); // { dg-error "could not convert" } - f6_b(std::tuple<int, int>{}); // { dg-error "could not convert" } - f6_c(std::tuple<int, int, int>{}); // { dg-error "could not convert" } - f6_b(std::pair<int, int>{}); // { dg-error "could not convert" } - - f7_a(v0_a); - f7_b(v0_b); - f7_c(v0_c); - f7_b(v20); - - f7_a(v6_a); - f7_b(v6_b); - f7_c(v6_c); - - f7_a({1}); - f7_b({1,2}); - f7_c({1,2,3}); - - f7_a(std::tuple<int>{}); - f7_b(std::tuple<int, int>{}); - f7_c(std::tuple<int, int, int>{}); - f7_b(std::pair<int, int>{}); - - - f7_a(std::tuple<long>{}); - f7_b(std::tuple<long, long>{}); - f7_c(std::tuple<long, long, long>{}); + f8_a(v0_a); // { dg-error "could not convert" } + f8_b(v0_b); // { dg-error "could not convert" } + f8_c(v0_c); // { dg-error "could not convert" } + f8_b(v20); // { dg-error "could not convert" } + + f8_a(v1_a); + f8_b(v1_b); + f8_c(v1_c); + + f8_a({1}); // { dg-error "explicit" } + f8_b({1,2}); // { dg-error "explicit" } + f8_c({1,2,3}); // { dg-error "explicit" } + + f8_a(std::tuple<Explicit>{}); + f8_b(std::tuple<Explicit, Explicit>{}); + f8_c(std::tuple<Explicit, Explicit, Explicit>{}); + + f8_a(std::tuple<int>{}); // { dg-error "could not convert" } + f8_b(std::tuple<int, int>{}); // { dg-error "could not convert" } + f8_c(std::tuple<int, int, int>{}); // { dg-error "could not convert" } + f8_b(std::pair<int, int>{}); // { dg-error "could not convert" } + + f9_a(v0_a); + f9_b(v0_b); + f9_c(v0_c); + f9_b(v20); + + f9_a(v6_a); + f9_b(v6_b); + f9_c(v6_c); + + f9_a({1}); + f9_b({1,2}); + f9_c({1,2,3}); + + f9_a(std::tuple<int>{}); + f9_b(std::tuple<int, int>{}); + f9_c(std::tuple<int, int, int>{}); + f9_b(std::pair<int, int>{}); + + f9_a(std::tuple<long>{}); + f9_b(std::tuple<long, long>{}); + f9_c(std::tuple<long, long, long>{}); + + f10_a({}); // { dg-error "explicit" } + f10_b({}); // { dg-error "explicit" } + f11_a({}); // { dg-error "explicit" } + f11_b({}); // { dg-error "explicit" } + + f10_a(std::tuple<ExplicitDefault>{}); + f10_b(std::tuple<ExplicitDefault, int>{}); + f11_a(std::tuple<ExplicitDefaultDefault>{}); + f11_b(std::tuple<ExplicitDefaultDefault, int>{}); }