From cbc735d1a60f9ca68b37586946a6e8d8972b4844 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 20 Mar 2025 11:59:43 +0100 Subject: [PATCH 01/18] Add methods to TCP and UDP sockets to modify hop limit --- library/std/src/lib.rs | 1 + library/std/src/net/tcp.rs | 78 +++++++++++++++++++ library/std/src/net/tcp/tests.rs | 17 ++++ library/std/src/net/udp.rs | 76 ++++++++++++++++++ library/std/src/net/udp/tests.rs | 12 +++ library/std/src/sys/net/connection/sgx.rs | 33 ++++++++ .../std/src/sys/net/connection/socket/mod.rs | 36 +++++++++ .../src/sys/net/connection/socket/windows.rs | 9 ++- .../std/src/sys/net/connection/uefi/mod.rs | 32 ++++++++ .../std/src/sys/net/connection/unsupported.rs | 32 ++++++++ library/std/src/sys/net/connection/wasip1.rs | 32 ++++++++ .../sys/net/connection/xous/tcplistener.rs | 8 ++ .../src/sys/net/connection/xous/tcpstream.rs | 8 ++ .../std/src/sys/net/connection/xous/udp.rs | 16 ++++ .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 2 + 16 files changed, 390 insertions(+), 4 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 41b97335cf0f2..c96d644e997e9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -368,6 +368,7 @@ #![feature(maybe_dangling)] #![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_fill)] +#![feature(ipv6_hop_limit)] #![feature(once_lazy_lock_get_unchecked)] #![feature(panic_can_unwind)] #![feature(panic_internals)] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 00f802e5d9155..887a390d7a561 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -605,6 +605,46 @@ impl TcpStream { self.0.ttl() } + // Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// This value sets the unicast hop limit field that is used in every packet + /// sent from this socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:54321") + /// .expect("Couldn't connect to the server..."); + /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0.set_hop_limit_v6(limit) + } + + /// Gets the value of the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// For more information about this option, see [`TcpStream::set_hop_limit_v6`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:54321") + /// .expect("Couldn't connect to the server..."); + /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn hop_limit_v6(&self) -> io::Result { + self.0.hop_limit_v6() + } + /// Gets the value of the `SO_ERROR` option on this socket. /// /// This will retrieve the stored error in the underlying socket, clearing @@ -1032,6 +1072,44 @@ impl TcpListener { self.0.ttl() } + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// This value sets the unicast hop limit field that is used in every packet + /// sent from this socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:54321").unwrap(); + /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0.set_hop_limit_v6(limit) + } + + /// Gets the value of the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// For more information about this option, see [`TcpListener::set_hop_limit_v6`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// assert_eq!(listener.hop_limit_v6().unwrap(), 88); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn hop_limit_v6(&self) -> io::Result { + self.0.hop_limit_v6() + } + #[stable(feature = "net2_mutators", since = "1.9.0")] #[deprecated(since = "1.16.0", note = "this option can only be set before the socket is bound")] #[allow(missing_docs)] diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 45a512cb9b4c7..9b8b28f6cb158 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -894,6 +894,23 @@ fn ttl() { assert_eq!(ttl, t!(stream.ttl())); } +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn hop_limit() { + let hlim = 100; + + let addr = next_test_ip6(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_hop_limit_v6(hlim)); + assert_eq!(hlim, t!(listener.hop_limit_v6())); + + let stream = t!(TcpStream::connect(&addr)); + + t!(stream.set_hop_limit_v6(hlim)); + assert_eq!(hlim, t!(stream.hop_limit_v6())); +} + #[test] #[cfg_attr(target_env = "sgx", ignore)] fn set_nonblocking() { diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 6448c9f2e0091..39dc6a6c833bd 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -589,6 +589,82 @@ impl UdpSocket { self.0.ttl() } + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// This value sets the unicast hop limit field that is used in every packet + /// sent from this socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0.set_hop_limit_v6(limit) + } + + /// Gets the value of the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// For more information about this option, see [`UdpSocket::set_hop_limit_v6`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); + /// assert_eq!(socket.hop_limit_v6().unwrap(), 88); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn hop_limit_v6(&self) -> io::Result { + self.0.hop_limit_v6() + } + + /// Sets the value for the `IPV6_MULTICAST_HOPS` option on this socket. + /// + /// This value sets the hop limit field for outgoing multicast packets + /// sent from this socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0.set_multicast_hop_limit_v6(limit) + } + + /// Gets the value of the `IPV6_MULTICAST_HOPS` option on this socket. + /// + /// For more information about this option, see [`UdpSocket::set_multicast_hop_limit_v6`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(ipv6_hop_limit)] + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); + /// assert_eq!(socket.multicast_hop_limit_v6().unwrap(), 88); + /// ``` + #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + pub fn multicast_hop_limit_v6(&self) -> io::Result { + self.0.multicast_hop_limit_v6() + } + /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. /// /// This function specifies a new multicast group for this socket to join. diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 38d6dab80f64e..84ac9e2cd0c08 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -353,6 +353,18 @@ fn ttl() { assert_eq!(ttl, t!(stream.ttl())); } +#[test] +fn hop_limit() { + let hlim = 100; + + let addr = next_test_ip6(); + + let stream = t!(UdpSocket::bind(&addr)); + + t!(stream.set_hop_limit_v6(hlim)); + assert_eq!(hlim, t!(stream.hop_limit_v6())); +} + #[test] fn set_nonblocking() { each_ip(&mut |socket, _| { diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index acebb8c5bd60c..8771a89568da8 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -9,6 +9,7 @@ use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, u use crate::time::Duration; const DEFAULT_FAKE_TTL: u32 = 64; +const DEFAULT_FAKE_HLIM: u8 = 64; #[derive(Debug, Clone)] pub struct Socket { @@ -243,6 +244,14 @@ impl TcpStream { sgx_ineffective(DEFAULT_FAKE_TTL) } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + sgx_ineffective(()) + } + + pub fn hop_limit_v6(&self) -> io::Result { + sgx_ineffective(DEFAULT_FAKE_HLIM) + } + pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -322,6 +331,14 @@ impl TcpListener { sgx_ineffective(DEFAULT_FAKE_TTL) } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + sgx_ineffective(()) + } + + pub fn hop_limit_v6(&self) -> io::Result { + sgx_ineffective(DEFAULT_FAKE_HLIM) + } + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { sgx_ineffective(()) } @@ -461,6 +478,22 @@ impl UdpSocket { self.0 } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn take_error(&self) -> io::Result> { self.0 } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 4e5de0209ad24..223e26fc062ad 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -506,6 +506,15 @@ impl TcpStream { Ok(raw as u32) } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + } + + pub fn hop_limit_v6(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + Ok(raw as u8) + } + pub fn take_error(&self) -> io::Result> { self.inner.take_error() } @@ -634,6 +643,15 @@ impl TcpListener { Ok(raw as u32) } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + } + + pub fn hop_limit_v6(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + Ok(raw as u8) + } + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) } } @@ -856,6 +874,24 @@ impl UdpSocket { Ok(raw as u32) } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + } + + pub fn hop_limit_v6(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + Ok(raw as u8) + } + + pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)?; + Ok(raw as u8) + } + pub fn take_error(&self) -> io::Result> { self.inner.take_error() } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 8b98d0d31e507..393aba49c69b5 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -29,10 +29,11 @@ pub(super) mod netc { pub use crate::sys::c::{ ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, IPPROTO_IP, IPPROTO_IPV6, - IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, SO_BROADCAST, - SO_RCVTIMEO, SO_SNDTIMEO, SOCK_DGRAM, SOCK_STREAM, SOCKADDR as sockaddr, - SOCKADDR_STORAGE as sockaddr_storage, SOL_SOCKET, WSAEMSGSIZE as EMSGSIZE, bind, connect, - freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_LOOP, + IPV6_UNICAST_HOPS, IPV6_V6ONLY, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO, SOCK_DGRAM, + SOCK_STREAM, SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOL_SOCKET, + WSAEMSGSIZE as EMSGSIZE, bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, + listen, setsockopt, }; #[allow(non_camel_case_types)] diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index b29b324a1ee9e..a377b99892917 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -145,6 +145,14 @@ impl TcpStream { self.inner.ttl() } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn take_error(&self) -> io::Result> { unsupported() } @@ -197,6 +205,14 @@ impl TcpListener { self.inner.ttl() } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { unsupported() } @@ -324,6 +340,22 @@ impl UdpSocket { self.0 } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { + self.0 + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn take_error(&self) -> io::Result> { self.0 } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index 7a4d3a97b8324..df285a4c0987d 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -111,6 +111,14 @@ impl TcpStream { self.0 } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn take_error(&self) -> io::Result> { self.0 } @@ -153,6 +161,14 @@ impl TcpListener { self.0 } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { self.0 } @@ -279,6 +295,22 @@ impl UdpSocket { self.0 } + pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0 + } + + pub fn hop_limit_v6(&self) -> io::Result { + self.0 + } + + pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + self.0 + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + self.0 + } + pub fn take_error(&self) -> io::Result> { self.0 } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index d461ea85f9fea..15d7f9a453141 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -169,6 +169,14 @@ impl TcpStream { unsupported() } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + unsupported() + } + + pub fn hop_limit_v6(&self) -> io::Result { + unsupported() + } + pub fn take_error(&self) -> io::Result> { unsupported() } @@ -253,6 +261,14 @@ impl TcpListener { unsupported() } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + unsupported() + } + + pub fn hop_limit_v6(&self) -> io::Result { + unsupported() + } + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { unsupported() } @@ -425,6 +441,22 @@ impl UdpSocket { unsupported() } + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + unsupported() + } + + pub fn hop_limit_v6(&self) -> io::Result { + unsupported() + } + + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { + unsupported() + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + unsupported() + } + pub fn take_error(&self) -> io::Result> { unsupported() } diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs index f406b4381f29a..e0730b2aac6c8 100644 --- a/library/std/src/sys/net/connection/xous/tcplistener.rs +++ b/library/std/src/sys/net/connection/xous/tcplistener.rs @@ -204,6 +204,14 @@ impl TcpListener { .map(|res| res[0] as _)?) } + pub fn set_hop_limit_v6(&self, hlim: u8) -> io::Result<()> { + unimpl!(); + } + + pub fn hop_limit_v6(&self) -> io::Result { + unimpl!(); + } + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { unimpl!(); } diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 45fe0418a27fa..11cd3f2c008bc 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -403,6 +403,14 @@ impl TcpStream { .map(|res| res[0] as _)?) } + pub fn set_hop_limit_v6(&self, hlim: u8) -> io::Result<()> { + unimpl!(); + } + + pub fn hop_limit_v6(&self) -> io::Result { + unimpl!(); + } + pub fn take_error(&self) -> io::Result> { // this call doesn't have a meaning on our platform, but we can at least not panic if it's used. Ok(None) diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs index 281639488a015..7b01e715d57af 100644 --- a/library/std/src/sys/net/connection/xous/udp.rs +++ b/library/std/src/sys/net/connection/xous/udp.rs @@ -385,6 +385,14 @@ impl UdpSocket { .map(|res| res[0] as _)?) } + pub fn set_hop_limit_v6(&self, hlim: u8) -> io::Result<()> { + unimpl!(); + } + + pub fn hop_limit_v6(&self) -> io::Result { + unimpl!(); + } + pub fn take_error(&self) -> io::Result> { // this call doesn't have a meaning on our platform, but we can at least not panic if it's used. Ok(None) @@ -420,6 +428,14 @@ impl UdpSocket { unimpl!(); } + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { + unimpl!(); + } + + pub fn multicast_hop_limit_v6(&self) -> io::Result { + unimpl!(); + } + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { unimpl!(); } diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index ebe4b8e128352..4586abf1ddbf4 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2257,7 +2257,9 @@ IPPROTO_UDP IPV6_ADD_MEMBERSHIP IPV6_DROP_MEMBERSHIP IPV6_MREQ +IPV6_MULTICAST_HOPS IPV6_MULTICAST_LOOP +IPV6_UNICAST_HOPS IPV6_V6ONLY IsThreadAFiber LINGER diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 34c4407296dcf..a1fa0880abbda 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -2907,7 +2907,9 @@ impl Default for IPV6_MREQ { unsafe { core::mem::zeroed() } } } +pub const IPV6_MULTICAST_HOPS: i32 = 10; pub const IPV6_MULTICAST_LOOP: i32 = 11; +pub const IPV6_UNICAST_HOPS: i32 = 4; pub const IPV6_V6ONLY: i32 = 27; pub const IP_ADD_MEMBERSHIP: i32 = 12; pub const IP_DROP_MEMBERSHIP: i32 = 13; From a6a041921002f973f5688a586e0d21bf2c6714bd Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 20 Mar 2025 16:03:05 +0100 Subject: [PATCH 02/18] Use IPv6 addresses in hop_limit_v6 docs --- library/std/src/net/tcp.rs | 8 ++++---- library/std/src/net/udp.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 887a390d7a561..9d3f397da1e74 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -616,7 +616,7 @@ impl TcpStream { /// #![feature(ipv6_hop_limit)] /// use std::net::TcpStream; /// - /// let stream = TcpStream::connect("127.0.0.1:54321") + /// let stream = TcpStream::connect("[::1]:12345") /// .expect("Couldn't connect to the server..."); /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` @@ -635,7 +635,7 @@ impl TcpStream { /// #![feature(ipv6_hop_limit)] /// use std::net::TcpStream; /// - /// let stream = TcpStream::connect("127.0.0.1:54321") + /// let stream = TcpStream::connect("[::1]:12345") /// .expect("Couldn't connect to the server..."); /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); @@ -1083,7 +1083,7 @@ impl TcpListener { /// #![feature(ipv6_hop_limit)] /// use std::net::TcpListener; /// - /// let listener = TcpListener::bind("127.0.0.1:54321").unwrap(); + /// let listener = TcpListener::bind("[::1]:12345").unwrap(); /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "47727")] @@ -1101,7 +1101,7 @@ impl TcpListener { /// #![feature(ipv6_hop_limit)] /// use std::net::TcpListener; /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// let listener = TcpListener::bind("[::1]:12345").unwrap(); /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(listener.hop_limit_v6().unwrap(), 88); /// ``` diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 39dc6a6c833bd..7ee046fcd8a7b 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -600,7 +600,7 @@ impl UdpSocket { /// #![feature(ipv6_hop_limit)] /// use std::net::UdpSocket; /// - /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "47727")] @@ -618,7 +618,7 @@ impl UdpSocket { /// #![feature(ipv6_hop_limit)] /// use std::net::UdpSocket; /// - /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(socket.hop_limit_v6().unwrap(), 88); /// ``` @@ -638,7 +638,7 @@ impl UdpSocket { /// #![feature(ipv6_hop_limit)] /// use std::net::UdpSocket; /// - /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "47727")] @@ -656,7 +656,7 @@ impl UdpSocket { /// #![feature(ipv6_hop_limit)] /// use std::net::UdpSocket; /// - /// let socket = UdpSocket::bind("127.0.0.1:54321").expect("couldn't bind to address"); + /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// assert_eq!(socket.multicast_hop_limit_v6().unwrap(), 88); /// ``` From 01ba492d75bb1d8cba1eed8f146adc2347f3d930 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Mon, 31 Mar 2025 12:04:44 +0200 Subject: [PATCH 03/18] Update tracking issue to 139166 --- library/std/src/net/tcp.rs | 8 ++++---- library/std/src/net/udp.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 9d3f397da1e74..741238b29bc77 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -620,7 +620,7 @@ impl TcpStream { /// .expect("Couldn't connect to the server..."); /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -640,7 +640,7 @@ impl TcpStream { /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -1086,7 +1086,7 @@ impl TcpListener { /// let listener = TcpListener::bind("[::1]:12345").unwrap(); /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -1105,7 +1105,7 @@ impl TcpListener { /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(listener.hop_limit_v6().unwrap(), 88); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 7ee046fcd8a7b..914c400fb05f1 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -603,7 +603,7 @@ impl UdpSocket { /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -622,7 +622,7 @@ impl UdpSocket { /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(socket.hop_limit_v6().unwrap(), 88); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -641,7 +641,7 @@ impl UdpSocket { /// let socket = UdpSocket::bind("[::1]:12345").expect("couldn't bind to address"); /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_multicast_hop_limit_v6(limit) } @@ -660,7 +660,7 @@ impl UdpSocket { /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// assert_eq!(socket.multicast_hop_limit_v6().unwrap(), 88); /// ``` - #[unstable(feature = "ipv6_hop_limit", issue = "47727")] + #[unstable(feature = "ipv6_hop_limit", issue = "139166")] pub fn multicast_hop_limit_v6(&self) -> io::Result { self.0.multicast_hop_limit_v6() } From 942ea4b2a7cfab4b13b2bba2a6a686b0f7a6989a Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Mon, 31 Mar 2025 12:06:28 +0200 Subject: [PATCH 04/18] Update docs according to PR review Co-authored-by: David Tolnay --- library/std/src/net/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 741238b29bc77..a7489ec94df8a 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -605,7 +605,7 @@ impl TcpStream { self.0.ttl() } - // Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. /// /// This value sets the unicast hop limit field that is used in every packet /// sent from this socket. From e2421632b657bdd1b36b8dcdb766999074a85a3f Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 16 Apr 2025 12:20:56 +0200 Subject: [PATCH 05/18] Fix unused_variables --- library/std/src/sys/net/connection/unsupported.rs | 8 ++++---- library/std/src/sys/net/connection/xous/tcpstream.rs | 2 +- library/std/src/sys/net/connection/xous/udp.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index df285a4c0987d..193348a79ae3d 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -111,7 +111,7 @@ impl TcpStream { self.0 } - pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { self.0 } @@ -161,7 +161,7 @@ impl TcpListener { self.0 } - pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { self.0 } @@ -295,7 +295,7 @@ impl UdpSocket { self.0 } - pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { self.0 } @@ -303,7 +303,7 @@ impl UdpSocket { self.0 } - pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { self.0 } diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 11cd3f2c008bc..6f8944ba8f18d 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -403,7 +403,7 @@ impl TcpStream { .map(|res| res[0] as _)?) } - pub fn set_hop_limit_v6(&self, hlim: u8) -> io::Result<()> { + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { unimpl!(); } diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs index 7b01e715d57af..e254bfe1a5e45 100644 --- a/library/std/src/sys/net/connection/xous/udp.rs +++ b/library/std/src/sys/net/connection/xous/udp.rs @@ -385,7 +385,7 @@ impl UdpSocket { .map(|res| res[0] as _)?) } - pub fn set_hop_limit_v6(&self, hlim: u8) -> io::Result<()> { + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { unimpl!(); } From 0d559ec779113355be09105209585db07229ddd0 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Tue, 24 Mar 2026 12:27:38 +0100 Subject: [PATCH 06/18] fix: add cfg guards on unsupported wasi p2 and p3 targets --- library/std/src/net/tcp.rs | 4 ++++ library/std/src/net/tcp/tests.rs | 1 + library/std/src/net/udp.rs | 4 ++++ library/std/src/net/udp/tests.rs | 1 + library/std/src/sys/net/connection/socket/mod.rs | 8 ++++++++ 5 files changed, 18 insertions(+) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index a7489ec94df8a..1cd97dfa702a7 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -621,6 +621,7 @@ impl TcpStream { /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -641,6 +642,7 @@ impl TcpStream { /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -1087,6 +1089,7 @@ impl TcpListener { /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -1106,6 +1109,7 @@ impl TcpListener { /// assert_eq!(listener.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 9b8b28f6cb158..4db9335a76574 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -896,6 +896,7 @@ fn ttl() { #[test] #[cfg_attr(target_env = "sgx", ignore)] +#[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] fn hop_limit() { let hlim = 100; diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 914c400fb05f1..8fd5b2a0a446d 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -604,6 +604,7 @@ impl UdpSocket { /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -623,6 +624,7 @@ impl UdpSocket { /// assert_eq!(socket.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -642,6 +644,7 @@ impl UdpSocket { /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_multicast_hop_limit_v6(limit) } @@ -661,6 +664,7 @@ impl UdpSocket { /// assert_eq!(socket.multicast_hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn multicast_hop_limit_v6(&self) -> io::Result { self.0.multicast_hop_limit_v6() } diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 84ac9e2cd0c08..87b4cba5e70da 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -354,6 +354,7 @@ fn ttl() { } #[test] +#[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] fn hop_limit() { let hlim = 100; diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 223e26fc062ad..7c342972fc317 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -506,10 +506,12 @@ impl TcpStream { Ok(raw as u32) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; Ok(raw as u8) @@ -643,10 +645,12 @@ impl TcpListener { Ok(raw as u32) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; Ok(raw as u8) @@ -874,19 +878,23 @@ impl UdpSocket { Ok(raw as u32) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; Ok(raw as u8) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn multicast_hop_limit_v6(&self) -> io::Result { let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)?; Ok(raw as u8) From 6fe6d4c12dec009a330e5d08310de8d16ae96c7d Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Tue, 24 Mar 2026 13:10:36 +0100 Subject: [PATCH 07/18] fix: tidy PAL and unsafe blocks CI failure --- library/std/src/lib.rs | 2 +- library/std/src/net/tcp.rs | 4 -- library/std/src/net/udp.rs | 4 -- .../std/src/sys/net/connection/socket/mod.rs | 56 ++++++++++++++++--- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c96d644e997e9..ec0142c0df10c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -363,12 +363,12 @@ #![feature(io_error_uncategorized)] #![feature(io_slice_as_bytes)] #![feature(ip)] +#![feature(ipv6_hop_limit)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(maybe_dangling)] #![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_fill)] -#![feature(ipv6_hop_limit)] #![feature(once_lazy_lock_get_unchecked)] #![feature(panic_can_unwind)] #![feature(panic_internals)] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 1cd97dfa702a7..a7489ec94df8a 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -621,7 +621,6 @@ impl TcpStream { /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -642,7 +641,6 @@ impl TcpStream { /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -1089,7 +1087,6 @@ impl TcpListener { /// listener.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -1109,7 +1106,6 @@ impl TcpListener { /// assert_eq!(listener.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 8fd5b2a0a446d..914c400fb05f1 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -604,7 +604,6 @@ impl UdpSocket { /// socket.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_hop_limit_v6(limit) } @@ -624,7 +623,6 @@ impl UdpSocket { /// assert_eq!(socket.hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { self.0.hop_limit_v6() } @@ -644,7 +642,6 @@ impl UdpSocket { /// socket.set_multicast_hop_limit_v6(88).expect("set_multicast_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { self.0.set_multicast_hop_limit_v6(limit) } @@ -664,7 +661,6 @@ impl UdpSocket { /// assert_eq!(socket.multicast_hop_limit_v6().unwrap(), 88); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn multicast_hop_limit_v6(&self) -> io::Result { self.0.multicast_hop_limit_v6() } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 7c342972fc317..04dde9175d7fa 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -508,15 +508,25 @@ impl TcpStream { #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + } + + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) } #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; Ok(raw as u8) } + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn hop_limit_v6(&self) -> io::Result { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + pub fn take_error(&self) -> io::Result> { self.inner.take_error() } @@ -647,15 +657,25 @@ impl TcpListener { #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + } + + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) } #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; Ok(raw as u8) } + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn hop_limit_v6(&self) -> io::Result { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) } } @@ -880,26 +900,46 @@ impl UdpSocket { #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } + } + + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) } #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; Ok(raw as u8) } + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn hop_limit_v6(&self) -> io::Result { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) } + } + + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) } #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn multicast_hop_limit_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)? }; Ok(raw as u8) } + #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] + pub fn multicast_hop_limit_v6(&self) -> io::Result { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + pub fn take_error(&self) -> io::Result> { self.inner.take_error() } From a836f46197754459dc8912ea011ef4859ea9212c Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Tue, 24 Mar 2026 15:02:06 +0100 Subject: [PATCH 08/18] fix: tidy CI --- library/std/src/sys/net/connection/socket/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 04dde9175d7fa..931ad85cc1db8 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -931,7 +931,8 @@ impl UdpSocket { #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn multicast_hop_limit_v6(&self) -> io::Result { - let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)? }; + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)? }; Ok(raw as u8) } From 3b50f0e427c2bf35254796d2d60547b28a9b8e6b Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Thu, 6 Aug 2026 17:34:10 +0200 Subject: [PATCH 09/18] fix: port tests to new TCP testing framework --- library/std/src/net/tcp/tests.rs | 5 ++--- library/std/src/net/udp/tests.rs | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 4db9335a76574..58de3d478caa0 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -900,13 +900,12 @@ fn ttl() { fn hop_limit() { let hlim = 100; - let addr = next_test_ip6(); - let listener = t!(TcpListener::bind(&addr)); + let listener = t!(TcpListener::bind(LOCALHOST_IP6)); t!(listener.set_hop_limit_v6(hlim)); assert_eq!(hlim, t!(listener.hop_limit_v6())); - let stream = t!(TcpStream::connect(&addr)); + let stream = t!(TcpStream::connect(t!(listener.local_addr()))); t!(stream.set_hop_limit_v6(hlim)); assert_eq!(hlim, t!(stream.hop_limit_v6())); diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 87b4cba5e70da..89ec91122c5fb 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -358,9 +358,7 @@ fn ttl() { fn hop_limit() { let hlim = 100; - let addr = next_test_ip6(); - - let stream = t!(UdpSocket::bind(&addr)); + let stream = t!(UdpSocket::bind(LOCALHOST_IP6)); t!(stream.set_hop_limit_v6(hlim)); assert_eq!(hlim, t!(stream.hop_limit_v6())); From 44b00ff44dfa263622c277acd7c6984864af4ed6 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Fri, 7 Aug 2026 09:46:49 +0200 Subject: [PATCH 10/18] Trigger CI From 931014d7f8e6d5ce74dd2cf1c38aa7e632498b82 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 23 Sep 2026 14:38:37 +0200 Subject: [PATCH 11/18] Fix TCP hop limit doctest indentation --- library/std/src/net/tcp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index a7489ec94df8a..9fe16c4f9bd68 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -617,7 +617,7 @@ impl TcpStream { /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("[::1]:12345") - /// .expect("Couldn't connect to the server..."); + /// .expect("Couldn't connect to the server..."); /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// ``` #[unstable(feature = "ipv6_hop_limit", issue = "139166")] @@ -636,7 +636,7 @@ impl TcpStream { /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("[::1]:12345") - /// .expect("Couldn't connect to the server..."); + /// .expect("Couldn't connect to the server..."); /// stream.set_hop_limit_v6(88).expect("set_hop_limit_v6 call failed"); /// assert_eq!(stream.hop_limit_v6().unwrap(), 88); /// ``` From 4bfcbaf01e63ff80ce5bd3debb6210dbb5096500 Mon Sep 17 00:00:00 2001 From: Luca Cominardi Date: Wed, 23 Sep 2026 14:55:52 +0200 Subject: [PATCH 12/18] Use cfg_select for socket hop limit methods --- .../std/src/sys/net/connection/socket/mod.rs | 137 ++++++++++-------- 1 file changed, 76 insertions(+), 61 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 931ad85cc1db8..7f1e1ee95699f 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -506,25 +506,29 @@ impl TcpStream { Ok(raw as u32) } - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } - } - - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] - pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) - } - - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] - pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; - Ok(raw as u8) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + let _ = limit; + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => unsafe { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + }, + } } - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] pub fn hop_limit_v6(&self) -> io::Result { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => { + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; + Ok(raw as u8) + } + } } pub fn take_error(&self) -> io::Result> { @@ -655,25 +659,29 @@ impl TcpListener { Ok(raw as u32) } - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } - } - - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] - pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) - } - - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] - pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; - Ok(raw as u8) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + let _ = limit; + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => unsafe { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + }, + } } - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] pub fn hop_limit_v6(&self) -> io::Result { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => { + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; + Ok(raw as u8) + } + } } pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { @@ -898,47 +906,54 @@ impl UdpSocket { Ok(raw as u32) } - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) } - } - - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] - pub fn set_hop_limit_v6(&self, _: u8) -> io::Result<()> { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) - } - - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] - pub fn hop_limit_v6(&self) -> io::Result { - let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; - Ok(raw as u8) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + let _ = limit; + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => unsafe { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, limit as c_int) + }, + } } - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] pub fn hop_limit_v6(&self) -> io::Result { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => { + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS)? }; + Ok(raw as u8) + } + } } - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] pub fn set_multicast_hop_limit_v6(&self, limit: u8) -> io::Result<()> { - unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) } - } - - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] - pub fn set_multicast_hop_limit_v6(&self, _: u8) -> io::Result<()> { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) - } - - #[cfg(not(all(target_os = "wasi", any(target_env = "p2", target_env = "p3"))))] - pub fn multicast_hop_limit_v6(&self) -> io::Result { - let raw: c_int = - unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)? }; - Ok(raw as u8) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + let _ = limit; + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => unsafe { + setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS, limit as c_int) + }, + } } - #[cfg(all(target_os = "wasi", any(target_env = "p2", target_env = "p3")))] pub fn multicast_hop_limit_v6(&self) -> io::Result { - Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + cfg_select! { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { + Err(io::Error::new(ErrorKind::Unsupported, "not supported on this platform")) + } + _ => { + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_HOPS)? }; + Ok(raw as u8) + } + } } pub fn take_error(&self) -> io::Result> { From e75273b0247664eded2f7bd482c76dc0adaaf149 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 2 Oct 2026 08:44:29 +0200 Subject: [PATCH 13/18] core: io: clean `unused_variables` lint under `no_io_statics` When building `core` with `--cfg no_io_statics`, the compiler warns: error: unused variable: `f` --> .../library/core/src/io/error/os_functions.rs:9:36 | 9 | pub(super) unsafe fn set_functions(f: &'static OsFunctions) { | ^ help: if this is intentional, prefix it with an underscore: `_f` | = note: `-D unused-variables` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(unused_variables)]` Thus clean it up. Signed-off-by: Miguel Ojeda --- library/core/src/io/error/os_functions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/io/error/os_functions.rs b/library/core/src/io/error/os_functions.rs index b34b7c7dc7926..fcc549f0fb643 100644 --- a/library/core/src/io/error/os_functions.rs +++ b/library/core/src/io/error/os_functions.rs @@ -6,7 +6,7 @@ use crate::fmt; /// The provided reference must point to data that is entirely constant; it must /// not be created during runtime. #[inline] -pub(super) unsafe fn set_functions(f: &'static OsFunctions) { +pub(super) unsafe fn set_functions(_f: &'static OsFunctions) { // FIXME: externally implementable items may allow for weak linkage, allowing // these methods to be overridden even when atomic pointers are not supported. } From f3f9adf7082e27e0b77b05ec3e2fdaee1badd056 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Fri, 2 Oct 2026 14:48:46 +0200 Subject: [PATCH 14/18] tests: add test for warning-free builds of `core` under `no_io_statics` Similar to the existing tests for other `cfg`s like `no_fp_fmt_parse`, add one for `no_io_statics`. This should prevent issues like the one in the parent commit. Signed-off-by: Miguel Ojeda --- tests/run-make/core-no-io-statics/rmake.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/run-make/core-no-io-statics/rmake.rs diff --git a/tests/run-make/core-no-io-statics/rmake.rs b/tests/run-make/core-no-io-statics/rmake.rs new file mode 100644 index 0000000000000..0e75dfa8c273c --- /dev/null +++ b/tests/run-make/core-no-io-statics/rmake.rs @@ -0,0 +1,14 @@ +// This test checks that the core library of Rust can be compiled when enabling +// `--cfg no_io_statics`. + +use run_make_support::{rustc, source_root}; + +fn main() { + rustc() + .edition("2024") + .arg("-Dwarnings") + .crate_type("rlib") + .input(source_root().join("library/core/src/lib.rs")) + .cfg("no_io_statics") + .run(); +} From da0baa24c41da903b35aa146503e4261ffe26aaa Mon Sep 17 00:00:00 2001 From: Yara Date: Fri, 2 Oct 2026 15:38:20 +0200 Subject: [PATCH 15/18] reflection: fix ICE when TypeId::info called on ADT We are refactoring from a large enum where the fields of the variants contain all the reflection info to a flat enum containing only the type kind (struct/bool/array etc). While we removed the fields of Struct, Enum and Union we forgot to take out the const eval code writing into those fields. That gave an ICE. This fixes that. --- .../src/const_eval/type_info.rs | 4 +- .../src/const_eval/type_info/adt.rs | 178 +----------------- 2 files changed, 7 insertions(+), 175 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 0bece36c64ed0..0df2e9b5fd0ae 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -91,9 +91,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.project_downcast_named(&field_dest, sym::Slice)?; variant } - ty::Adt(adt_def, generics) => { - self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)? - } + ty::Adt(adt_def, _) => self.write_adt_type_info(&field_dest, *adt_def)?, ty::Bool => { let (variant, _variant_place) = self.project_downcast_named(&field_dest, sym::Bool)?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs index 281d7b0a921ba..4ff1b37e953d4 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs @@ -1,13 +1,12 @@ use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ - AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, VariantDef, + AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, }; use rustc_span::{bug, span_bug, sym}; use crate::const_eval::CompileTimeMachine; use crate::interpret::{ - CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Scalar, Writeable, interp_ok, + CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Writeable, interp_ok, }; impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { @@ -15,190 +14,25 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { pub(crate) fn write_adt_type_info( &mut self, place: &impl Writeable<'tcx, CtfeProvenance>, - adt: (Ty<'tcx>, AdtDef<'tcx>), - generics: &'tcx GenericArgs<'tcx>, + adt_def: AdtDef<'tcx>, ) -> InterpResult<'tcx, VariantIdx> { - let (adt_ty, adt_def) = adt; let variant_idx = match adt_def.adt_kind() { AdtKind::Struct => { - let (variant, variant_place) = self.project_downcast_named(place, sym::Struct)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_struct_type_info( - place, - (adt_ty, adt_def.variant(VariantIdx::ZERO)), - generics, - )?; + let (variant, _) = self.project_downcast_named(place, sym::Struct)?; variant } AdtKind::Union => { - let (variant, variant_place) = self.project_downcast_named(place, sym::Union)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_union_type_info( - place, - (adt_ty, adt_def.variant(VariantIdx::ZERO)), - generics, - )?; + let (variant, _) = self.project_downcast_named(place, sym::Union)?; variant } AdtKind::Enum => { - let (variant, variant_place) = self.project_downcast_named(place, sym::Enum)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_enum_type_info(place, adt, generics)?; + let (variant, _) = self.project_downcast_named(place, sym::Enum)?; variant } }; interp_ok(variant_idx) } - pub(crate) fn write_struct_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - struct_: (Ty<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (struct_ty, struct_def) = struct_; - let struct_layout = self.layout_of(struct_ty)?; - - for (field_idx, field) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - - match field.name { - sym::generics => self.write_generics(&field_place, generics)?, - sym::fields => { - self.write_variant_fields(field_place, struct_def, struct_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = struct_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - pub(crate) fn write_union_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - union_: (Ty<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (union_ty, union_def) = union_; - let union_layout = self.layout_of(union_ty)?; - - for (field_idx, field) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - - match field.name { - sym::generics => self.write_generics(&field_place, generics)?, - sym::fields => { - self.write_variant_fields(field_place, union_def, union_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = union_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - pub(crate) fn write_enum_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - enum_: (Ty<'tcx>, AdtDef<'tcx>), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (enum_ty, enum_def) = enum_; - let enum_layout = self.layout_of(enum_ty)?; - - for (field_idx, field) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - - match field.name { - sym::generics => self.write_generics(&field_place, generics)?, - sym::type_id_variants => { - self.allocate_fill_and_write_slice_ptr( - &field_place, - enum_def.variants().len() as u64, - |this, i, place| { - let variant_idx = VariantIdx::from_usize(i as usize); - let variant_def = &enum_def.variants()[variant_idx]; - let variant_layout = enum_layout.for_variant(this, variant_idx); - this.write_enum_variant(place, (variant_layout, &variant_def), generics) - }, - )?; - } - sym::non_exhaustive => { - let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - - fn write_enum_variant( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - variant: (TyAndLayout<'tcx>, &'tcx VariantDef), - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - let (variant_layout, variant_def) = variant; - - for (field_idx, field_def) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - match field_def.name { - sym::name => { - let name_place = self.allocate_str_dedup(variant_def.name.as_str())?; - let ptr = self.mplace_to_imm_ptr(&name_place, None)?; - self.write_immediate(*ptr, &field_place)? - } - sym::fields => { - self.write_variant_fields(field_place, &variant_def, variant_layout, generics)? - } - sym::non_exhaustive => { - let is_non_exhaustive = variant_def.is_field_list_non_exhaustive(); - self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)? - } - other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"), - } - } - interp_ok(()) - } - - // Write fields for struct, enum variants - fn write_variant_fields( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - variant_def: &'tcx VariantDef, - variant_layout: TyAndLayout<'tcx>, - generics: &'tcx GenericArgs<'tcx>, - ) -> InterpResult<'tcx> { - self.allocate_fill_and_write_slice_ptr( - &place, - variant_def.fields.len() as u64, - |this, i, place| { - let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)]; - let field_ty = field_def.ty(*this.tcx, generics).skip_norm_wip(); - this.write_field(field_ty, place, variant_layout, Some(field_def.name), i) - }, - ) - } - pub(super) fn write_generics( &mut self, place: &impl Writeable<'tcx, CtfeProvenance>, From 6065c5ae5206289fa17f13049c8bfad88fbfa3af Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 2 Oct 2026 16:42:27 -0400 Subject: [PATCH 16/18] Make the tracking issue template better suited for experiments --- .github/ISSUE_TEMPLATE/tracking_issue.md | 32 +++++++++++++++--------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index 0e0fdc5ca864e..e4bdcd212f381 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -1,6 +1,6 @@ --- name: Tracking Issue -about: A tracking issue for an accepted feature or RFC in Rust. +about: A tracking issue for an unstable feature in Rust. title: Tracking Issue for XXX labels: C-tracking-issue --- @@ -8,19 +8,27 @@ labels: C-tracking-issue NOTE: For library features, please use the "Library Tracking Issue" template instead. Thank you for creating a tracking issue! 📜 Tracking issues are for tracking a -feature from implementation to stabilisation. Make sure to include the relevant -RFC for the feature if it has one. Otherwise provide a short summary of the -feature and link any relevant PRs or issues, and remove any sections that are -not relevant to the feature. +feature from implementation to stabilisation. Remember to add team labels to the tracking issue. -For a language team feature, this would e.g., be `T-lang`. +For a language team feature, this would e.g., be `T-lang`: + +> @rustbot label T-lang + Such a feature should also be labeled with e.g., `F-my_feature`. This label is used to associate issues (e.g., bugs and design questions) to the feature. --> -This is a tracking issue for the RFC "XXX" (rust-lang/rfcs#NNN). -The feature gate for the issue is `#![feature(FFF)]`. +This is a tracking issue for `#![feature(FFF)]`. +The RFC for this feature is rust-lang/rfcs#NNN. + + ### About tracking issues @@ -38,8 +46,8 @@ implementing a feature, followed by a PR that stabilises the feature. However for larger features an implementation could be broken up into multiple PRs. --> -- [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring - instructions?) +- [ ] Create the feature gate +- [ ] Implement the feature - [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide]) - [ ] Style updates for any new syntax ([nightly-style-procedure]) - [ ] Style team decision on new formatting @@ -59,8 +67,8 @@ stabilised. It is useful to link related discussions and conculsions as they develop. --> -- [ ] list all the "unresolved questions" found in the RFC to ensure they are - not forgotten. +- [ ] List any unresolved questions, including those listed in the RFC if there is one, + to ensure they are not forgotten. ### Implementation history From 89f50a5d3a11eb03f983aca5158590e4771bfd16 Mon Sep 17 00:00:00 2001 From: panstromek Date: Sat, 3 Oct 2026 07:01:18 +0200 Subject: [PATCH 17/18] ref: Avoid long iterator chain in all_rust_features --- compiler/rustc_target/src/target_features.rs | 42 ++++++++++---------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 2ee7dea9f8af3..5272ed2df59b3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -1062,26 +1062,28 @@ const XTENSA_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ /// /// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator! pub fn all_rust_features() -> impl Iterator { - std::iter::empty() - .chain(ARM_FEATURES) - .chain(AARCH64_FEATURES) - .chain(X86_FEATURES) - .chain(HEXAGON_FEATURES) - .chain(POWERPC_FEATURES) - .chain(MIPS_FEATURES) - .chain(NVPTX_FEATURES) - .chain(RISCV_FEATURES) - .chain(WASM_FEATURES) - .chain(BPF_FEATURES) - .chain(XTENSA_FEATURES) - .chain(CSKY_FEATURES) - .chain(LOONGARCH_FEATURES) - .chain(IBMZ_FEATURES) - .chain(SPARC_FEATURES) - .chain(M68K_FEATURES) - .chain(AVR_FEATURES) - .cloned() - .map(|(f, s, _)| (f, s)) + [ + ARM_FEATURES, + AARCH64_FEATURES, + X86_FEATURES, + HEXAGON_FEATURES, + POWERPC_FEATURES, + MIPS_FEATURES, + NVPTX_FEATURES, + RISCV_FEATURES, + WASM_FEATURES, + BPF_FEATURES, + XTENSA_FEATURES, + CSKY_FEATURES, + LOONGARCH_FEATURES, + IBMZ_FEATURES, + SPARC_FEATURES, + M68K_FEATURES, + AVR_FEATURES, + ] + .into_iter() + .flatten() + .map(|(f, s, _)| (*f, *s)) } /// Find which target architectures a feature belongs to. From 62cbb1801373d3e36a957780a9bb92830a6ebbaf Mon Sep 17 00:00:00 2001 From: Davlat Davydov Date: Fri, 2 Oct 2026 02:26:15 +0300 Subject: [PATCH 18/18] Add documentation for the and attributes Fix test-tidy review changes review changes review changes fix llvm build --- library/core/src/attribute_docs.rs | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index 584e1583c9bdb..989f1e154add6 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -406,6 +406,104 @@ const _: () = (); /// [the `no_std` attribute]: ../reference/names/preludes.html#the-no_std-attribute const _: () = (); +#[doc(attribute = "no_main")] +/// Prevents emitting the `main` entrypoint symbol. +/// +/// Written as an inner attribute at the top of the crate root, the `no_main` attribute prevents +/// the compiler from generating the program's standard Rust entrypoint, leaving that up to you. +/// This is useful when some other object being linked into the program defines the entrypoint, +/// or when you want to define the platform's `main` symbol yourself. +/// +/// If you define an entry point symbol that is suitable for your target, it must also be exported +/// under an unmangled name using the [`no_mangle` attribute]: +/// +/// ```standalone_crate +/// #![no_main] +/// +/// use std::ffi::{c_char, c_int}; +/// +/// #[unsafe(no_mangle)] +/// pub extern "C" fn main(_argc: c_int, _argv: *const *const c_char) -> c_int { +/// println!("Hello world!"); +/// 0 +/// } +/// ``` +/// +/// Unlike `no_std`, the `no_main` attribute does not prevent the compiler from generating +/// the startup routine or linking the standard library provided by the operating system's executable [ABI]. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// [`no_mangle` attribute]: ../reference/abi.html#the-no_mangle-attribute +const _: () = (); + +#[doc(attribute = "repr")] +/// Specifies the [representation] of a type. +/// +/// Written as an outer attribute on a `struct`, `enum` or `union`, `repr` controls how the +/// type is laid out in memory. This is needed when passing types across an [FFI] boundary +/// or whenever you rely on a specific layout. +/// +/// The available representations are: +/// +/// * [`Rust`] (the default): the layout is unspecified and may change between compilations. +/// * [`C`]: the layout follows the rules of the C language for the target platform. +/// * The [primitive representations] (`u8`, `i32`, `usize`, ...): set the discriminant +/// type of an enum. +/// * [`transparent`]: the type has the same layout and ABI as its only non-zero-sized field. +/// +/// The `align(N)` and `packed(N)` modifiers raise or lower the alignment of a type, respectively. +/// `N` must be a power of two no greater than 229. The two modifiers cannot be +/// applied to the same type, and references to fields of a `packed` type cannot be created, +/// since they may be unaligned. +/// +/// # Examples +/// +/// ``` +/// #[repr(C, align(16))] +/// struct Foo { +/// first: u32, +/// second: u32, +/// third: u32, +/// } +/// +/// assert_eq!(align_of::(), 16); +/// // 12 bytes of fields, rounded up to a multiple of the alignment. +/// assert_eq!(size_of::(), 16); +/// ``` +/// +/// ``` +/// #[repr(C, packed(2))] +/// struct Foo { +/// first: u32, +/// second: u32, +/// third: u32, +/// } +/// +/// assert_eq!(align_of::(), 2); +/// assert_eq!(size_of::(), 12); +/// ``` +/// +/// ``` +/// #[repr(C)] +/// struct Foo { +/// item: T, +/// } +/// ``` +/// +/// `Foo` is laid out according to the C rules and is guaranteed to be 16-byte aligned. +/// +/// The representation is a property of the type definition, so it does +/// parameters: below, `Foo` and `Foo` both use the `C` representation. Their actual +/// layouts still differ, because they depend on `T`. +/// +/// [representation]: ../reference/type-layout.html#representations +/// [`Rust`]: ../reference/type-layout.html#the-rust-representation +/// [`C`]: ../reference/type-layout.html#the-c-representation +/// [primitive representations]: ../reference/type-layout.html#primitive-representations +/// [`transparent`]: ../reference/type-layout.html#the-transparent-representation +/// [FFI]: https://en.wikipedia.org/wiki/Foreign_function_interface +const _: () = (); + #[doc(attribute = "inline")] // /// Suggest that the compiler inline a function at its call sites.