]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Initialize all members of basic_endpoint union [PR109482]
authorJonathan Wakely <jwakely@redhat.com>
Wed, 12 Apr 2023 10:55:24 +0000 (11:55 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 12 Apr 2023 12:15:12 +0000 (13:15 +0100)
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
libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc
libstdc++-v3/testsuite/experimental/net/internet/endpoint/extensible.cc

index eb23ae21cdc1d6daf5631ea78314d3bde937afe0..1f63c61ce85a891522ec8703e8921b23867deeac 100644 (file)
@@ -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];
index b4bef88b4a3d30206815d878e636baaa90897e4e..d54b0c9550b5c4cd6601c2b7cbd2f00e6e6f0778 100644 (file)
@@ -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
 }
index d205024c799ee7dd91e3ce1a9317dd811ccc5a60..ffc43cf17b6ab07288ff6cdbb159dc278905e870 100644 (file)
@@ -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));