From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id F18AE3857C4F; Tue, 24 Aug 2021 16:00:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F18AE3857C4F MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r11-8910] libstdc++: Fix socket option classes X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-11 X-Git-Oldrev: edcf1b0de47e503fd7afe7095bfdffbe9475f13f X-Git-Newrev: 91e84187e4ddac74135f1540065c25816cad044c Message-Id: <20210824160031.F18AE3857C4F@sourceware.org> Date: Tue, 24 Aug 2021 16:00:31 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Aug 2021 16:00:32 -0000 https://gcc.gnu.org/g:91e84187e4ddac74135f1540065c25816cad044c commit r11-8910-g91e84187e4ddac74135f1540065c25816cad044c Author: Jonathan Wakely Date: Mon Apr 26 21:16:21 2021 +0100 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::value() member function was present unconditionally (so was defined for socket_base::linger which is incorrect). - The __socket_crtp::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 base classes. (__socket_base): Adjust base class. (__socket_base): 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. (cherry picked from commit 06c86a4f210c76a157512a2963e6c31302d161cb) Diff: --- libstdc++-v3/include/experimental/bits/net.h | 35 +++-- libstdc++-v3/include/experimental/socket | 66 +++++++-- .../experimental/net/socket/socket_base.cc | 148 ++++++++++++++++++++- 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 0ac9ca7ddc6..3087f8957da 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 + // Base class for types meeting both GettableSocketOption and + // SettableSocketOption requirements. + // The bool parameter allows __sockopt_base to have a + // __sockopt_base base class (so that its _M_value is an int) + // but to have that be a distinct type from __sockopt_base. + template 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 void* @@ -134,24 +139,36 @@ inline namespace v1 // Base class for types meeting BooleanSocketOption requirements. template<> - struct __sockopt_base : __sockopt_base + struct __sockopt_base : __sockopt_base { __sockopt_base() = default; - explicit __sockopt_base(bool __val) : __sockopt_base(__val) { } + explicit + __sockopt_base(bool __val) noexcept + : __sockopt_base(__val) + { } - bool value() const noexcept { return __sockopt_base::_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 : __sockopt_base + { + using __sockopt_base::__sockopt_base; + + int value() const noexcept { return this->_M_value; } + }; + template 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 09c3b729607..538dc78e72c 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 + class broadcast : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_BROADCAST; }; - struct debug : __sockopt_crtp + class debug : public __sockopt_crtp { + public: + friend __sockopt_crtp; 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 + class do_not_route : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_DONTROUTE; }; - struct keep_alive : __sockopt_crtp + class keep_alive : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_KEEPALIVE; }; - struct linger : __sockopt_crtp + class linger : public __sockopt_crtp { + 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; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_LINGER; }; - struct out_of_band_inline : __sockopt_crtp + class out_of_band_inline : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_OOBINLINE; }; - struct receive_buffer_size : __sockopt_crtp + class receive_buffer_size : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_RCVBUF; }; - struct receive_low_watermark : __sockopt_crtp + class receive_low_watermark : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_RCVLOWAT; }; - struct reuse_address : __sockopt_crtp + class reuse_address : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_REUSEADDR; }; - struct send_buffer_size : __sockopt_crtp + class send_buffer_size : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_SNDBUF; }; - struct send_low_watermark : __sockopt_crtp + class send_low_watermark : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; 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 b0b02b4e560..95cd8151840 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 // . -// { dg-do compile { target c++14 } } +// { dg-do run { target c++14 } } #include #include +#include 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(), "" ); +static_assert( ! is_destructible(), "" ); + +template +void check_gettable_sockopt() +{ + P p; + static_assert( is_same().level(p)), int>(), "" ); + static_assert( noexcept(declval().level(p)), "" ); + + static_assert( is_same().name(p)), int>(), "" ); + static_assert( noexcept(declval().name(p)), "" ); + + static_assert( is_same().data(p)), void*>(), "" ); + static_assert( noexcept(declval().data(p)), "" ); + + static_assert( is_same().size(p)), size_t>(), "" ); + static_assert( noexcept(declval().size(p)), "" ); + + static_assert( is_same().resize(p, 0)), void>(), "" ); + static_assert( ! noexcept(declval().resize(p, 0)), "" ); + + C opt; + VERIFY(opt.size(p) == sizeof(T)); +} + +template +void check_settable_sockopt() +{ + P p; + static_assert( is_same().level(p)), int>(), "" ); + static_assert( noexcept(declval().level(p)), "" ); + + static_assert( is_same().name(p)), int>(), "" ); + static_assert( noexcept(declval().name(p)), "" ); + + static_assert( is_same().data(p)), const void*>(), "" ); + static_assert( noexcept(declval().data(p)), "" ); + + static_assert( is_same().size(p)), size_t>(), "" ); + static_assert( noexcept(declval().size(p)), "" ); + + C opt; + VERIFY(opt.size(p) == sizeof(T)); +} + +template +void check_boolean_sockopt() +{ + check_gettable_sockopt(); + check_settable_sockopt(); + + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + + static_assert( is_nothrow_constructible(), "" ); + static_assert( is_nothrow_assignable(), "" ); + + static_assert( is_same().value()), bool>(), "" ); + static_assert( noexcept(declval().value()), "" ); + + static_assert( is_same(declval())), bool>(), "" ); + static_assert( noexcept(static_cast(declval())), "" ); + + static_assert( is_same()), bool>(), "" ); + static_assert( noexcept(!declval()), "" ); +} + +template +void check_integer_sockopt() +{ + check_gettable_sockopt(); + check_settable_sockopt(); + + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + + static_assert( is_nothrow_constructible(), "" ); + static_assert( is_nothrow_assignable(), "" ); + + static_assert( is_same().value()), int>(), "" ); + static_assert( noexcept(declval().value()), "" ); +} + +void test_option_types() +{ + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_gettable_sockopt(); + check_settable_sockopt(); + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + static_assert( is_nothrow_constructible(), "" ); + + static_assert( is_same().enabled()), bool>(), "" ); + static_assert( noexcept(declval().enabled()), "" ); + + static_assert( is_void().enabled(true))>(), "" ); + static_assert( noexcept(declval().enabled(true)), "" ); + + static_assert( is_same().timeout()), chrono::seconds>(), "" ); + static_assert( noexcept(declval().timeout()), "" ); + + static_assert( is_void().timeout(chrono::seconds()))>(), "" ); + static_assert( noexcept(declval().timeout(chrono::seconds())), "" ); + + check_boolean_sockopt(); + + check_integer_sockopt(); + + check_integer_sockopt(); + + check_boolean_sockopt(); + + check_integer_sockopt(); + + check_integer_sockopt(); +} + void test_constants() { static_assert( is_enum::value, "" ); @@ -43,3 +185,7 @@ void test_constants() static_assert( is_same::value, "" ); } +int main() +{ + test_option_types(); +}