aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-04-26 21:16:21 +0100
committerJonathan Wakely <jwakely@redhat.com>2021-04-26 21:16:21 +0100
commit06c86a4f210c76a157512a2963e6c31302d161cb (patch)
tree53e2126bff13e0a82f5f78dbe9018a11831c6bf2 /libstdc++-v3
parent49adc066729bda093b0658e3926bbf64cd4628b3 (diff)
downloadgcc-06c86a4f210c76a157512a2963e6c31302d161cb.zip
gcc-06c86a4f210c76a157512a2963e6c31302d161cb.tar.gz
gcc-06c86a4f210c76a157512a2963e6c31302d161cb.tar.bz2
libstdc++: Fix socket option classes
This fixes some flaws in the socket option types defined in net::socket_base: - The constructors were not noexcept. - The __sockopt_base<T>::value() member function was present unconditionally (so was defined for socket_base::linger which is incorrect). - The __socket_crtp<C, T>::operator=(T) assignment operator was not noexcept, and was hidden in the derived classes. Also: - Use class instead of struct for the socket option types. - Define the _S_level and _S_name constants as private. - Declare the __socket_crtp base as a friend. libstdc++-v3/ChangeLog: * include/experimental/bits/net.h (__socket_base): Add bool template parameter to allow BooleanSocketOption and IntegerSocketOption to have different __socket_base<int> base classes. (__socket_base<bool>): Adjust base class. (__socket_base<int>): Add partial specialization. (__socket_crtp::operator=(_Tp)): Add noexcept-specifier. * include/experimental/socket (socket_base::broadcast) (socket_base::debug, socket_base::do_not_route) (socket_base::keep_alive, socket_base::linger) (socket_base::out_of_band_inline) (socket_base::receive_buffer_size) (socket_base::receive_low_watermark) (socket_base::reuse_address, socket_base::send_buffer_size) (socket_base::send_low_watermark): Add using-declaration for __socket_crtp::operator=(_Tp). * testsuite/experimental/net/socket/socket_base.cc: Check properties of socket option types.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/include/experimental/bits/net.h35
-rw-r--r--libstdc++-v3/include/experimental/socket66
-rw-r--r--libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc148
3 files changed, 228 insertions, 21 deletions
diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h
index 0ac9ca7..3087f89 100644
--- a/libstdc++-v3/include/experimental/bits/net.h
+++ b/libstdc++-v3/include/experimental/bits/net.h
@@ -95,15 +95,20 @@ inline namespace v1
/// @endcond
- // Base class for types meeting IntegerSocketOption requirements.
- template<typename _Tp>
+ // Base class for types meeting both GettableSocketOption and
+ // SettableSocketOption requirements.
+ // The bool parameter allows __sockopt_base<bool> to have a
+ // __sockopt_base<int, B> base class (so that its _M_value is an int)
+ // but to have that be a distinct type from __sockopt_base<int>.
+ template<typename _Tp, bool = true>
struct __sockopt_base
{
__sockopt_base() = default;
- explicit __sockopt_base(int __val) : _M_value(__val) { }
-
- int value() const noexcept { return _M_value; }
+ explicit
+ __sockopt_base(_Tp __val) noexcept(noexcept(_Tp(std::declval<_Tp&>())))
+ : _M_value(__val)
+ { }
template<typename _Protocol>
void*
@@ -134,24 +139,36 @@ inline namespace v1
// Base class for types meeting BooleanSocketOption requirements.
template<>
- struct __sockopt_base<bool> : __sockopt_base<int>
+ struct __sockopt_base<bool> : __sockopt_base<int, false>
{
__sockopt_base() = default;
- explicit __sockopt_base(bool __val) : __sockopt_base<int>(__val) { }
+ explicit
+ __sockopt_base(bool __val) noexcept
+ : __sockopt_base<int, false>(__val)
+ { }
- bool value() const noexcept { return __sockopt_base<int>::_M_value; }
+ bool value() const noexcept { return this->_M_value; }
explicit operator bool() const noexcept { return value(); }
bool operator!() const noexcept { return !value(); }
};
+ // Base class for types meeting IntegerSocketOption requirements.
+ template<>
+ struct __sockopt_base<int> : __sockopt_base<int, false>
+ {
+ using __sockopt_base<int, false>::__sockopt_base;
+
+ int value() const noexcept { return this->_M_value; }
+ };
+
template<typename _Derived, typename _Tp = int>
struct __sockopt_crtp : __sockopt_base<_Tp>
{
using __sockopt_base<_Tp>::__sockopt_base;
_Derived&
- operator=(_Tp __value)
+ operator=(_Tp __value) noexcept(noexcept(__value = __value))
{
__sockopt_base<_Tp>::_M_value = __value;
return static_cast<_Derived&>(*this);
diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket
index 09c3b72..538dc78 100644
--- a/libstdc++-v3/include/experimental/socket
+++ b/libstdc++-v3/include/experimental/socket
@@ -138,41 +138,59 @@ inline namespace v1
{
public:
#ifdef _GLIBCXX_HAVE_SYS_SOCKET_H
- struct broadcast : __sockopt_crtp<broadcast, bool>
+ class broadcast : public __sockopt_crtp<broadcast, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<broadcast, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_BROADCAST;
};
- struct debug : __sockopt_crtp<debug, bool>
+ class debug : public __sockopt_crtp<debug, bool>
{
+ public:
+ friend __sockopt_crtp<debug, bool>;
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_DEBUG;
};
- struct do_not_route : __sockopt_crtp<do_not_route, bool>
+ class do_not_route : public __sockopt_crtp<do_not_route, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<do_not_route, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_DONTROUTE;
};
- struct keep_alive : __sockopt_crtp<keep_alive, bool>
+ class keep_alive : public __sockopt_crtp<keep_alive, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<keep_alive, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_KEEPALIVE;
};
- struct linger : __sockopt_crtp<linger, ::linger>
+ class linger : public __sockopt_crtp<linger, ::linger>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
linger() noexcept = default;
@@ -198,54 +216,80 @@ inline namespace v1
timeout(chrono::seconds __t) noexcept
{ _M_value.l_linger = __t.count(); }
+ private:
+ friend __sockopt_crtp<linger, ::linger>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_LINGER;
};
- struct out_of_band_inline : __sockopt_crtp<out_of_band_inline, bool>
+ class out_of_band_inline : public __sockopt_crtp<out_of_band_inline, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<out_of_band_inline, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_OOBINLINE;
};
- struct receive_buffer_size : __sockopt_crtp<receive_buffer_size>
+ class receive_buffer_size : public __sockopt_crtp<receive_buffer_size>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<receive_buffer_size>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_RCVBUF;
};
- struct receive_low_watermark : __sockopt_crtp<receive_low_watermark>
+ class receive_low_watermark : public __sockopt_crtp<receive_low_watermark>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<receive_low_watermark>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_RCVLOWAT;
};
- struct reuse_address : __sockopt_crtp<reuse_address, bool>
+ class reuse_address : public __sockopt_crtp<reuse_address, bool>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<reuse_address, bool>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_REUSEADDR;
};
- struct send_buffer_size : __sockopt_crtp<send_buffer_size>
+ class send_buffer_size : public __sockopt_crtp<send_buffer_size>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<send_buffer_size>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_SNDBUF;
};
- struct send_low_watermark : __sockopt_crtp<send_low_watermark>
+ class send_low_watermark : public __sockopt_crtp<send_low_watermark>
{
+ public:
using __sockopt_crtp::__sockopt_crtp;
+ using __sockopt_crtp::operator=;
+ private:
+ friend __sockopt_crtp<send_low_watermark>;
static const int _S_level = SOL_SOCKET;
static const int _S_name = SO_SNDLOWAT;
};
diff --git a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
index b0b02b4..95cd815 100644
--- a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
+++ b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc
@@ -15,14 +15,156 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-do compile { target c++14 } }
+// { dg-do run { target c++14 } }
#include <experimental/socket>
#include <testsuite_common_types.h>
+#include <testsuite_hooks.h>
using S = std::experimental::net::socket_base;
using namespace std;
+// Dummy protocol
+struct P
+{
+ struct endpoint
+ {
+ using protocol_type = P;
+ P protocol() const;
+ };
+};
+
+static_assert( ! is_default_constructible<S>(), "" );
+static_assert( ! is_destructible<S>(), "" );
+
+template<typename C, typename T>
+void check_gettable_sockopt()
+{
+ P p;
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().data(p)), void*>(), "" );
+ static_assert( noexcept(declval<C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<const C&>().size(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().resize(p, 0)), void>(), "" );
+ static_assert( ! noexcept(declval<C&>().resize(p, 0)), "" );
+
+ C opt;
+ VERIFY(opt.size(p) == sizeof(T));
+}
+
+template<typename C, typename T>
+void check_settable_sockopt()
+{
+ P p;
+ static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().level(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
+ static_assert( noexcept(declval<const C&>().name(p)), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().data(p)), const void*>(), "" );
+ static_assert( noexcept(declval<const C&>().data(p)), "" );
+
+ static_assert( is_same<decltype(declval<C&>().size(p)), size_t>(), "" );
+ static_assert( noexcept(declval<C&>().size(p)), "" );
+
+ C opt;
+ VERIFY(opt.size(p) == sizeof(T));
+}
+
+template<typename C, typename T = int>
+void check_boolean_sockopt()
+{
+ check_gettable_sockopt<C, T>();
+ check_settable_sockopt<C, T>();
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, bool>(), "" );
+ static_assert( is_nothrow_assignable<C&, bool>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), bool>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+
+ static_assert( is_same<decltype(static_cast<bool>(declval<const C&>())), bool>(), "" );
+ static_assert( noexcept(static_cast<bool>(declval<const C&>())), "" );
+
+ static_assert( is_same<decltype(!declval<const C&>()), bool>(), "" );
+ static_assert( noexcept(!declval<const C&>()), "" );
+}
+
+template<typename C, typename T = int>
+void check_integer_sockopt()
+{
+ check_gettable_sockopt<C, T>();
+ check_settable_sockopt<C, T>();
+
+ static_assert( is_destructible<C>(), "" );
+ static_assert( is_nothrow_default_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_constructible<C>(), "" );
+ static_assert( is_nothrow_copy_assignable<C>(), "" );
+
+ static_assert( is_nothrow_constructible<C, int>(), "" );
+ static_assert( is_nothrow_assignable<C&, int>(), "" );
+
+ static_assert( is_same<decltype(declval<const C&>().value()), int>(), "" );
+ static_assert( noexcept(declval<const C&>().value()), "" );
+}
+
+void test_option_types()
+{
+ check_boolean_sockopt<S::broadcast>();
+
+ check_boolean_sockopt<S::debug>();
+
+ check_boolean_sockopt<S::do_not_route>();
+
+ check_boolean_sockopt<S::keep_alive>();
+
+ check_gettable_sockopt<S::linger, ::linger>();
+ check_settable_sockopt<S::linger, ::linger>();
+ static_assert( is_destructible<S::linger>(), "" );
+ static_assert( is_nothrow_default_constructible<S::linger>(), "" );
+ static_assert( is_nothrow_copy_constructible<S::linger>(), "" );
+ static_assert( is_nothrow_copy_assignable<S::linger>(), "" );
+ static_assert( is_nothrow_constructible<S::linger, bool, chrono::seconds>(), "" );
+
+ static_assert( is_same<decltype(declval<const S::linger&>().enabled()), bool>(), "" );
+ static_assert( noexcept(declval<const S::linger&>().enabled()), "" );
+
+ static_assert( is_void<decltype(declval<S::linger&>().enabled(true))>(), "" );
+ static_assert( noexcept(declval<S::linger&>().enabled(true)), "" );
+
+ static_assert( is_same<decltype(declval<const S::linger&>().timeout()), chrono::seconds>(), "" );
+ static_assert( noexcept(declval<const S::linger&>().timeout()), "" );
+
+ static_assert( is_void<decltype(declval<S::linger&>().timeout(chrono::seconds()))>(), "" );
+ static_assert( noexcept(declval<S::linger&>().timeout(chrono::seconds())), "" );
+
+ check_boolean_sockopt<S::out_of_band_inline>();
+
+ check_integer_sockopt<S::receive_buffer_size>();
+
+ check_integer_sockopt<S::receive_low_watermark>();
+
+ check_boolean_sockopt<S::reuse_address>();
+
+ check_integer_sockopt<S::send_buffer_size>();
+
+ check_integer_sockopt<S::send_low_watermark>();
+}
+
void test_constants()
{
static_assert( is_enum<S::shutdown_type>::value, "" );
@@ -43,3 +185,7 @@ void test_constants()
static_assert( is_same<decltype(m), const int*>::value, "" );
}
+int main()
+{
+ test_option_types();
+}