diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index 3fd200251fa..5336b8a8ce3 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -1219,10 +1219,10 @@ namespace ip
 
   /// @}
 
-  bool
+  constexpr bool
   operator==(const network_v4& __a, const network_v4& __b) noexcept;
 
-  bool
+  constexpr bool
   operator==(const network_v6& __a, const network_v6& __b) noexcept;
 
 
@@ -1263,10 +1263,10 @@ namespace ip
     constexpr address_v4
     netmask() const noexcept
     {
-      address_v4::uint_type __val = address_v4::broadcast().to_uint();
-      __val >>= (32 - _M_prefix_len);
-      __val <<= (32 - _M_prefix_len);
-      return address_v4{__val};
+      address_v4 __m;
+      if (_M_prefix_len)
+	__m = address_v4(0xFFFFFFFFu << (32 - _M_prefix_len));
+      return __m;
     }
 
     constexpr address_v4
@@ -1275,7 +1275,7 @@ namespace ip
 
     constexpr address_v4
     broadcast() const noexcept
-    { return address_v4{_M_addr.to_uint() | ~netmask().to_uint()}; }
+    { return address_v4{_M_addr.to_uint() | (0xFFFFFFFFu >> _M_prefix_len)}; }
 
     address_v4_range
     hosts() const noexcept
@@ -1306,8 +1306,23 @@ namespace ip
       __string_with<_Allocator>
       to_string(const _Allocator& __a = _Allocator()) const
       {
-	return address().to_string(__a) + '/'
-	  + std::to_string(prefix_length());
+	auto __str = address().to_string(__a);
+	const unsigned __addrlen = __str.length();
+	const unsigned __preflen = prefix_length() >= 10 ? 2 : 1;
+	auto __write = [=](char* __p, size_t __n) {
+	  __p[__addrlen] = '/';
+	  std::__detail::__to_chars_10_impl(__p + __addrlen + 1, __preflen,
+					    (unsigned char)prefix_length());
+	  return __n;
+	};
+	const unsigned __len = __addrlen + 1 + __preflen;
+#if __cpp_lib_string_resize_and_overwrite
+	__str.resize_and_overwrite(__len, __write);
+#else
+	__str.resize(__len);
+	__write(&__str.front(), __len);
+#endif
+	return __str;
       }
 
   private:
