summaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2017-05-17 13:54:23 +0000
committerville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2017-05-17 13:54:23 +0000
commitb4d90ee21694777d1558cc9d2d29ac82cb7b168c (patch)
tree5dba2cc1db7a08d1f9a5a4c2c53436d4d65bed2e /libstdc++-v3
parenta1dda1ac8b4c9de64cfd4f709f5c04d256ea74b1 (diff)
downloadgcc-b4d90ee21694777d1558cc9d2d29ac82cb7b168c.tar.gz
Implement new C++ intrinsics __is_assignable and __is_constructible.
c-family/ Implement new C++ intrinsics __is_assignable and __is_constructible. * c-common.c (__is_assignable, __is_constructible): New. * c-common.h (RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE): Likewise. cp/ PR c++/80654 PR c++/80682 Implement new C++ intrinsics __is_assignable and __is_constructible. * cp-tree.h (CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE): New. (is_xible): New. * cxx-pretty-print.c (pp_cxx_trait_expression): Handle CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE. * method.c (constructible_expr): Set cp_unevaluated. (is_xible_helper): New. (is_trivially_xible): Adjust. (is_xible): New. * parser.c (cp_parser_primary_expression): Handle RID_IS_ASSIGNABLE and RID_IS_CONSTRUCTIBLE. (cp_parser_trait_expr): Likewise. * semantics.c (trait_expr_value): Handle CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE. testsuite/ * g++.dg/ext/80654.C: New. libstdc++-v3/ Implement new C++ intrinsics __is_assignable and __is_constructible. * include/std/type_traits (__do_is_static_castable_impl): Remove. (__is_static_castable_impl, __is_static_castable_safe): Likewise. (__is_static_castable, __do_is_direct_constructible_impl): Likewise. (__is_direct_constructible_impl): Likewise. (__is_direct_constructible_new_safe): Likewise. (__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise. (__is_direct_constructible_ref_cast): Likewise. (__is_direct_constructible_new, __is_direct_constructible): Likewise. (__do_is_nary_constructible_impl): Likewise. (__is_nary_constructible_impl, __is_nary_constructible): Likewise. (__is_constructible_impl): Likewise. (is_constructible): Call the intrinsic. (__is_assignable_helper): Remove. (is_assignable): Call the intrinsic. (is_trivially_constructible): Likewise. (__is_trivially_copy_constructible_impl): New. (is_trivially_copy_constructible): Use it. (__is_trivially_move_constructible_impl): New. (is_trivially_move_constructible): Use it. (is_trivially_assignable): Call the intrinsic. (__is_trivially_copy_assignable_impl): New. (is_trivially_copy_assignable): Use it. (__is_trivially_move_assignable_impl): New. (is_trivially_move_assignable): Use it. (testsuite/20_util/declval/requirements/1_neg.cc): Adjust. (testsuite/20_util/is_trivially_copy_assignable/value.cc): Add test for void. (testsuite/20_util/is_trivially_copy_constructible/value.cc): Likewise. (testsuite/20_util/is_trivially_move_assignable/value.cc): Likewise. (testsuite/20_util/is_trivially_move_constructible/value.cc): Likewise. (testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Adjust. (testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@248153 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog37
-rw-r--r--libstdc++-v3/include/std/type_traits290
-rw-r--r--libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc4
9 files changed, 109 insertions, 234 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index c32dc62abca..98d363acc2e 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,40 @@
+2017-05-17 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Implement new C++ intrinsics __is_assignable and __is_constructible.
+ * include/std/type_traits (__do_is_static_castable_impl): Remove.
+ (__is_static_castable_impl, __is_static_castable_safe): Likewise.
+ (__is_static_castable, __do_is_direct_constructible_impl): Likewise.
+ (__is_direct_constructible_impl): Likewise.
+ (__is_direct_constructible_new_safe): Likewise.
+ (__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
+ (__is_direct_constructible_ref_cast): Likewise.
+ (__is_direct_constructible_new, __is_direct_constructible): Likewise.
+ (__do_is_nary_constructible_impl): Likewise.
+ (__is_nary_constructible_impl, __is_nary_constructible): Likewise.
+ (__is_constructible_impl): Likewise.
+ (is_constructible): Call the intrinsic.
+ (__is_assignable_helper): Remove.
+ (is_assignable): Call the intrinsic.
+ (is_trivially_constructible): Likewise.
+ (__is_trivially_copy_constructible_impl): New.
+ (is_trivially_copy_constructible): Use it.
+ (__is_trivially_move_constructible_impl): New.
+ (is_trivially_move_constructible): Use it.
+ (is_trivially_assignable): Call the intrinsic.
+ (__is_trivially_copy_assignable_impl): New.
+ (is_trivially_copy_assignable): Use it.
+ (__is_trivially_move_assignable_impl): New.
+ (is_trivially_move_assignable): Use it.
+ (testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
+ (testsuite/20_util/is_trivially_copy_assignable/value.cc):
+ Add test for void.
+ (testsuite/20_util/is_trivially_copy_constructible/value.cc): Likewise.
+ (testsuite/20_util/is_trivially_move_assignable/value.cc): Likewise.
+ (testsuite/20_util/is_trivially_move_constructible/value.cc): Likewise.
+ (testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Adjust.
+ (testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
+ Likewise.
+
2017-05-16 Jonathan Wakely <jwakely@redhat.com>
* testsuite/experimental/source_location/1.cc: Change expected result
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index aac7cff6cf6..390b6f40af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -924,213 +924,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_default_constructible_safe<_Tp>::type
{ };
-
- // Implementation of is_constructible.
-
- // The hardest part of this trait is the binary direct-initialization
- // case, because we hit into a functional cast of the form T(arg).
- // This implementation uses different strategies depending on the
- // target type to reduce the test overhead as much as possible:
- //
- // a) For a reference target type, we use a static_cast expression
- // modulo its extra cases.
- //
- // b) For a non-reference target type we use a ::new expression.
- struct __do_is_static_castable_impl
- {
- template<typename _From, typename _To, typename
- = decltype(static_cast<_To>(declval<_From>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_impl
- : public __do_is_static_castable_impl
- {
- typedef decltype(__test<_From, _To>(0)) type;
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_safe
- : public __is_static_castable_impl<_From, _To>::type
- { };
-
- // __is_static_castable
- template<typename _From, typename _To>
- struct __is_static_castable
- : public integral_constant<bool, (__is_static_castable_safe<
- _From, _To>::value)>
- { };
-
- // Implementation for non-reference types. To meet the proper
- // variable definition semantics, we also need to test for
- // is_destructible in this case.
- // This form should be simplified by a single expression:
- // ::delete ::new _Tp(declval<_Arg>()), see c++/51222.
- struct __do_is_direct_constructible_impl
- {
- template<typename _Tp, typename _Arg, typename
- = decltype(::new _Tp(declval<_Arg>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_impl
- : public __do_is_direct_constructible_impl
- {
- typedef decltype(__test<_Tp, _Arg>(0)) type;
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new_safe
- : public __and_<is_destructible<_Tp>,
- __is_direct_constructible_impl<_Tp, _Arg>>
- { };
-
- template<typename, typename>
- struct is_same;
-
- template<typename, typename>
- struct is_base_of;
-
- template<typename>
- struct remove_reference;
-
- template<typename _From, typename _To, bool
- = __not_<__or_<is_void<_From>,
- is_function<_From>>>::value>
- struct __is_base_to_derived_ref;
-
- template<typename _Tp, typename... _Args>
- struct is_constructible;
-
- // Detect whether we have a downcast situation during
- // reference binding.
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<_From
- >::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<_To
- >::type>::type __dst_t;
- typedef __and_<__not_<is_same<__src_t, __dst_t>>,
- is_base_of<__src_t, __dst_t>,
- __not_<is_constructible<__dst_t, _From>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, false>
- : public false_type
- { };
-
- template<typename _From, typename _To, bool
- = __and_<is_lvalue_reference<_From>,
- is_rvalue_reference<_To>>::value>
- struct __is_lvalue_to_rvalue_ref;
-
- // Detect whether we have an lvalue of non-function type
- // bound to a reference-compatible rvalue-reference.
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<
- _From>::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<
- _To>::type>::type __dst_t;
- typedef __and_<__not_<is_function<__src_t>>,
- __or_<is_same<__src_t, __dst_t>,
- is_base_of<__dst_t, __src_t>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, false>
- : public false_type
- { };
-
- // Here we handle direct-initialization to a reference type as
- // equivalent to a static_cast modulo overshooting conversions.
- // These are restricted to the following conversions:
- // a) A base class value to a derived class reference
- // b) An lvalue to an rvalue-reference of reference-compatible
- // types that are not functions
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_ref_cast
- : public __and_<__is_static_castable<_Arg, _Tp>,
- __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>,
- __is_lvalue_to_rvalue_ref<_Arg, _Tp>
- >>>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new
- : public conditional<is_reference<_Tp>::value,
- __is_direct_constructible_ref_cast<_Tp, _Arg>,
- __is_direct_constructible_new_safe<_Tp, _Arg>
- >::type
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible
- : public __is_direct_constructible_new<_Tp, _Arg>::type
- { };
-
- // Since default-construction and binary direct-initialization have
- // been handled separately, the implementation of the remaining
- // n-ary construction cases is rather straightforward. We can use
- // here a functional cast, because array types are excluded anyway
- // and this form is never interpreted as a C cast.
- struct __do_is_nary_constructible_impl
- {
- template<typename _Tp, typename... _Args, typename
- = decltype(_Tp(declval<_Args>()...))>
- static true_type __test(int);
-
- template<typename, typename...>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible_impl
- : public __do_is_nary_constructible_impl
- {
- typedef decltype(__test<_Tp, _Args...>(0)) type;
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible
- : public __is_nary_constructible_impl<_Tp, _Args...>::type
- {
- static_assert(sizeof...(_Args) > 1,
- "Only useful for > 1 arguments");
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_constructible_impl
- : public __is_nary_constructible<_Tp, _Args...>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_constructible_impl<_Tp, _Arg>
- : public __is_direct_constructible<_Tp, _Arg>
- { };
-
- template<typename _Tp>
- struct __is_constructible_impl<_Tp>
- : public is_default_constructible<_Tp>
- { };
-
/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
- : public __is_constructible_impl<_Tp, _Args...>::type
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1255,26 +1052,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nothrow_move_constructible_impl<_Tp>
{ };
- template<typename _Tp, typename _Up>
- class __is_assignable_helper
- {
- template<typename _Tp1, typename _Up1,
- typename = decltype(declval<_Tp1>() = declval<_Up1>())>
- static true_type
- __test(int);
-
- template<typename, typename>
- static false_type
- __test(...);
-
- public:
- typedef decltype(__test<_Tp, _Up>(0)) type;
- };
-
/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
- : public __is_assignable_helper<_Tp, _Up>::type
+ : public __bool_constant<__is_assignable(_Tp, _Up)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1364,8 +1145,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_constructible
template<typename _Tp, typename... _Args>
struct is_trivially_constructible
- : public __and_<is_constructible<_Tp, _Args...>, integral_constant<bool,
- __is_trivially_constructible(_Tp, _Args...)>>
+ : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)>
{ };
/// is_trivially_default_constructible
@@ -1405,45 +1185,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ };
/// is_trivially_copy_constructible
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_copy_constructible_impl;
+
template<typename _Tp>
- struct is_trivially_copy_constructible
+ struct __is_trivially_copy_constructible_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_copy_constructible_impl<_Tp, true>
: public __and_<is_copy_constructible<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, const _Tp&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_copy_constructible
+ : public __is_trivially_copy_constructible_impl<_Tp>
+ { };
+
/// is_trivially_move_constructible
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_move_constructible_impl;
+
template<typename _Tp>
- struct is_trivially_move_constructible
+ struct __is_trivially_move_constructible_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_move_constructible_impl<_Tp, true>
: public __and_<is_move_constructible<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, _Tp&&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_move_constructible
+ : public __is_trivially_move_constructible_impl<_Tp>
+ { };
+
/// is_trivially_assignable
template<typename _Tp, typename _Up>
struct is_trivially_assignable
- : public __and_<is_assignable<_Tp, _Up>,
- integral_constant<bool,
- __is_trivially_assignable(_Tp, _Up)>>
+ : public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
{ };
/// is_trivially_copy_assignable
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_copy_assignable_impl;
+
template<typename _Tp>
- struct is_trivially_copy_assignable
+ struct __is_trivially_copy_assignable_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_copy_assignable_impl<_Tp, true>
: public __and_<is_copy_assignable<_Tp>,
integral_constant<bool,
__is_trivially_assignable(_Tp&, const _Tp&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_copy_assignable
+ : public __is_trivially_copy_assignable_impl<_Tp>
+ { };
+
/// is_trivially_move_assignable
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_move_assignable_impl;
+
template<typename _Tp>
- struct is_trivially_move_assignable
+ struct __is_trivially_move_assignable_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_move_assignable_impl<_Tp, true>
: public __and_<is_move_assignable<_Tp>,
integral_constant<bool,
__is_trivially_assignable(_Tp&, _Tp&&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_move_assignable
+ : public __is_trivially_move_assignable_impl<_Tp>
+ { };
+
/// is_trivially_destructible
template<typename _Tp>
struct is_trivially_destructible
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 dc9daeb42ce..4e254e89191 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -18,7 +18,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "static assertion failed" "" { target *-*-* } 2259 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2089 }
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
index b002246dfd5..902aa5e5932 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
@@ -88,4 +88,6 @@ void test01()
MoveOnly>(false), "");
static_assert(test_property<is_trivially_copy_assignable,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_copy_assignable,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
index 845e0586151..627410bdc30 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
@@ -82,4 +82,6 @@ void test01()
MoveOnly>(false), "");
static_assert(test_property<is_trivially_copy_constructible,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_copy_constructible,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
index 68833b67f12..221048347a2 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
@@ -88,4 +88,6 @@ void test01()
MoveOnly>(true), "");
static_assert(test_property<is_trivially_move_assignable,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_move_assignable,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
index ad6045bda81..9a21b6e2133 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
@@ -82,4 +82,6 @@ void test01()
MoveOnly>(true), "");
static_assert(test_property<is_trivially_move_constructible,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_move_constructible,
+ void>(false), "");
}
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 664fb70fb4b..e3e80f91979 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
@@ -47,4 +47,4 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1924 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1754 }
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 6d6471755f7..86b0c2d6da7 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
@@ -47,5 +47,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1820 }
-// { dg-error "declaration of" "" { target *-*-* } 1777 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1650 }
+