From: Jonathan Wakely Date: Wed, 12 Apr 2023 10:55:24 +0000 (+0100) Subject: libstdc++: Initialize all members of basic_endpoint union [PR109482] X-Git-Tag: basepoints/gcc-14~58 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f10b4957ca6058d1a801c5e4bfe11bf159da809;p=thirdparty%2Fgcc.git libstdc++: Initialize all members of basic_endpoint union [PR109482] On Solaris the in_addr struct contains a union and value-initializing it does not make the s_addr member active. This means we can't access that member later during constant evaluation. Make the constructors explicitly set every member that we might want to read later in constexpr member functions. This means even the default constructor can only be constexpr for C++20, because we can't change the active member of a union in older standards. libstdc++-v3/ChangeLog: PR libstdc++/109482 * include/experimental/internet (basic_endpoint::basic_endpoint()): Ensure that the required union members are active. Only define as constexpr for C++20 and later. (basic_endpoint::basic_endpoint(const protocol_type&, port_type)): Likewise. * testsuite/experimental/net/internet/endpoint/cons.cc: Only check constexpr default constructor for C++20 and later. * testsuite/experimental/net/internet/endpoint/extensible.cc: Likewise. --- diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet index eb23ae21cdc1..1f63c61ce85a 100644 --- a/libstdc++-v3/include/experimental/internet +++ b/libstdc++-v3/include/experimental/internet @@ -1512,9 +1512,14 @@ namespace ip // constructors: - constexpr + _GLIBCXX20_CONSTEXPR basic_endpoint() noexcept : _M_data() - { _M_data._M_v4.sin_family = protocol_type::v4().family(); } + { + _M_data._M_v4.sin_family = protocol_type::v4().family(); + // If in_addr contains a union, make the correct member active: + if (std::__is_constant_evaluated()) + std::_Construct(&_M_data._M_v4.sin_addr.s_addr); + } _GLIBCXX20_CONSTEXPR basic_endpoint(const protocol_type& __proto, @@ -1523,19 +1528,25 @@ namespace ip { if (__proto == protocol_type::v4()) { - _M_data._M_v4.sin_family = __proto.family(); + _M_data._M_v4.sin_family = protocol_type::v4().family(); _M_data._M_v4.sin_port = address_v4::_S_hton_16(__port_num); + if (std::__is_constant_evaluated()) + std::_Construct(&_M_data._M_v4.sin_addr.s_addr); } else if (__proto == protocol_type::v6()) { std::_Construct(&_M_data._M_v6); _M_data._M_v6.sin6_family = __proto.family(); _M_data._M_v6.sin6_port = address_v4::_S_hton_16(__port_num); + _M_data._M_v6.sin6_scope_id = 0; + if (std::__is_constant_evaluated()) + std::_Construct(&_M_data._M_v6.sin6_addr.s6_addr); } else { __glibcxx_assert(__proto == protocol_type::v4() || __proto == protocol_type::v6()); + } } @@ -1548,13 +1559,16 @@ namespace ip { _M_data._M_v4.sin_family = protocol_type::v4().family(); _M_data._M_v4.sin_port = address_v4::_S_hton_16(__port_num); - _M_data._M_v4.sin_addr.s_addr = __addr._M_v4._M_addr; + std::_Construct(&_M_data._M_v4.sin_addr.s_addr, + __addr._M_v4._M_addr); } else { std::_Construct(&_M_data._M_v6); _M_data._M_v6.sin6_family = protocol_type::v6().family(); _M_data._M_v6.sin6_port = address_v4::_S_hton_16(__port_num); + if (std::__is_constant_evaluated()) + std::_Construct(&_M_data._M_v6.sin6_addr.s6_addr); uint8_t* __s6a = _M_data._M_v6.sin6_addr.s6_addr; for (int __i = 0; __i < 16; ++__i) __s6a[__i] = __addr._M_v6._M_bytes[__i]; diff --git a/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc index b4bef88b4a3d..d54b0c9550b5 100644 --- a/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc +++ b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc @@ -7,7 +7,10 @@ using namespace std::experimental::net; -constexpr void +#if __cplusplus >= 202002 +constexpr +#endif +void test_default() { ip::tcp::endpoint t1; @@ -57,23 +60,19 @@ test_addr() VERIFY( t2.port() == 80 ); } -constexpr bool -test_constexpr() -{ - test_default(); -#if __cplusplus >= 202002 - // Non-default basic_endpoint constructors are only constexpr in C++20. - test_proto(); - test_addr(); -#endif - return true; -} - int main() { test_default(); test_proto(); test_addr(); - static_assert( test_constexpr(), "valid in constant expressions" ); +#if __cplusplus >= 202002 + // basic_endpoint constructors are only constexpr in C++20. + constexpr bool b = []{ + test_default(); + test_proto(); + test_addr(); + return true; + }(); +#endif } diff --git a/libstdc++-v3/testsuite/experimental/net/internet/endpoint/extensible.cc b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/extensible.cc index d205024c799e..ffc43cf17b6a 100644 --- a/libstdc++-v3/testsuite/experimental/net/internet/endpoint/extensible.cc +++ b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/extensible.cc @@ -11,8 +11,12 @@ using namespace std::experimental::net; void test_extensible() { +#if __cplusplus >= 202002L static_assert(ip::tcp::endpoint().capacity() == sizeof(sockaddr_in6), "ip::tcp::endpoint::capacity() can store a sockaddr_in6"); +#else + VERIFY( ip::tcp::endpoint().capacity() == sizeof(sockaddr_in6) ); +#endif ip::tcp::endpoint t1(ip::tcp::v4(), 22); VERIFY(t1.size() == sizeof(sockaddr_in));