@@ -1379,14 +1394,14 @@ namespace ip
    * @{
    */
 
-  inline bool
+  constexpr bool
   operator==(const network_v4& __a, const network_v4& __b) noexcept
   {
     return __a.address() == __b.address()
       && __a.prefix_length() == __b.prefix_length();
   }
 
-  inline bool
+  constexpr bool
   operator!=(const network_v4& __a, const network_v4& __b) noexcept
   { return !(__a == __b); }
 
@@ -1396,14 +1411,14 @@ namespace ip
    * @{
    */
 
-  inline bool
+  constexpr bool
   operator==(const network_v6& __a, const network_v6& __b) noexcept
   {
     return __a.address() == __b.address()
       && __a.prefix_length() == __b.prefix_length();
   }
 
-  inline bool
+  constexpr bool
   operator!=(const network_v6& __a, const network_v6& __b) noexcept
   { return !(__a == __b); }
 
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc
new file mode 100644
index 00000000000..7784b6f6f58
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc
@@ -0,0 +1,129 @@
+// { dg-do run { target c++14 } }
+// { dg-require-effective-target net_ts_ip }
+// { dg-add-options net_ts }
+
+#include <experimental/internet>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+using std::experimental::net::ip::network_v4;
+using std::experimental::net::ip::address_v4;
+
+constexpr void
+test01()
+{
+  network_v4 n0;
+  VERIFY( n0.address().is_unspecified() );
+  VERIFY( n0.prefix_length() == 0 );
+}
+
+constexpr void
+test02()
+{
+  address_v4 a0;
+  network_v4 n0{ a0, 0 };
+  VERIFY( n0.address() == a0 );
+  VERIFY( n0.prefix_length() == 0 );
+
+  address_v4 a1{ address_v4::bytes_type{ 1, 2, 3, 4 } };
+  network_v4 n1{ a1, 12};
+  VERIFY( n1.address() == a1 );
+  VERIFY( n1.prefix_length() == 12 );
+}
+
+void
+test02_errors()
+{
+  address_v4 a0;
+  try
+  {
+    network_v4{a0, -1};
+    VERIFY(false);
+  }
+  catch(const std::out_of_range&)
+  {
+  }
+
+  try
+  {
+    network_v4{a0, 33};
+    VERIFY(false);
+  }
+  catch(const std::out_of_range&)
+  {
+  }
+}
+
+constexpr void
+test03()
+{
+  address_v4 a0;
+  network_v4 n0{ a0, a0 };
+  VERIFY( n0.address() == a0 );
+  VERIFY( n0.prefix_length() == 0 );
+
+  address_v4 a1{ address_v4::bytes_type{ 1, 2, 3, 4 } };
+  network_v4 n1{ a1, address_v4::broadcast() };
+  VERIFY( n1.address() == a1 );
+  VERIFY( n1.prefix_length() == 32 );
+
+  network_v4 n2{ a1, address_v4::bytes_type(128, 0, 0, 0) };
+  VERIFY( n2.address() == a1 );
+  VERIFY( n2.prefix_length() == 1 );
+
+  network_v4 n3{ a1, address_v4::bytes_type(255, 255, 255, 192) };
+  VERIFY( n3.address() == a1 );
+  VERIFY( n3.prefix_length() == 26 );
+}
+
+void
+test03_errors()
+{
+  address_v4 a0;
+  try
+  {
+    // Contains non-contiguous non-zero bits.
+    network_v4{a0, address_v4::bytes_type(255, 1, 0, 0)};
+    VERIFY(false);
+  }
+  catch(const std::invalid_argument&)
+  {
+  }
+
+  try
+  {
+    // Most significant bit is zero and any other bits are non-zero.
+    network_v4{a0, address_v4::bytes_type(1, 0, 0, 0)};
+    VERIFY(false);
+  }
+  catch(const std::invalid_argument&)
+  {
+  }
+
+  try
+  {
+    // Most significant bit is zero and any other bits are non-zero.
+    network_v4{a0, address_v4::bytes_type(0, 1, 0, 0)};
+    VERIFY(false);
+  }
+  catch(const std::invalid_argument&)
+  {
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test02_errors();
+  test03();
+  test03_errors();
+
+  constexpr bool c = []{
+    test01();
+    test02();
+    test03();
+    return true;
+  };
+}
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc
new file mode 100644
index 00000000000..3ea65862649
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc
@@ -0,0 +1,186 @@
+// { dg-do run { target c++14 } }
+// { dg-require-effective-target net_ts_ip }
+// { dg-add-options net_ts }
+
+#include <experimental/internet>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using std::experimental::net::ip::network_v4;
+using std::experimental::net::ip::address_v4;
+
+constexpr void
+test_netmask()
+{
+  network_v4 n0;
+  VERIFY( n0.netmask() == address_v4() );
+
+  network_v4 n1({}, 1);
+  VERIFY( n1.netmask() == address_v4(address_v4::bytes_type(128)) );
+
+  network_v4 n2({}, 2);
+  VERIFY( n2.netmask() == address_v4(address_v4::bytes_type(192)) );
+
+  network_v4 n3({}, 3);
+  VERIFY( n3.netmask() == address_v4(address_v4::bytes_type(224)) );
+
+  network_v4 n4({}, 17);
+  VERIFY( n4.netmask() == address_v4(address_v4::bytes_type(255, 255, 128)) );
+}
+
+constexpr void
+test_network()
+{
+  network_v4 n0;
+  VERIFY( n0.network() == address_v4() );
+
+  network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1);
+  VERIFY( n1.network() == address_v4(address_v4::bytes_type(0, 0, 0, 0)) );
+
+  network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8);
+  VERIFY( n2.network() == address_v4(address_v4::bytes_type(1, 0, 0, 0)) );
+
+  network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 15);
+  VERIFY( n3.network() == address_v4(address_v4::bytes_type(1, 2, 0, 0)) );
+
+  network_v4 n4(address_v4::bytes_type{1, 2, 3, 4}, 16);
+  VERIFY( n4.network() == address_v4(address_v4::bytes_type(1, 2, 0, 0)) );
+
+  network_v4 n5(address_v4::bytes_type{1, 2, 3, 4}, 23);
+  VERIFY( n5.network() == address_v4(address_v4::bytes_type(1, 2, 2, 0)) );
+
+  network_v4 n6(address_v4::bytes_type{1, 2, 3, 4}, 24);
+  VERIFY( n6.network() == address_v4(address_v4::bytes_type(1, 2, 3, 0)) );
+
+  network_v4 n7(address_v4::bytes_type{1, 2, 3, 4}, 29);
+  VERIFY( n7.network() == address_v4(address_v4::bytes_type(1, 2, 3, 0)) );
+
+  network_v4 n8(address_v4::bytes_type{1, 2, 3, 4}, 30);
+  VERIFY( n8.network() == address_v4(address_v4::bytes_type(1, 2, 3, 4)) );
+
+  network_v4 n9(address_v4::bytes_type{1, 2, 3, 4}, 32);
+  VERIFY( n9.network() == address_v4(address_v4::bytes_type(1, 2, 3, 4)) );
+}
+
+constexpr void
+test_broadcast()
+{
+  using b = address_v4::bytes_type;
+
+  network_v4 n0;
+  VERIFY( n0.broadcast() == address_v4::broadcast() );
+
+  network_v4 n1(b{1, 2, 3, 4}, 1);
+  VERIFY( n1.broadcast() == address_v4(b(127, 255, 255, 255)) );
+
+  network_v4 n2(b{1, 2, 3, 4}, 8);
+  VERIFY( n2.broadcast() == address_v4(b(1, 255, 255, 255)) );
+
+  network_v4 n3(b{1, 2, 3, 4}, 15);
+  VERIFY( n3.broadcast() == address_v4(b(1, 3, 255, 255)) );
+
+  network_v4 n4(b{1, 2, 3, 4}, 16);
+  VERIFY( n4.broadcast() == address_v4(b(1, 2, 255, 255)) );
+
+  network_v4 n5(b{1, 2, 3, 4}, 23);
+  VERIFY( n5.broadcast() == address_v4(b(1, 2, 3, 255)) );
+
+  network_v4 n6(b{1, 2, 3, 4}, 24);
+  VERIFY( n6.broadcast() == address_v4(b(1, 2, 3, 255)) );
+
+  network_v4 n7(b{1, 2, 3, 4}, 29);
+  VERIFY( n7.broadcast() == address_v4(b(1, 2, 3, 7)) );
+
+  network_v4 n8(b{1, 2, 3, 4}, 30);
+  VERIFY( n8.broadcast() == address_v4(b(1, 2, 3, 7)) );
+
+  network_v4 n9(b{1, 2, 3, 4}, 31);
+  VERIFY( n9.broadcast() == address_v4(b(1, 2, 3, 5)) );
+
+  network_v4 n10(b{1, 2, 3, 4}, 32);
+  VERIFY( n10.broadcast() == address_v4(b(1, 2, 3, 4)) );
+}
+
+constexpr void
+test_canonical()
+{
+  network_v4 n0;
+  VERIFY( n0.canonical() == network_v4(n0.network(), n0.prefix_length()) );
+
+  network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1);
+  VERIFY( n1.canonical() == network_v4(n1.network(), n1.prefix_length()) );
+
+  network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8);
+  VERIFY( n2.canonical() == network_v4(n2.network(), n2.prefix_length()) );
+
+  network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 15);
+  VERIFY( n3.canonical() == network_v4(n3.network(), n3.prefix_length()) );
+
+  network_v4 n4(address_v4::bytes_type{1, 2, 3, 4}, 16);
+  VERIFY( n4.canonical() == network_v4(n4.network(), n4.prefix_length()) );
+
+  network_v4 n5(address_v4::bytes_type{1, 2, 3, 4}, 23);
+  VERIFY( n5.canonical() == network_v4(n5.network(), n5.prefix_length()) );
+
+  network_v4 n6(address_v4::bytes_type{1, 2, 3, 4}, 24);
+  VERIFY( n6.canonical() == network_v4(n6.network(), n6.prefix_length()) );
+
+  network_v4 n7(address_v4::bytes_type{1, 2, 3, 4}, 29);
+  VERIFY( n7.canonical() == network_v4(n7.network(), n7.prefix_length()) );
+
+  network_v4 n8(address_v4::bytes_type{1, 2, 3, 4}, 30);
+  VERIFY( n8.canonical() == network_v4(n8.network(), n8.prefix_length()) );
+
+  network_v4 n9(address_v4::bytes_type{1, 2, 3, 4}, 32);
+  VERIFY( n9.canonical() == network_v4(n9.network(), n9.prefix_length()) );
+}
+
+constexpr void
+test_is_host()
+{
+  network_v4 n0;
+  VERIFY( ! n0.is_host() );
+
+  network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1);
+  VERIFY( ! n1.is_host() );
+
+  network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8);
+  VERIFY( ! n2.is_host() );
+
+  network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 32);
+  VERIFY( n3.is_host() );
+}
+
+void
+test_to_string()
+{
+  using b = address_v4::bytes_type;
+  __gnu_test::uneq_allocator<char> alloc(123);
+  auto str = network_v4(address_v4(b(12, 34, 56, 78)), 24).to_string(alloc);
+  VERIFY(str.get_allocator().get_personality() == alloc.get_personality());
+  VERIFY( str == "12.34.56.78/24" );
+
+  __gnu_test::uneq_allocator<char> alloc2(99);
+  auto str2 = network_v4(address_v4(b(87, 65, 43, 21)), 4).to_string(alloc2);
+  VERIFY(str2.get_allocator().get_personality() == alloc2.get_personality());
+  VERIFY( str2 == "87.65.43.21/4" );
+}
+
+int main()
+{
+  test_netmask();
+  test_network();
+  test_broadcast();
+  test_canonical();
+  test_is_host();
+  test_to_string();
+
+  constexpr bool c = []{
+    test_netmask();
+    test_network();
+    test_broadcast();
+    test_canonical();
+    test_is_host();
+    return true;
+  };
+}
