From 96b44f6f659acc13bba63e29263e504f84b19fc3 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 16 Aug 2022 20:23:32 +0200 Subject: [PATCH 1/7] Use `DisplayBuffer` for socket addresses. --- .../src/net/{ip => addr}/display_buffer.rs | 6 +- library/std/src/net/{ip.rs => addr/ip/mod.rs} | 7 +-- library/std/src/net/{ => addr}/ip/tests.rs | 0 library/std/src/net/addr/mod.rs | 4 ++ .../src/net/{addr.rs => addr/socket/mod.rs} | 58 +++++++------------ .../std/src/net/addr/{ => socket}/tests.rs | 0 library/std/src/net/mod.rs | 5 +- 7 files changed, 34 insertions(+), 46 deletions(-) rename library/std/src/net/{ip => addr}/display_buffer.rs (86%) rename library/std/src/net/{ip.rs => addr/ip/mod.rs} (99%) rename library/std/src/net/{ => addr}/ip/tests.rs (100%) create mode 100644 library/std/src/net/addr/mod.rs rename library/std/src/net/{addr.rs => addr/socket/mod.rs} (94%) rename library/std/src/net/addr/{ => socket}/tests.rs (100%) diff --git a/library/std/src/net/ip/display_buffer.rs b/library/std/src/net/addr/display_buffer.rs similarity index 86% rename from library/std/src/net/ip/display_buffer.rs rename to library/std/src/net/addr/display_buffer.rs index bd852d5da8ec5..7aadf06e92fc6 100644 --- a/library/std/src/net/ip/display_buffer.rs +++ b/library/std/src/net/addr/display_buffer.rs @@ -3,12 +3,12 @@ use crate::mem::MaybeUninit; use crate::str; /// Used for slow path in `Display` implementations when alignment is required. -pub struct IpDisplayBuffer { +pub struct DisplayBuffer { buf: [MaybeUninit; SIZE], len: usize, } -impl IpDisplayBuffer { +impl DisplayBuffer { #[inline] pub const fn new() -> Self { Self { buf: MaybeUninit::uninit_array(), len: 0 } @@ -25,7 +25,7 @@ impl IpDisplayBuffer { } } -impl fmt::Write for IpDisplayBuffer { +impl fmt::Write for DisplayBuffer { fn write_str(&mut self, s: &str) -> fmt::Result { let bytes = s.as_bytes(); diff --git a/library/std/src/net/ip.rs b/library/std/src/net/addr/ip/mod.rs similarity index 99% rename from library/std/src/net/ip.rs rename to library/std/src/net/addr/ip/mod.rs index 6004810655ebb..a670f7168334a 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/addr/ip/mod.rs @@ -8,8 +8,7 @@ use crate::mem::transmute; use crate::sys::net::netc as c; use crate::sys_common::{FromInner, IntoInner}; -mod display_buffer; -use display_buffer::IpDisplayBuffer; +use super::display_buffer::DisplayBuffer; /// An IP address, either IPv4 or IPv6. /// @@ -997,7 +996,7 @@ impl fmt::Display for Ipv4Addr { } else { const LONGEST_IPV4_ADDR: &str = "255.255.255.255"; - let mut buf = IpDisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new(); + let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new(); // Buffer is long enough for the longest possible IPv4 address, so this should never fail. write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); @@ -1844,7 +1843,7 @@ impl fmt::Display for Ipv6Addr { } else { const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"; - let mut buf = IpDisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new(); + let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new(); // Buffer is long enough for the longest possible IPv6 address, so this should never fail. write!(buf, "{}", self).unwrap(); diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/addr/ip/tests.rs similarity index 100% rename from library/std/src/net/ip/tests.rs rename to library/std/src/net/addr/ip/tests.rs diff --git a/library/std/src/net/addr/mod.rs b/library/std/src/net/addr/mod.rs new file mode 100644 index 0000000000000..afecab3049848 --- /dev/null +++ b/library/std/src/net/addr/mod.rs @@ -0,0 +1,4 @@ +mod display_buffer; + +pub mod ip; +pub mod socket; diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr/socket/mod.rs similarity index 94% rename from library/std/src/net/addr.rs rename to library/std/src/net/addr/socket/mod.rs index 53fee952a7a7a..33b0dfa03e0ed 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr/socket/mod.rs @@ -2,9 +2,9 @@ mod tests; use crate::cmp::Ordering; -use crate::fmt; +use crate::fmt::{self, Write}; use crate::hash; -use crate::io::{self, Write}; +use crate::io; use crate::iter; use crate::mem; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -15,6 +15,8 @@ use crate::sys_common::net::LookupHost; use crate::sys_common::{FromInner, IntoInner}; use crate::vec; +use super::display_buffer::DisplayBuffer; + /// An internet socket address, either IPv4 or IPv6. /// /// Internet socket addresses consist of an [IP address], a 16-bit port number, as well @@ -616,25 +618,18 @@ impl fmt::Debug for SocketAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV4 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Fast path: if there's no alignment stuff, write to the output buffer - // directly + // If there are no alignment requirements, write the socket address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. if f.precision().is_none() && f.width().is_none() { write!(f, "{}:{}", self.ip(), self.port()) } else { - const IPV4_SOCKET_BUF_LEN: usize = (3 * 4) // the segments - + 3 // the separators - + 1 + 5; // the port - let mut buf = [0; IPV4_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - // Unwrap is fine because writing to a sufficiently-sized - // buffer is infallible - write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); - let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); - - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) + const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536"; + + let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new(); + // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail. + write!(buf, "{}:{}", self.ip(), self.port()).unwrap(); + + f.pad(buf.as_str()) } } } @@ -649,35 +644,26 @@ impl fmt::Debug for SocketAddrV4 { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV6 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Fast path: if there's no alignment stuff, write to the output - // buffer directly + // If there are no alignment requirements, write the socket address directly to `f`. + // Otherwise, write it to a local buffer and then use `f.pad`. if f.precision().is_none() && f.width().is_none() { match self.scope_id() { 0 => write!(f, "[{}]:{}", self.ip(), self.port()), scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()), } } else { - const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address - + 7 // The colon separators - + 2 // The brackets - + 1 + 10 // The scope id - + 1 + 5; // The port - - let mut buf = [0; IPV6_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; + const LONGEST_IPV6_SOCKET_ADDR: &str = + "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536"; + let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new(); match self.scope_id() { - 0 => write!(buf_slice, "[{}]:{}", self.ip(), self.port()), - scope_id => write!(buf_slice, "[{}%{}]:{}", self.ip(), scope_id, self.port()), + 0 => write!(buf, "[{}]:{}", self.ip(), self.port()), + scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()), } - // Unwrap is fine because writing to a sufficiently-sized - // buffer is infallible + // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail. .unwrap(); - let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) + f.pad(buf.as_str()) } } } diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/socket/tests.rs similarity index 100% rename from library/std/src/net/addr/tests.rs rename to library/std/src/net/addr/socket/tests.rs diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index 6f9743f3a0ebe..8dd0936133dc0 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -24,9 +24,9 @@ use crate::io::{self, ErrorKind}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +pub use self::addr::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +pub use self::addr::socket::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::parser::AddrParseError; #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] @@ -37,7 +37,6 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream}; pub use self::udp::UdpSocket; mod addr; -mod ip; mod parser; mod tcp; #[cfg(test)] From 65003fd4e341d0556a4100e4616eec9861b89b93 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 20 Aug 2022 00:06:47 +0200 Subject: [PATCH 2/7] Add tests for `SockAddr` `Display`. --- library/std/src/net/addr/socket/tests.rs | 69 ++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/library/std/src/net/addr/socket/tests.rs b/library/std/src/net/addr/socket/tests.rs index 585a17451a0b7..15211f81981ba 100644 --- a/library/std/src/net/addr/socket/tests.rs +++ b/library/std/src/net/addr/socket/tests.rs @@ -51,6 +51,75 @@ fn to_socket_addr_string() { // s has been moved into the tsa call } +#[test] +fn ipv4_socket_addr_to_string() { + // Shortest possible IPv4 length. + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0"); + + // Longest possible IPv4 length. + assert_eq!( + SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(), + "255.255.255.255:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + "1.1.1.1:53 " + ); + assert_eq!( + &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + " 1.1.1.1:53" + ); +} + +#[test] +fn ipv6_socket_addr_to_string() { + // IPv4-mapped address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0) + .to_string(), + "[::ffff:192.0.2.128]:8080" + ); + + // IPv4-compatible address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), + "[::192.0.2.128]:8080" + ); + + // IPv6 address with no zero segments. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(), + "[8:9:a:b:c:d:e:f]:80" + ); + + // Shortest possible IPv6 length. + assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0"); + + // Longest possible IPv6 length. + assert_eq!( + SocketAddrV6::new( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888), + u16::MAX, + u32::MAX, + u32::MAX, + ) + .to_string(), + "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + "[1:2:3:4:5:6:7:8]:9 " + ); + assert_eq!( + &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + " [1:2:3:4:5:6:7:8]:9" + ); +} + #[test] fn bind_udp_socket_bad() { // rust-lang/rust#53957: This is a regression test for a parsing problem From a1e4a339edd0df546263d6ae79b003b465454248 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 20 Aug 2022 00:24:49 +0200 Subject: [PATCH 3/7] Move `net::parser` into `net::addr` module. --- library/std/src/net/addr/mod.rs | 1 + library/std/src/net/{parser.rs => addr/parser/mod.rs} | 0 library/std/src/net/{ => addr}/parser/tests.rs | 0 library/std/src/net/mod.rs | 5 ++--- 4 files changed, 3 insertions(+), 3 deletions(-) rename library/std/src/net/{parser.rs => addr/parser/mod.rs} (100%) rename library/std/src/net/{ => addr}/parser/tests.rs (100%) diff --git a/library/std/src/net/addr/mod.rs b/library/std/src/net/addr/mod.rs index afecab3049848..da33666a5805a 100644 --- a/library/std/src/net/addr/mod.rs +++ b/library/std/src/net/addr/mod.rs @@ -1,4 +1,5 @@ mod display_buffer; pub mod ip; +pub mod parser; pub mod socket; diff --git a/library/std/src/net/parser.rs b/library/std/src/net/addr/parser/mod.rs similarity index 100% rename from library/std/src/net/parser.rs rename to library/std/src/net/addr/parser/mod.rs diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/addr/parser/tests.rs similarity index 100% rename from library/std/src/net/parser/tests.rs rename to library/std/src/net/addr/parser/tests.rs diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index 8dd0936133dc0..3a2e1d6d24c73 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -26,9 +26,9 @@ use crate::io::{self, ErrorKind}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::addr::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::socket::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +pub use self::addr::parser::AddrParseError; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::parser::AddrParseError; +pub use self::addr::socket::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] pub use self::tcp::IntoIncoming; #[stable(feature = "rust1", since = "1.0.0")] @@ -37,7 +37,6 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream}; pub use self::udp::UdpSocket; mod addr; -mod parser; mod tcp; #[cfg(test)] pub(crate) mod test; From f7e8ba28a4785e698a55fb95e4b3e803302de0ff Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 24 Aug 2022 13:13:12 +0200 Subject: [PATCH 4/7] Flatten `net` module again. --- library/std/src/net/addr/mod.rs | 5 ----- library/std/src/net/{addr => }/display_buffer.rs | 0 library/std/src/net/{addr/ip/mod.rs => ip_addr.rs} | 0 library/std/src/net/{addr/ip => ip_addr}/tests.rs | 0 library/std/src/net/mod.rs | 11 +++++++---- library/std/src/net/{addr/parser/mod.rs => parser.rs} | 0 library/std/src/net/{addr => }/parser/tests.rs | 0 .../src/net/{addr/socket/mod.rs => socket_addr.rs} | 0 .../std/src/net/{addr/socket => socket_addr}/tests.rs | 0 9 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 library/std/src/net/addr/mod.rs rename library/std/src/net/{addr => }/display_buffer.rs (100%) rename library/std/src/net/{addr/ip/mod.rs => ip_addr.rs} (100%) rename library/std/src/net/{addr/ip => ip_addr}/tests.rs (100%) rename library/std/src/net/{addr/parser/mod.rs => parser.rs} (100%) rename library/std/src/net/{addr => }/parser/tests.rs (100%) rename library/std/src/net/{addr/socket/mod.rs => socket_addr.rs} (100%) rename library/std/src/net/{addr/socket => socket_addr}/tests.rs (100%) diff --git a/library/std/src/net/addr/mod.rs b/library/std/src/net/addr/mod.rs deleted file mode 100644 index da33666a5805a..0000000000000 --- a/library/std/src/net/addr/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod display_buffer; - -pub mod ip; -pub mod parser; -pub mod socket; diff --git a/library/std/src/net/addr/display_buffer.rs b/library/std/src/net/display_buffer.rs similarity index 100% rename from library/std/src/net/addr/display_buffer.rs rename to library/std/src/net/display_buffer.rs diff --git a/library/std/src/net/addr/ip/mod.rs b/library/std/src/net/ip_addr.rs similarity index 100% rename from library/std/src/net/addr/ip/mod.rs rename to library/std/src/net/ip_addr.rs diff --git a/library/std/src/net/addr/ip/tests.rs b/library/std/src/net/ip_addr/tests.rs similarity index 100% rename from library/std/src/net/addr/ip/tests.rs rename to library/std/src/net/ip_addr/tests.rs diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index 3a2e1d6d24c73..01e3db9de51c4 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -24,11 +24,11 @@ use crate::io::{self, ErrorKind}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::parser::AddrParseError; +pub use self::parser::AddrParseError; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::addr::socket::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] pub use self::tcp::IntoIncoming; #[stable(feature = "rust1", since = "1.0.0")] @@ -36,7 +36,10 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::udp::UdpSocket; -mod addr; +mod display_buffer; +mod ip_addr; +mod parser; +mod socket_addr; mod tcp; #[cfg(test)] pub(crate) mod test; diff --git a/library/std/src/net/addr/parser/mod.rs b/library/std/src/net/parser.rs similarity index 100% rename from library/std/src/net/addr/parser/mod.rs rename to library/std/src/net/parser.rs diff --git a/library/std/src/net/addr/parser/tests.rs b/library/std/src/net/parser/tests.rs similarity index 100% rename from library/std/src/net/addr/parser/tests.rs rename to library/std/src/net/parser/tests.rs diff --git a/library/std/src/net/addr/socket/mod.rs b/library/std/src/net/socket_addr.rs similarity index 100% rename from library/std/src/net/addr/socket/mod.rs rename to library/std/src/net/socket_addr.rs diff --git a/library/std/src/net/addr/socket/tests.rs b/library/std/src/net/socket_addr/tests.rs similarity index 100% rename from library/std/src/net/addr/socket/tests.rs rename to library/std/src/net/socket_addr/tests.rs From d01498a902ac61e4931384be89969b55cf391bd7 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Thu, 1 Sep 2022 22:19:13 +0200 Subject: [PATCH 5/7] Add `rustc_diagnostic_item` for IP addresses. --- library/std/src/net/ip_addr.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs index a670f7168334a..18cd43a6b8332 100644 --- a/library/std/src/net/ip_addr.rs +++ b/library/std/src/net/ip_addr.rs @@ -29,13 +29,16 @@ use super::display_buffer::DisplayBuffer; /// assert_eq!(localhost_v4.is_ipv6(), false); /// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")] #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum IpAddr { /// An IPv4 address. + #[cfg_attr(not(test), rustc_diagnostic_item = "ip_addr_variant_v4")] #[stable(feature = "ip_addr", since = "1.7.0")] V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), /// An IPv6 address. + #[cfg_attr(not(test), rustc_diagnostic_item = "ip_addr_variant_v6")] #[stable(feature = "ip_addr", since = "1.7.0")] V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), } @@ -72,6 +75,7 @@ pub enum IpAddr { /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv4Addr")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { octets: [u8; 4], @@ -154,6 +158,7 @@ pub struct Ipv4Addr { /// assert_eq!(localhost.is_loopback(), true); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv6Addr")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { octets: [u8; 16], From 8c78400c541df0600132a726c7b58717b158befa Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 2 Sep 2022 01:11:20 +0200 Subject: [PATCH 6/7] Fix clippy. --- .../src/matches/redundant_pattern_match.rs | 81 +++++++++++++++---- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index f7443471e31dd..39c8e9a93f06d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -2,7 +2,7 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths}; use if_chain::if_chain; @@ -12,7 +12,7 @@ use rustc_hir::LangItem::{OptionNone, PollPending}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; -use rustc_span::sym; +use rustc_span::{sym, Symbol, def_id::DefId}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { @@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>( ("is_some()", op_ty) } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if match_def_path(cx, id, &paths::IPADDR_V4) { + } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V4, Item::Diag(sym!(IpAddr), sym!(V4))) { ("is_ipv4()", op_ty) - } else if match_def_path(cx, id, &paths::IPADDR_V6) { + } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V6, Item::Diag(sym!(IpAddr), sym!(V6))) { ("is_ipv6()", op_ty) } else { return; @@ -174,6 +174,7 @@ fn find_sugg_for_if_let<'tcx>( pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { if arms.len() == 2 { + let lang_items = cx.tcx.lang_items(); let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); let found_good_method = match node_pair { @@ -188,7 +189,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::RESULT_OK, + Item::Lang(lang_items.result_ok_variant()), &paths::RESULT_ERR, + Item::Lang(lang_items.result_err_variant()), "is_ok()", "is_err()", ) @@ -199,7 +202,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::IPADDR_V4, + Item::Diag(sym!(IpAddr), sym!(V4)), &paths::IPADDR_V6, + Item::Diag(sym!(IpAddr), sym!(V6)), "is_ipv4()", "is_ipv6()", ) @@ -213,13 +218,16 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( cx, arms, path_left, path_right, &paths::OPTION_SOME, + Item::Lang(lang_items.option_some_variant()), &paths::OPTION_NONE, + Item::Lang(lang_items.option_none_variant()), "is_some()", "is_none()", ) @@ -230,7 +238,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op path_left, path_right, &paths::POLL_READY, + Item::Lang(lang_items.poll_ready_variant()), &paths::POLL_PENDING, + Item::Lang(lang_items.poll_pending_variant()), "is_ready()", "is_pending()", ) @@ -266,28 +276,67 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } } +#[derive(Clone, Copy)] +enum Item { + Lang(Option), + Diag(Symbol, Symbol), +} + +fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_path: &[&str], expected_item: Item) -> bool { + let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; + + // TODO: Path matching can be removed when `IpAddr` is a diagnostic item. + if match_def_path(cx, id, expected_path) { + return true + } + + match expected_item { + Item::Lang(expected_id) => { + Some(cx.tcx.parent(id)) == expected_id + }, + Item::Diag(expected_ty, expected_variant) => { + let ty = cx.typeck_results().pat_ty(pat); + + if is_type_diagnostic_item(cx, ty, expected_ty) { + let variant = ty.ty_adt_def() + .expect("struct pattern type is not an ADT") + .variant_of_res(cx.qpath_res(path, pat.hir_id)); + + return variant.name == expected_variant + } + + false + } + } +} + #[expect(clippy::too_many_arguments)] fn find_good_method_for_match<'a>( cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, - expected_left: &[&str], - expected_right: &[&str], + expected_path_left: &[&str], + expected_item_left: Item, + expected_path_right: &[&str], + expected_item_right: Item, should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let left_id = cx - .typeck_results() - .qpath_res(path_left, arms[0].pat.hir_id) - .opt_def_id()?; - let right_id = cx - .typeck_results() - .qpath_res(path_right, arms[1].pat.hir_id) - .opt_def_id()?; - let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) { + let pat_left = arms[0].pat; + let pat_right = arms[1].pat; + + let body_node_pair = if ( + is_pat_variant(cx, pat_left, path_left, expected_path_left, expected_item_left) + ) && ( + is_pat_variant(cx, pat_right, path_right, expected_path_right, expected_item_right) + ) { (&arms[0].body.kind, &arms[1].body.kind) - } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) { + } else if ( + is_pat_variant(cx, pat_left, path_left, expected_path_right, expected_item_right) + ) && ( + is_pat_variant(cx, pat_right, path_right, expected_path_left, expected_item_left) + ) { (&arms[1].body.kind, &arms[0].body.kind) } else { return None; From 14230a7f8e117aa049d3ae661fa00ded7edefc68 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 12 Sep 2022 19:03:24 +0200 Subject: [PATCH 7/7] Simplify `clippy` fix. --- compiler/rustc_span/src/symbol.rs | 1 + library/std/src/net/ip_addr.rs | 2 - .../src/matches/redundant_pattern_match.rs | 59 +++++++------------ src/tools/clippy/clippy_utils/src/paths.rs | 2 - 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 871bc5c1cdb06..2d4e268118127 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -214,6 +214,7 @@ symbols! { IntoIterator, IoRead, IoWrite, + IpAddr, IrTyKind, Is, ItemContext, diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs index 18cd43a6b8332..4f14fc28038ad 100644 --- a/library/std/src/net/ip_addr.rs +++ b/library/std/src/net/ip_addr.rs @@ -34,11 +34,9 @@ use super::display_buffer::DisplayBuffer; #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum IpAddr { /// An IPv4 address. - #[cfg_attr(not(test), rustc_diagnostic_item = "ip_addr_variant_v4")] #[stable(feature = "ip_addr", since = "1.7.0")] V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), /// An IPv6 address. - #[cfg_attr(not(test), rustc_diagnostic_item = "ip_addr_variant_v6")] #[stable(feature = "ip_addr", since = "1.7.0")] V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), } diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 39c8e9a93f06d..c89784065b8be 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,15 +4,15 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; -use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths}; +use clippy_utils::{higher, is_lang_ctor, is_trait_method}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, PollPending}; +use rustc_hir::LangItem::{self, OptionSome, OptionNone, PollPending, PollReady, ResultOk, ResultErr}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; -use rustc_span::{sym, Symbol, def_id::DefId}; +use rustc_span::{sym, Symbol}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { @@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>( ("is_some()", op_ty) } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V4, Item::Diag(sym!(IpAddr), sym!(V4))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) { ("is_ipv4()", op_ty) - } else if is_pat_variant(cx, check_pat, qpath, &paths::IPADDR_V6, Item::Diag(sym!(IpAddr), sym!(V6))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) { ("is_ipv6()", op_ty) } else { return; @@ -174,7 +174,6 @@ fn find_sugg_for_if_let<'tcx>( pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { if arms.len() == 2 { - let lang_items = cx.tcx.lang_items(); let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); let found_good_method = match node_pair { @@ -188,10 +187,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::RESULT_OK, - Item::Lang(lang_items.result_ok_variant()), - &paths::RESULT_ERR, - Item::Lang(lang_items.result_err_variant()), + Item::Lang(ResultOk), + Item::Lang(ResultErr), "is_ok()", "is_err()", ) @@ -201,10 +198,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::IPADDR_V4, - Item::Diag(sym!(IpAddr), sym!(V4)), - &paths::IPADDR_V6, - Item::Diag(sym!(IpAddr), sym!(V6)), + Item::Diag(sym::IpAddr, sym!(V4)), + Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv4()", "is_ipv6()", ) @@ -224,10 +219,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::OPTION_SOME, - Item::Lang(lang_items.option_some_variant()), - &paths::OPTION_NONE, - Item::Lang(lang_items.option_none_variant()), + Item::Lang(OptionSome), + Item::Lang(OptionNone), "is_some()", "is_none()", ) @@ -237,10 +230,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op arms, path_left, path_right, - &paths::POLL_READY, - Item::Lang(lang_items.poll_ready_variant()), - &paths::POLL_PENDING, - Item::Lang(lang_items.poll_pending_variant()), + Item::Lang(PollReady), + Item::Lang(PollPending), "is_ready()", "is_pending()", ) @@ -278,21 +269,17 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op #[derive(Clone, Copy)] enum Item { - Lang(Option), + Lang(LangItem), Diag(Symbol, Symbol), } -fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_path: &[&str], expected_item: Item) -> bool { +fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool { let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; - // TODO: Path matching can be removed when `IpAddr` is a diagnostic item. - if match_def_path(cx, id, expected_path) { - return true - } - match expected_item { - Item::Lang(expected_id) => { - Some(cx.tcx.parent(id)) == expected_id + Item::Lang(expected_lang_item) => { + let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap(); + cx.tcx.parent(id) == expected_id }, Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); @@ -316,9 +303,7 @@ fn find_good_method_for_match<'a>( arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, - expected_path_left: &[&str], expected_item_left: Item, - expected_path_right: &[&str], expected_item_right: Item, should_be_left: &'a str, should_be_right: &'a str, @@ -327,15 +312,15 @@ fn find_good_method_for_match<'a>( let pat_right = arms[1].pat; let body_node_pair = if ( - is_pat_variant(cx, pat_left, path_left, expected_path_left, expected_item_left) + is_pat_variant(cx, pat_left, path_left, expected_item_left) ) && ( - is_pat_variant(cx, pat_right, path_right, expected_path_right, expected_item_right) + is_pat_variant(cx, pat_right, path_right, expected_item_right) ) { (&arms[0].body.kind, &arms[1].body.kind) } else if ( - is_pat_variant(cx, pat_left, path_left, expected_path_right, expected_item_right) + is_pat_variant(cx, pat_left, path_left, expected_item_right) ) && ( - is_pat_variant(cx, pat_right, path_right, expected_path_left, expected_item_left) + is_pat_variant(cx, pat_right, path_right, expected_item_left) ) { (&arms[1].body.kind, &arms[0].body.kind) } else { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index fb0d34e02eece..07170e2df12ab 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -66,8 +66,6 @@ pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; -pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; -pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];