[committed] libstdc++: Initialize all members of basic_endpoint union [PR109482]
Checks
Commit Message
Tested x86_64-linux and sparc-solaris2.11. Pushed to trunk.
-- >8 --
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.
---
libstdc++-v3/include/experimental/internet | 22 ++++++++++++---
.../net/internet/endpoint/cons.cc | 27 +++++++++----------
.../net/internet/endpoint/extensible.cc | 4 +++
3 files changed, 35 insertions(+), 18 deletions(-)
@@ -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];
@@ -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
}
@@ -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));