From 9e90840a6ae4a6f61781bd80adea825d156ddffa Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 26 Dec 2019 19:01:22 +0100 Subject: [PATCH 01/25] Simplify NodeHeader by avoiding slices in BTreeMaps with shared roots --- src/liballoc/collections/btree/map.rs | 6 +-- src/liballoc/collections/btree/node.rs | 55 +++--------------------- src/liballoc/collections/btree/search.rs | 18 ++++---- 3 files changed, 19 insertions(+), 60 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 302c2bcd5e4a3..e70f881bc3d7e 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1968,7 +1968,7 @@ where (i, false) => i, }, (_, Unbounded) => 0, - (true, Included(_)) => min_node.keys().len(), + (true, Included(_)) => min_node.len(), (true, Excluded(_)) => 0, }; @@ -1987,9 +1987,9 @@ where } (i, false) => i, }, - (_, Unbounded) => max_node.keys().len(), + (_, Unbounded) => max_node.len(), (true, Included(_)) => 0, - (true, Excluded(_)) => max_node.keys().len(), + (true, Excluded(_)) => max_node.len(), }; if !diverged { diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index f40e0b0c30479..f190209503d3e 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -54,10 +54,8 @@ pub const CAPACITY: usize = 2 * B - 1; /// `NodeHeader` because we do not want unnecessary padding between `len` and the keys. /// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited /// by `as_header`.) -/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around -/// because the size of `NodeHeader` depends on its alignment! #[repr(C)] -struct NodeHeader { +struct NodeHeader { /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. /// This either points to an actual node or is null. parent: *const InternalNode, @@ -72,9 +70,6 @@ struct NodeHeader { /// This next to `parent_idx` to encourage the compiler to join `len` and /// `parent_idx` into the same 32-bit word, reducing space overhead. len: u16, - - /// See `into_key_slice`. - keys_start: [K2; 0], } #[repr(C)] struct LeafNode { @@ -128,7 +123,7 @@ unsafe impl Sync for NodeHeader<(), ()> {} // We use just a header in order to save space, since no operation on an empty tree will // ever take a pointer past the first key. static EMPTY_ROOT_NODE: NodeHeader<(), ()> = - NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0, keys_start: [] }; + NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0 }; /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an @@ -390,7 +385,7 @@ impl NodeRef { } /// Borrows a view into the keys stored in the node. - /// Works on all possible nodes, including the shared root. + /// The caller must ensure that the node is not the shared root. pub fn keys(&self) -> &[K] { self.reborrow().into_key_slice() } @@ -528,47 +523,9 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { fn into_key_slice(self) -> &'a [K] { - // We have to be careful here because we might be pointing to the shared root. - // In that case, we must not create an `&LeafNode`. We could just return - // an empty slice whenever the length is 0 (this includes the shared root), - // but we want to avoid that run-time check. - // Instead, we create a slice pointing into the node whenever possible. - // We can sometimes do this even for the shared root, as the slice will be - // empty and `NodeHeader` contains an empty `keys_start` array. - // We cannot *always* do this because: - // - `keys_start` is not correctly typed because we want `NodeHeader`'s size to - // not depend on the alignment of `K` (needed because `as_header` should be safe). - // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()` - // and hence just adds a size-0-align-1 field, not affecting layout). - // If the correctly typed header is more highly aligned than the allocated header, - // we cannot transmute safely. - // - Even if we can transmute, the offset of a correctly typed `keys_start` might - // be different and outside the bounds of the allocated header! - // So we do an alignment check and a size check first, that will be evaluated - // at compile-time, and only do any run-time check in the rare case that - // the compile-time checks signal danger. - if (mem::align_of::>() > mem::align_of::>() - || mem::size_of::>() != mem::size_of::>()) - && self.is_shared_root() - { - &[] - } else { - // If we are a `LeafNode`, we can always transmute to - // `NodeHeader` and `keys_start` always has the same offset - // as the actual `keys`. - // Thanks to the checks above, we know that we can transmute to - // `NodeHeader` and that `keys_start` will be - // in-bounds of some allocation even if this is the shared root! - // (We might be one-past-the-end, but that is allowed by LLVM.) - // Thus we can use `NodeHeader` - // to compute the pointer where the keys start. - // This entire hack will become unnecessary once - // lands, then we can just take a raw - // pointer to the `keys` field of `*const InternalNode`. - let header = self.as_header() as *const _ as *const NodeHeader; - let keys = unsafe { &(*header).keys_start as *const _ as *const K }; - unsafe { slice::from_raw_parts(keys, self.len()) } - } + debug_assert!(!self.is_shared_root()); + // We cannot be the shared root, so `as_leaf` is okay. + unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len()) } } /// The caller must ensure that the node is not the shared root. diff --git a/src/liballoc/collections/btree/search.rs b/src/liballoc/collections/btree/search.rs index 48cbf67eea254..25e206f4f73db 100644 --- a/src/liballoc/collections/btree/search.rs +++ b/src/liballoc/collections/btree/search.rs @@ -61,16 +61,18 @@ where { // This function is defined over all borrow types (immutable, mutable, owned), // and may be called on the shared root in each case. - // Crucially, we use `keys()` here, i.e., we work with immutable data. - // `keys_mut()` does not support the shared root, so we cannot use it. // Using `keys()` is fine here even if BorrowType is mutable, as all we return // is an index -- not a reference. - for (i, k) in node.keys().iter().enumerate() { - match key.cmp(k.borrow()) { - Ordering::Greater => {} - Ordering::Equal => return (i, true), - Ordering::Less => return (i, false), + let len = node.len(); + // Skip search for empty nodes because `keys()` does not work on shared roots. + if len > 0 { + for (i, k) in node.keys().iter().enumerate() { + match key.cmp(k.borrow()) { + Ordering::Greater => {} + Ordering::Equal => return (i, true), + Ordering::Less => return (i, false), + } } } - (node.keys().len(), false) + (len, false) } From 34878d7b05813e090b370f48b8d437e4bd875094 Mon Sep 17 00:00:00 2001 From: Vita Batrla Date: Fri, 17 Jan 2020 14:43:36 +0100 Subject: [PATCH 02/25] Options IP_MULTICAST_TTL and IP_MULTICAST_LOOP are 1 byte on BSD and Solaris See ip(4P) man page: IP_MULTICAST_TTL Time to live for multicast datagrams. This option takes an unsigned character as an argument. Its value is the TTL that IP uses on outgoing multi- cast datagrams. The default is 1. IP_MULTICAST_LOOP Loopback for multicast datagrams. Normally multi- cast datagrams are delivered to members on the sending host (or sending zone). Setting the unsigned character argument to 0 causes the oppo- site behavior, meaning that when multiple zones are present, the datagrams are delivered to all zones except the sending zone. https://docs.oracle.com/cd/E88353_01/html/E37851/ip-4p.html https://man.openbsd.org/ip.4 --- src/libstd/sys_common/net.rs | 68 ++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index c7d4828892c04..32e392f1efc86 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -12,6 +12,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use libc::{c_int, c_void}; +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris"))] +use libc::{c_uchar}; #[cfg(not(any( target_os = "dragonfly", @@ -565,24 +569,6 @@ impl UdpSocket { Ok(raw != 0) } - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) - } - - pub fn multicast_loop_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; - Ok(raw != 0) - } - - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; - Ok(raw as u32) - } - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) } @@ -663,6 +649,52 @@ impl UdpSocket { } } +#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris")))] +impl UdpSocket { + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) + } + + pub fn multicast_loop_v4(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + Ok(raw as u32) + } +} + +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris"))] +impl UdpSocket { + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_uchar) + } + + pub fn multicast_loop_v4(&self) -> io::Result { + let raw: c_uchar = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_uchar) + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + let raw: c_uchar = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + Ok(raw as u32) + } +} + impl FromInner for UdpSocket { fn from_inner(socket: Socket) -> UdpSocket { UdpSocket { inner: socket } From dda32e4e535fb3fb9e728b8c96386db7d231b247 Mon Sep 17 00:00:00 2001 From: Vita Batrla Date: Fri, 17 Jan 2020 22:46:32 +0100 Subject: [PATCH 03/25] refactor fix using cfg_if! --- src/libstd/sys_common/net.rs | 175 +++++++++++------------------------ 1 file changed, 55 insertions(+), 120 deletions(-) diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 32e392f1efc86..152da978bfd85 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -12,80 +12,43 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use libc::{c_int, c_void}; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] -use libc::{c_uchar}; - -#[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re" -)))] -use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP; -#[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re" -)))] -use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re" -))] -use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd", - target_os = "netbsd", - target_os = "solaris", - target_os = "haiku", - target_os = "l4re" -))] -use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: c_int = 0x0; + +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "dragonfly", target_os = "freebsd", + target_os = "ios", target_os = "macos", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", target_os = "haiku", target_os = "l4re"))] { + use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + } else { + use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP; + use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; + } +} + +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku"))] { + use libc::MSG_NOSIGNAL; + } else { + const MSG_NOSIGNAL: c_int = 0x0; + } +} + +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris"))] { + type ip_mcast_type_v4 = c_uchar; + } else { + type ip_mcast_type_v4 = c_int; + } +} //////////////////////////////////////////////////////////////////////////////// // sockaddr and misc bindings @@ -569,6 +532,24 @@ impl UdpSocket { Ok(raw != 0) } + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as ip_mcast_type_v4) + } + + pub fn multicast_loop_v4(&self) -> io::Result { + let raw: ip_mcast_type_v4 = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as ip_mcast_type_v4) + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + let raw: ip_mcast_type_v4 = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + Ok(raw as u32) + } + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) } @@ -649,52 +630,6 @@ impl UdpSocket { } } -#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "solaris")))] -impl UdpSocket { - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) - } - - pub fn multicast_loop_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; - Ok(raw != 0) - } - - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; - Ok(raw as u32) - } -} - -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] -impl UdpSocket { - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_uchar) - } - - pub fn multicast_loop_v4(&self) -> io::Result { - let raw: c_uchar = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; - Ok(raw != 0) - } - - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_uchar) - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: c_uchar = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; - Ok(raw as u32) - } -} - impl FromInner for UdpSocket { fn from_inner(socket: Socket) -> UdpSocket { UdpSocket { inner: socket } From 239a7d9124ee486e9d0096429136d719437b83b2 Mon Sep 17 00:00:00 2001 From: Vita Batrla Date: Sat, 18 Jan 2020 00:38:37 +0100 Subject: [PATCH 04/25] refactor fix using cfg_if! (fix build) --- src/libstd/sys_common/net.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 152da978bfd85..7e603a8682ba5 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -44,9 +44,9 @@ cfg_if::cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "solaris"))] { - type ip_mcast_type_v4 = c_uchar; + type IpV4MultiCastType = c_uchar; } else { - type ip_mcast_type_v4 = c_int; + type IpV4MultiCastType = c_int; } } @@ -533,20 +533,30 @@ impl UdpSocket { } pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as ip_mcast_type_v4) + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_LOOP, + multicast_loop_v4 as IpV4MultiCastType, + ) } pub fn multicast_loop_v4(&self) -> io::Result { - let raw: ip_mcast_type_v4 = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; Ok(raw != 0) } pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as ip_mcast_type_v4) + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_TTL, + multicast_ttl_v4 as IpV4MultiCastType, + ) } pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: ip_mcast_type_v4 = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; Ok(raw as u32) } From 766f6c5d0ad5c71f42ab3a305572bf1e7b5edafa Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Fri, 17 Jan 2020 16:11:52 -0800 Subject: [PATCH 05/25] Actually pass target LLVM args to LLVM --- src/librustc_codegen_llvm/llvm_util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 52613fef7e612..4823fe10c463f 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -58,9 +58,10 @@ unsafe fn configure_llvm(sess: &Session) { let cg_opts = sess.opts.cg.llvm_args.iter(); let tg_opts = sess.target.target.options.llvm_args.iter(); + let sess_args = cg_opts.chain(tg_opts); let user_specified_args: FxHashSet<_> = - cg_opts.chain(tg_opts).map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect(); + sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect(); { // This adds the given argument to LLVM. Unless `force` is true @@ -107,7 +108,7 @@ unsafe fn configure_llvm(sess: &Session) { // during inlining. Unfortunately these may block other optimizations. add("-preserve-alignment-assumptions-during-inlining=false", false); - for arg in &sess.opts.cg.llvm_args { + for arg in sess_args { add(&(*arg), true); } } From 01cbe506f99aa484f583a7affb65d15a839d2412 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:23 -0800 Subject: [PATCH 06/25] Add `constness` field to `ast::ItemKind::Impl` --- src/librustc_ast_lowering/item.rs | 6 +++--- src/librustc_ast_passes/ast_validation.rs | 2 ++ src/librustc_builtin_macros/deriving/generic/mod.rs | 1 + src/librustc_builtin_macros/deriving/mod.rs | 1 + src/librustc_parse/parser/item.rs | 2 ++ src/librustc_save_analysis/sig.rs | 4 ++++ src/libsyntax/ast.rs | 1 + src/libsyntax/mut_visit.rs | 1 + src/libsyntax/print/pprust.rs | 9 +++++++++ src/libsyntax/visit.rs | 1 + 10 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 6da2d457f3c3b..170968e71fb35 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -67,9 +67,8 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { if let Some(hir_id) = item_hir_id { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl { ref of_trait, .. } = item.kind { - if of_trait.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); + if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind { + if constness == Constness::Const { this.lctx .diagnostic() .span_err(item.span, "const trait impls are not yet implemented"); @@ -366,6 +365,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unsafety, polarity, defaultness, + constness: _, // TODO generics: ref ast_generics, of_trait: ref trait_ref, self_ty: ref ty, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23701459025ae..23d2858a49966 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -616,6 +616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness: _, + constness: _, // TODO generics: _, of_trait: Some(_), ref self_ty, @@ -649,6 +650,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness, + constness: _, // TODO generics: _, of_trait: None, self_ty: _, diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index d346dbc8b4ee7..f8918016c1b98 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -709,6 +709,7 @@ impl<'a> TraitDef<'a> { unsafety, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, + constness: ast::Constness::NotConst, generics: trait_generics, of_trait: opt_trait_ref, self_ty: self_type, diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 9aa7623dc9f77..914dcdf196921 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -160,6 +160,7 @@ fn inject_impl_of_structural_trait( unsafety: ast::Unsafety::Normal, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, + constness: ast::Constness::NotConst, generics, of_trait: Some(trait_ref), self_ty: self_type, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 1921a6c850689..e4982896376d6 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -638,6 +638,7 @@ impl<'a> Parser<'a> { unsafety, polarity, defaultness, + constness, generics, of_trait: Some(trait_ref), self_ty: ty_second, @@ -657,6 +658,7 @@ impl<'a> Parser<'a> { unsafety, polarity, defaultness, + constness, generics, of_trait: None, self_ty: ty_first, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 779d3f55018d5..a9d2bfabb1ba6 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -486,6 +486,7 @@ impl Sig for ast::Item { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -499,6 +500,9 @@ impl Sig for ast::Item { text.push_str("unsafe "); } text.push_str("impl"); + if constness == ast::Constness::Const { + text.push_str(" const"); + } let generics_sig = generics.make(offset + text.len(), id, scx)?; text.push_str(&generics_sig.text); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a5a4eb1583bed..6b54893075e7b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2618,6 +2618,7 @@ pub enum ItemKind { unsafety: Unsafety, polarity: ImplPolarity, defaultness: Defaultness, + constness: Constness, generics: Generics, /// The trait being implemented, if any. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 750d054e8a0f2..8f82ff6b040a6 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -922,6 +922,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { unsafety: _, polarity: _, defaultness: _, + constness: _, generics, of_trait, self_ty, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bc67980c454c0..3927e4f903011 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1230,6 +1230,7 @@ impl<'a> State<'a> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -1240,6 +1241,7 @@ impl<'a> State<'a> { self.print_defaultness(defaultness); self.print_unsafety(unsafety); self.word_nbsp("impl"); + self.print_constness(constness); if !generics.params.is_empty() { self.print_generic_params(&generics.params); @@ -2773,6 +2775,13 @@ impl<'a> State<'a> { } } + crate fn print_constness(&mut self, s: ast::Constness) { + match s { + ast::Constness::Const => self.word_nbsp("const"), + ast::Constness::NotConst => {} + } + } + crate fn print_is_auto(&mut self, s: ast::IsAuto) { match s { ast::IsAuto::Yes => self.word_nbsp("auto"), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index d03a9dfc16758..946a0d29cd399 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -312,6 +312,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { unsafety: _, polarity: _, defaultness: _, + constness: _, ref generics, ref of_trait, ref self_ty, From a790f9bb2d277b5c7c267b15b812db12cc20b7a1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:24 -0800 Subject: [PATCH 07/25] Add `constness` field to `hir::ItemKind::Impl` --- src/librustc_ast_lowering/item.rs | 3 ++- src/librustc_hir/hir.rs | 1 + src/librustc_hir/intravisit.rs | 1 + src/librustc_hir/print.rs | 5 +++++ src/librustdoc/doctree.rs | 1 + src/librustdoc/visit_ast.rs | 2 ++ 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 170968e71fb35..c47a0f4eaca6c 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -365,7 +365,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unsafety, polarity, defaultness, - constness: _, // TODO + constness, generics: ref ast_generics, of_trait: ref trait_ref, self_ty: ref ty, @@ -422,6 +422,7 @@ impl<'hir> LoweringContext<'_, 'hir> { unsafety, polarity, defaultness: self.lower_defaultness(defaultness, true /* [1] */), + constness, generics, of_trait: trait_ref, self_ty: lowered_ty, diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 1fef871b5140e..d850cfe69cebe 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2440,6 +2440,7 @@ pub enum ItemKind<'hir> { unsafety: Unsafety, polarity: ImplPolarity, defaultness: Defaultness, + constness: Constness, generics: Generics<'hir>, /// The trait being implemented, if any. diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 1a73e41db9da5..539a0eee0e312 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -570,6 +570,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { unsafety: _, defaultness: _, polarity: _, + constness: _, ref generics, ref of_trait, ref self_ty, diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index 6c7d419395317..b9598c9376146 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -631,6 +631,7 @@ impl<'a> State<'a> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, ref self_ty, @@ -647,6 +648,10 @@ impl<'a> State<'a> { self.s.space(); } + if constness == ast::Constness::Const { + self.word_nbsp("const"); + } + if let hir::ImplPolarity::Negative = polarity { self.s.word("!"); } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 178ba69277233..218674b757f39 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -203,6 +203,7 @@ pub struct Impl<'hir> { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, pub defaultness: hir::Defaultness, + pub constness: ast::Constness, pub generics: &'hir hir::Generics<'hir>, pub trait_: &'hir Option>, pub for_: &'hir hir::Ty<'hir>, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index fdff18779e795..d3d45ccccad36 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -562,6 +562,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { unsafety, polarity, defaultness, + constness, ref generics, ref of_trait, self_ty, @@ -576,6 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { unsafety, polarity, defaultness, + constness, generics, trait_: of_trait, for_: self_ty, From 958b0bc8d22633927796502b13a7ce944100dec5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:25 -0800 Subject: [PATCH 08/25] Store `impl const` in `ItemKind::Impl` --- src/librustc_ast_passes/ast_validation.rs | 10 ++++++++-- src/librustc_parse/parser/item.rs | 16 ++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23d2858a49966..7dbd2362f04c9 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -616,7 +616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness: _, - constness: _, // TODO + constness: _, generics: _, of_trait: Some(_), ref self_ty, @@ -650,7 +650,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness, - constness: _, // TODO + constness, generics: _, of_trait: None, self_ty: _, @@ -678,6 +678,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default") .emit(); } + if constness == Constness::Const { + self.err_handler() + .struct_span_err(item.span, "inherent impls cannot be `const`") + .note("only trait implementations may be annotated with `const`") + .emit(); + } } ItemKind::Fn(ref sig, ref generics, _) => { self.visit_fn_header(&sig.header); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index e4982896376d6..43495da192839 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_error_codes::*; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey}; -use rustc_span::source_map::{self, respan, Span, Spanned}; +use rustc_span::source_map::{self, respan, Span}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; @@ -566,9 +566,9 @@ impl<'a> Parser<'a> { let constness = if self.eat_keyword(kw::Const) { let span = self.prev_span; self.sess.gated_spans.gate(sym::const_trait_impl, span); - Some(respan(span, Constness::Const)) + Constness::Const } else { - None + Constness::NotConst }; // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. @@ -631,8 +631,7 @@ impl<'a> Parser<'a> { err_path(ty_first.span) } }; - let constness = constness.map(|c| c.node); - let trait_ref = TraitRef { path, constness, ref_id: ty_first.id }; + let trait_ref = TraitRef { path, ref_id: ty_first.id }; ItemKind::Impl { unsafety, @@ -646,13 +645,6 @@ impl<'a> Parser<'a> { } } None => { - // Reject `impl const Type {}` here - if let Some(Spanned { node: Constness::Const, span }) = constness { - self.struct_span_err(span, "`const` cannot modify an inherent impl") - .help("only a trait impl can be `const`") - .emit(); - } - // impl Type ItemKind::Impl { unsafety, From eb60346cc99bde574708fe2e419898044868c1f8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:27 -0800 Subject: [PATCH 09/25] Add `MaybeConst` variant to `{ast,hir}::TraitBoundModifier` --- src/librustc_ast_lowering/lib.rs | 8 +++--- src/librustc_ast_passes/ast_validation.rs | 20 +++----------- src/librustc_hir/hir.rs | 1 + src/librustc_parse/parser/ty.rs | 33 ++++++++++++++++------- src/librustdoc/html/format.rs | 1 + src/libsyntax/ast.rs | 11 ++++++-- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 76a0889c376a2..90560c371e292 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1250,7 +1250,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bounds = this.arena.alloc_from_iter(bounds.iter().filter_map( |bound| match *bound { - GenericBound::Trait(ref ty, TraitBoundModifier::None) => { + GenericBound::Trait(ref ty, TraitBoundModifier::None) + | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => { Some(this.lower_poly_trait_ref(ty, itctx.reborrow())) } GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, @@ -2158,10 +2159,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { - if p.trait_ref.constness.is_some() { - self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented"); - } - let bound_generic_params = self.lower_generic_params( &p.bound_generic_params, &NodeMap::default(), @@ -2301,6 +2298,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match f { TraitBoundModifier::None => hir::TraitBoundModifier::None, TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, + TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 7dbd2362f04c9..23cb97348339d 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -917,22 +917,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound) { - if let GenericBound::Trait(poly, maybe_bound) = bound { - match poly.trait_ref.constness { - Some(Constness::NotConst) => { - if *maybe_bound == TraitBoundModifier::Maybe { - self.err_handler() - .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); - } - - if let Some(ctx) = self.bound_context { - let msg = format!("`?const` is not permitted in {}", ctx.description()); - self.err_handler().span_err(bound.span(), &msg); - } - } - - Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"), - None => {} + if let GenericBound::Trait(_, TraitBoundModifier::MaybeConst) = bound { + if let Some(ctx) = self.bound_context { + let msg = format!("`?const` is not permitted in {}", ctx.description()); + self.err_handler().span_err(bound.span(), &msg); } } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index d850cfe69cebe..b62a7e413e303 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -364,6 +364,7 @@ impl GenericArgs<'_> { pub enum TraitBoundModifier { None, Maybe, + MaybeConst, } /// The AST represents all type param bounds as types. diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 065a3b14428c7..9c9180778e522 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -27,11 +27,17 @@ struct BoundModifiers { } impl BoundModifiers { - fn trait_bound_modifier(&self) -> TraitBoundModifier { - match self.maybe { - Some(_) => TraitBoundModifier::Maybe, - None => TraitBoundModifier::None, - } + fn to_trait_bound_modifier(&self) -> Result { + let modifier = match (self.maybe, self.maybe_const) { + (None, None) => TraitBoundModifier::None, + (Some(_), None) => TraitBoundModifier::Maybe, + (None, Some(_)) => TraitBoundModifier::MaybeConst, + (Some(_), Some(_)) => { + return Err("`?const` and `?` are mutually exclusive"); + } + }; + + Ok(modifier) } } @@ -215,7 +221,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, TyKind> { assert_ne!(self.token, token::Question); - let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span)); + let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded @@ -557,9 +563,18 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; } - let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst); - let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span)); - Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier())) + let modifier = match modifiers.to_trait_bound_modifier() { + Ok(m) => m, + Err(msg) => { + self.struct_span_err(lo.to(self.prev_span), msg).emit(); + + // Continue compilation as if the user had written `?Trait`. + TraitBoundModifier::Maybe + } + }; + + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + Ok(GenericBound::Trait(poly_trait, modifier)) } /// Optionally parses `for<$generic_params>`. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6434dccdfc75b..79923fc3d3689 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -361,6 +361,7 @@ impl clean::GenericBound { let modifier_str = match modifier { hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::Maybe => "?", + hir::TraitBoundModifier::MaybeConst => "?const", }; if f.alternate() { write!(f, "{}{:#}", modifier_str, ty.print()) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6b54893075e7b..ce4d9cca81eb3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -266,12 +266,19 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0); /// small, positive ids. pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; -/// A modifier on a bound, currently this is only used for `?Sized`, where the -/// modifier is `Maybe`. Negative bounds should also be handled here. +/// A modifier on a bound, e.g., `?Sized` or `?const Trait`. +/// +/// Negative bounds should also be handled here. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] pub enum TraitBoundModifier { + /// No modifiers None, + + /// `?Trait` Maybe, + + /// `?const Trait` + MaybeConst, } /// The AST represents all type param bounds as types. From 1a3bd5775f8b8a1354ec703acf3a3a07e5f8b7c2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:29 -0800 Subject: [PATCH 10/25] Revert "Add a `constness` field to `ast::TraitRef`" This reverts commit fd4a6a12136c5b5d6bce4081e95890df1fd1febd. --- src/librustc_expand/build.rs | 2 +- src/libsyntax/ast.rs | 20 +++----------------- src/libsyntax/mut_visit.rs | 3 +-- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index bd3d6b589d00a..11f94ab2e6279 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -110,7 +110,7 @@ impl<'a> ExtCtxt<'a> { } pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { - ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID } + ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID } } pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ce4d9cca81eb3..7c2608a0c2a31 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1040,7 +1040,7 @@ impl Expr { pub fn to_bound(&self) -> Option { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( - PolyTraitRef::new(Vec::new(), path.clone(), None, self.span), + PolyTraitRef::new(Vec::new(), path.clone(), self.span), TraitBoundModifier::None, )), _ => None, @@ -2383,15 +2383,6 @@ pub enum AttrKind { pub struct TraitRef { pub path: Path, pub ref_id: NodeId, - - /// The `const` modifier, if any, that appears before this trait. - /// - /// | | `constness` | - /// |----------------|-----------------------------| - /// | `Trait` | `None` | - /// | `const Trait` | `Some(Constness::Const)` | - /// | `?const Trait` | `Some(Constness::NotConst)` | - pub constness: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2406,15 +2397,10 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new( - generic_params: Vec, - path: Path, - constness: Option, - span: Span, - ) -> Self { + pub fn new(generic_params: Vec, path: Path, span: Span) -> Self { PolyTraitRef { bound_generic_params: generic_params, - trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID }, + trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, span, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 8f82ff6b040a6..4a460c5d7b24c 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -838,8 +838,7 @@ pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut } } -pub fn noop_visit_trait_ref(tr: &mut TraitRef, vis: &mut T) { - let TraitRef { path, ref_id, constness: _ } = tr; +pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { vis.visit_path(path); vis.visit_id(ref_id); } From ab3081a70e5d402188c26c6f3e671a3c44812d1b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:31 -0800 Subject: [PATCH 11/25] Add `constness` field to `ty::Predicate::Trait` --- src/librustc/traits/auto_trait.rs | 9 +++++--- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/object_safety.rs | 4 ++-- .../traits/query/type_op/prove_predicate.rs | 2 +- src/librustc/traits/select.rs | 10 +++++---- src/librustc/traits/util.rs | 8 +++---- src/librustc/traits/wf.rs | 4 ++-- src/librustc/ty/fold.rs | 9 ++++++++ src/librustc/ty/mod.rs | 21 ++++++++++++------- src/librustc/ty/print/pretty.rs | 7 ++++++- src/librustc/ty/structural_impls.rs | 12 +++++++++-- src/librustc_lint/unused.rs | 2 +- .../borrow_check/type_check/mod.rs | 21 ++++++++++++------- .../transform/qualify_min_const_fn.rs | 11 ++++++++-- src/librustc_privacy/lib.rs | 2 +- src/librustc_traits/lowering/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 8 +++---- src/librustc_typeck/collect.rs | 4 ++-- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/simplify.rs | 2 +- src/libsyntax/ast.rs | 3 ++- 27 files changed, 104 insertions(+), 55 deletions(-) diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 89b28aeda1c5e..c97c5c2077f85 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -337,7 +337,10 @@ impl AutoTraitFinder<'tcx> { &Err(SelectionError::Unimplemented) => { if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { already_visited.remove(&pred); - self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred)); + self.add_user_pred( + &mut user_computed_preds, + ty::Predicate::Trait(pred, ast::Constness::NotConst), + ); predicates.push_back(pred); } else { debug!( @@ -405,7 +408,7 @@ impl AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { match (&new_pred, old_pred) { - (&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => { + (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; let old_substs = old_trait.skip_binder().trait_ref.substs; @@ -627,7 +630,7 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match &predicate { - &ty::Predicate::Trait(p) => { + &ty::Predicate::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9e5abc80822c7..1dbf53003585f 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -331,7 +331,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_obligation = obligation.with(data.clone()); if data.is_global() { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ce57fb8110496..ad6b821b1d771 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -234,7 +234,7 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref)) .any(|predicate| { match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. data.skip_binder().input_types().skip(1).any(has_self_ty) } @@ -285,7 +285,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate_predicates(tcx, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred) => { + ty::Predicate::Trait(ref trait_pred, _) => { trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) } ty::Predicate::Projection(..) diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index c0a0cbe9a3876..15870ec95d8d2 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -24,7 +24,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let Predicate::Trait(trait_ref) = key.value.predicate { + if let Predicate::Trait(trait_ref, _) = key.value.predicate { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized_def_id { if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3bfe542baabbf..9db907e88fab8 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -51,7 +51,7 @@ use std::cmp; use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; -use syntax::attr; +use syntax::{ast, attr}; pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -718,7 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) @@ -945,7 +945,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // trait refs. This is important because it's only a cycle // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); + let cycle = cycle.map(|stack| { + ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst) + }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); Some(EvaluatedToOk) @@ -1060,7 +1062,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate { - ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()), + ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; debug!("coinductive_predicate({:?}) = {:?}", predicate, result); diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index f058a4d2df24a..a5a16a1471225 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,8 +13,8 @@ use super::{Normalized, Obligation, ObligationCause, PredicateObligation, Select fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => { - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)) + ty::Predicate::Trait(ref data, constness) => { + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) } ty::Predicate::RegionOutlives(ref data) => { @@ -127,7 +127,7 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { let tcx = self.visited.tcx; match *predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -471,7 +471,7 @@ impl<'tcx, I: Iterator>> Iterator for FilterToTraits< fn next(&mut self) -> Option> { while let Some(pred) = self.base_iterator.next() { - if let ty::Predicate::Trait(data) = pred { + if let ty::Predicate::Trait(data, _) = pred { return Some(data.to_poly_trait_ref()); } } diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index 869ba5315c1ae..aba09c3c81850 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -62,7 +62,7 @@ pub fn predicate_obligations<'a, 'tcx>( // (*) ok to skip binders, because wf code is prepared for it match *predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } ty::Predicate::RegionOutlives(..) => {} @@ -245,7 +245,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } } - ty::Predicate::Trait(proj) => { + ty::Predicate::Trait(proj, _) => { // An associated item obligation born out of the `trait` failed to be met. // Point at the `impl` that failed the obligation, the associated item that // needed to meet the obligation, and the definition of that associated item, diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index b16db6ae5b18d..0dddca98c6257 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -150,6 +150,15 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } +impl TypeFoldable<'tcx> for syntax::ast::Constness { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// The `TypeFolder` trait defines the actual *folding*. There is a /// method defined for every foldable type. Each of these has a /// default implementation that does an "identity" fold. Within each diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3040ecf90ed53..c5fbf2896a4a1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1068,7 +1068,11 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. - Trait(PolyTraitPredicate<'tcx>), + /// + /// A trait predicate will have `Constness::Const` if it originates + /// from a bound on a `const fn` without the `?const` opt-out (e.g., + /// `const fn foobar() {}`). + Trait(PolyTraitPredicate<'tcx>, ast::Constness), /// `where 'a: 'b` RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), @@ -1191,8 +1195,8 @@ impl<'tcx> Predicate<'tcx> { let substs = &trait_ref.skip_binder().substs; match *self { - Predicate::Trait(ref binder) => { - Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs))) + Predicate::Trait(ref binder, constness) => { + Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } Predicate::Subtype(ref binder) => { Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) @@ -1338,13 +1342,16 @@ pub trait ToPredicate<'tcx> { impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() })) + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() }), + ast::Constness::NotConst, + ) } } impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) + ty::Predicate::Trait(self.to_poly_trait_predicate(), ast::Constness::NotConst) } } @@ -1413,7 +1420,7 @@ impl<'tcx> Predicate<'tcx> { /// with depth 0 are bound by the predicate. pub fn walk_tys(&'a self) -> impl Iterator> + 'a { match *self { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { @@ -1439,7 +1446,7 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { - Predicate::Trait(ref t) => Some(t.to_poly_trait_ref()), + Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), Predicate::Projection(..) | Predicate::Subtype(..) | Predicate::RegionOutlives(..) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8b1b2bb586597..9091de55b7d8e 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1791,7 +1791,12 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match *self { - ty::Predicate::Trait(ref data) => p!(print(data)), + ty::Predicate::Trait(ref data, constness) => { + if let ast::Constness::Const = constness { + p!(write("const ")); + } + p!(print(data)) + } ty::Predicate::Subtype(ref predicate) => p!(print(predicate)), ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)), ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 62e895af7f355..25f9dc5b0c7bf 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -15,6 +15,7 @@ use smallvec::SmallVec; use std::fmt; use std::rc::Rc; use std::sync::Arc; +use syntax::ast; impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -234,7 +235,12 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> { impl fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Predicate::Trait(ref a) => a.fmt(f), + ty::Predicate::Trait(ref a, constness) => { + if let ast::Constness::Const = constness { + write!(f, "const ")?; + } + a.fmt(f) + } ty::Predicate::Subtype(ref pair) => pair.fmt(f), ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f), ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f), @@ -474,7 +480,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { - ty::Predicate::Trait(ref binder) => tcx.lift(binder).map(ty::Predicate::Trait), + ty::Predicate::Trait(ref binder, constness) => { + tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness)) + } ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype), ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 26cbda3d97895..15158c09af074 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in cx.tcx.predicates_of(def).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { + if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; let descr_pre = diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 947bbef4379f5..8f00801eb25a3 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -33,6 +33,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::{Span, DUMMY_SP}; +use syntax::ast; use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; @@ -1931,12 +1932,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { traits::ObligationCauseCode::RepeatVec(should_suggest), ), self.param_env, - ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate { - trait_ref: ty::TraitRef::new( - self.tcx().lang_items().copy_trait().unwrap(), - tcx.mk_substs_trait(ty, &[]), - ), - })), + ty::Predicate::Trait( + ty::Binder::bind(ty::TraitPredicate { + trait_ref: ty::TraitRef::new( + self.tcx().lang_items().copy_trait().unwrap(), + tcx.mk_substs_trait(ty, &[]), + ), + }), + ast::Constness::NotConst, + ), ), &traits::SelectionError::Unimplemented, false, @@ -2574,7 +2578,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) { self.prove_predicates( - Some(ty::Predicate::Trait(trait_ref.to_poly_trait_ref().to_poly_trait_predicate())), + Some(ty::Predicate::Trait( + trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), + ast::Constness::NotConst, + )), locations, category, ); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index d927553c72e8b..b047e534e4f1c 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::borrow::Cow; -use syntax::attr; +use syntax::{ast, attr}; type McfResult = Result<(), (Span, Cow<'static, str>)>; @@ -27,12 +27,19 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - bug!("closure kind predicate on function: {:#?}", predicate) } Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate), - Predicate::Trait(pred) => { + Predicate::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } match pred.skip_binder().self_ty().kind { ty::Param(ref p) => { + // Allow `T: ?const Trait` + if *constness == ast::Constness::NotConst + && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) + { + continue; + } + let generics = tcx.generics_of(current); let def = generics.type_param(p, tcx); let span = tcx.def_span(def.def_id); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 90a422a4dcf6c..4b2e90ed83de2 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -93,7 +93,7 @@ where let ty::GenericPredicates { parent: _, predicates } = predicates; for (predicate, _span) in predicates { match predicate { - ty::Predicate::Trait(poly_predicate) => { + ty::Predicate::Trait(poly_predicate, _) => { let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder(); if self.visit_trait(trait_ref) { return true; diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 4b4fa4b7147fc..b77c603da9a74 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -94,7 +94,7 @@ impl<'tcx> Lower> for ty::Predicate<'tcx> { use rustc::ty::Predicate; match self { - Predicate::Trait(predicate) => predicate.lower(), + Predicate::Trait(predicate, _) => predicate.lower(), Predicate::RegionOutlives(predicate) => predicate.lower(), Predicate::TypeOutlives(predicate) => predicate.lower(), Predicate::Projection(predicate) => predicate.lower(), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 173bb29e964d1..7f196b2c4d352 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1490,7 +1490,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref ); match trait_ref { - ty::Predicate::Trait(pred) => { + ty::Predicate::Trait(pred, constness) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) .filter(|item| item.kind == ty::AssocKind::Type) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a32fbff7bfe2d..087b720a2f4c4 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -565,7 +565,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => { if unsize_did == tr.def_id() { let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; if let ty::Tuple(..) = sty { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88e7a265ebbcf..a88dca008d751 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -234,7 +234,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate, p) { - (Predicate::Trait(a), Predicate::Trait(b)) => relator.relate(a, b).is_ok(), + (Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(), (Predicate::Projection(a), Predicate::Projection(b)) => { relator.relate(a, b).is_ok() } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 636ea5b87d659..2012a2a1526b1 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate_predicates(self.tcx, predicates.predicates.clone()) .filter_map(|predicate| match predicate { - ty::Predicate::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => { + ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { Some(trait_pred) } _ => None, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b2542cc27a551..67526bb70d125 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -826,7 +826,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // FIXME: do we want to commit to this behavior for param bounds? let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate { - ty::Predicate::Trait(ref trait_predicate) => { + ty::Predicate::Trait(ref trait_predicate, _) => { match trait_predicate.skip_binder().trait_ref.self_ty().kind { ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()), _ => None, @@ -1430,7 +1430,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - if let &ty::Predicate::Trait(ref pred) = &o.predicate { + if let &ty::Predicate::Trait(ref pred, _) = &o.predicate { possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4affdc4a9d64e..7c1876f5d449c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2623,7 +2623,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { parent: None, predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map( |&predicate| match predicate { - ty::Predicate::Trait(ref data) + ty::Predicate::Trait(ref data, _) if data.skip_binder().self_ty().is_param(index) => { // HACK(eddyb) should get the original `Span`. @@ -3695,7 +3695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Predicate::Projection(ref data) => { Some((data.to_poly_trait_ref(self.tcx), obligation)) } - ty::Predicate::Trait(ref data) => Some((data.to_poly_trait_ref(), obligation)), + ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)), ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, @@ -3998,7 +3998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - if let ty::Predicate::Trait(predicate) = error.obligation.predicate { + if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. let mut referenced_in = final_arg_types @@ -4042,7 +4042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::Path(qpath) = &path.kind { if let hir::QPath::Resolved(_, path) = &qpath { for error in errors { - if let ty::Predicate::Trait(predicate) = error.obligation.predicate { + if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { // If any of the type arguments in this path segment caused the // `FullfillmentError`, point at its span (#61860). for arg in path diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a03b9f747372e..35f9a4fa68e11 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -432,7 +432,7 @@ fn type_param_predicates( icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) .into_iter() .filter(|(predicate, _)| match predicate { - ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index), + ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index), _ => false, }), ); @@ -857,7 +857,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi // which will, in turn, reach indirect supertraits. for &(pred, span) in superbounds { debug!("superbound: {:?}", pred); - if let ty::Predicate::Trait(bound) = pred { + if let ty::Predicate::Trait(bound, _) = pred { tcx.at(span).super_predicates_of(bound.def_id()); } } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index f37f6921cebaf..27f8059691a14 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .filter(|p| { !orig_bounds.contains(p) || match p { - &&ty::Predicate::Trait(pred) => pred.def_id() == sized_trait, + ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait, _ => false, } }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20a5a6c54984d..7a7d69c68a585 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -482,7 +482,7 @@ impl<'a> Clean> for ty::Predicate<'a> { use rustc::ty::Predicate; match *self { - Predicate::Trait(ref pred) => Some(pred.clean(cx)), + Predicate::Trait(ref pred, _) => Some(pred.clean(cx)), Predicate::Subtype(ref pred) => Some(pred.clean(cx)), Predicate::RegionOutlives(ref pred) => pred.clean(cx), Predicate::TypeOutlives(ref pred) => pred.clean(cx), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index c7b12d38c430a..2b59c60f0b77f 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -141,7 +141,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::Predicate::Trait(ref pred) = *pred { + if let ty::Predicate::Trait(ref pred, _) = *pred { if pred.skip_binder().trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7c2608a0c2a31..88bfb8ccb9525 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2165,7 +2165,8 @@ impl IsAsync { } } -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(HashStable_Generic)] pub enum Constness { Const, NotConst, From d2aefbb286c94240e25cbe0b8cc92a1336db5408 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:32 -0800 Subject: [PATCH 12/25] Add `ConstnessAnd` that implements `ToPredicate` --- src/librustc/traits/engine.rs | 4 +- src/librustc/traits/error_reporting/mod.rs | 28 ++++++---- .../traits/error_reporting/suggestions.rs | 17 +++--- src/librustc/traits/mod.rs | 4 +- src/librustc/traits/object_safety.rs | 6 +- src/librustc/traits/project.rs | 11 +++- src/librustc/traits/select.rs | 4 +- src/librustc/traits/util.rs | 25 +++++---- src/librustc/traits/wf.rs | 10 +++- src/librustc/ty/mod.rs | 56 ++++++++++++++++--- src/librustc/ty/sty.rs | 10 +++- src/librustc_ty/ty.rs | 3 +- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/autoderef.rs | 9 ++- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 4 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 7 ++- src/librustc_typeck/collect.rs | 12 ++-- src/librustdoc/clean/blanket_impl.rs | 4 +- 21 files changed, 155 insertions(+), 74 deletions(-) diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 5b804480119fe..84bfc86e6a94e 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -1,6 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use crate::ty::{self, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_hir::def_id::DefId; use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError}; @@ -33,7 +33,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }, ); } diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index db3173989ac60..2d02dbf823006 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -19,7 +19,9 @@ use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; use crate::ty::fold::TypeFolder; use crate::ty::SubtypePredicate; -use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{ + self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -130,7 +132,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error), + (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), _ => { // FIXME: make this work in other cases too. return false; @@ -138,7 +140,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) { - if let ty::Predicate::Trait(implication) = implication { + if let ty::Predicate::Trait(implication, _) = implication { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); // FIXME: I'm just not taking associated types at all here. @@ -530,7 +532,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { + ty::Predicate::Trait(ref trait_predicate, _) => { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { @@ -583,7 +585,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{}", message.unwrap_or_else(|| format!( "the trait bound `{}` is not satisfied{}", - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), post_message, )) ); @@ -695,7 +697,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_pred }); let unit_obligation = Obligation { - predicate: ty::Predicate::Trait(predicate), + predicate: ty::Predicate::Trait( + predicate, + ast::Constness::NotConst, + ), ..obligation.clone() }; if self.predicate_may_hold(&unit_obligation) { @@ -988,7 +993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> PredicateObligation<'tcx> { let new_trait_ref = ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.to_predicate()) + Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) } } @@ -1076,7 +1081,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let mut err = match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); @@ -1269,8 +1274,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) .value; - let obligation = - Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate()); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + cleaned_pred.without_const().to_predicate(), + ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index c09fd3079731c..9d8fa362ebbd9 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -6,7 +6,7 @@ use super::{ use crate::infer::InferCtxt; use crate::traits::object_safety::object_safety_violations; use crate::ty::TypeckTables; -use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, @@ -50,7 +50,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } else { " where" }, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), ), Applicability::MachineApplicable, ); @@ -340,8 +340,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); - let new_obligation = - Obligation::new(ObligationCause::dummy(), param_env, new_trait_ref.to_predicate()); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + new_trait_ref.without_const().to_predicate(), + ); if self.predicate_must_hold_modulo_regions(&new_obligation) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument @@ -1122,7 +1125,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // the type. The last generator has information about where the bound was introduced. At // least one generator should be present for this diagnostic to be modified. let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p) => { + ty::Predicate::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) } _ => (None, None), @@ -1545,7 +1548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required because it appears within the type `{}`", ty)); obligated_types.push(ty); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); if !self.is_recursive_obligation(obligated_types, &data.parent_code) { self.note_obligation_cause_code( err, @@ -1562,7 +1565,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { parent_trait_ref.print_only_trait_path(), parent_trait_ref.skip_binder().self_ty() )); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); self.note_obligation_cause_code( err, &parent_predicate, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 2e5da2b038254..7819366f8927d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -29,7 +29,7 @@ use crate::mir::interpret::ErrorHandled; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness}; use crate::util::common::ErrorReported; use chalk_engine; use rustc_hir as hir; @@ -732,7 +732,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( param_env, cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), recursion_depth: 0, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let result = infcx.predicate_must_hold_modulo_regions(&obligation); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ad6b821b1d771..15f81bb3f47ed 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -12,7 +12,7 @@ use super::elaborate_predicates; use crate::traits::{self, Obligation, ObligationCause}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -585,6 +585,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), } + .without_const() .to_predicate(); // U: Trait @@ -598,7 +599,7 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.to_predicate() + ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() }; let caller_bounds: Vec> = param_env @@ -620,6 +621,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), } + .without_const() .to_predicate(); Obligation::new(ObligationCause::dummy(), param_env, predicate) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 5bc211ade40ad..62672a7810480 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -16,7 +16,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -738,7 +738,12 @@ fn get_paranoid_cache_value_obligation<'a, 'tcx>( depth: usize, ) -> PredicateObligation<'tcx> { let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() } + Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.without_const().to_predicate(), + } } /// If we are projecting `::Item`, but `T: Trait` does not @@ -772,7 +777,7 @@ fn normalize_to_error<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9db907e88fab8..ac1ca4db9d6bb 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -37,7 +37,7 @@ use crate::middle::lang_items; use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -3368,7 +3368,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx.require_lang_item(lang_items::SizedTraitLangItem, None), tcx.mk_substs_trait(source, &[]), ); - nested.push(predicate_to_obligation(tr.to_predicate())); + nested.push(predicate_to_obligation(tr.without_const().to_predicate())); // If the type is `Foo + 'a`, ensure that the type // being cast to `Foo + 'a` outlives `'a`: diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index a5a16a1471225..f3bd98b855190 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -4,7 +4,7 @@ use smallvec::SmallVec; use crate::ty::outlives::Component; use crate::ty::subst::{GenericArg, Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -99,14 +99,14 @@ pub fn elaborate_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Elaborator<'tcx> { - elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) + elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) } pub fn elaborate_trait_refs<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect(); + let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); elaborate_predicates(tcx, predicates) } @@ -358,7 +358,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { let tcx = self.tcx; let trait_ref = item.trait_ref(); - let pred = trait_ref.to_predicate(); + let pred = trait_ref.without_const().to_predicate(); debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); @@ -370,13 +370,9 @@ impl<'tcx> TraitAliasExpander<'tcx> { // Don't recurse if this trait alias is already on the stack for the DFS search. let anon_pred = anonymize_predicate(tcx, &pred); - if item - .path - .iter() - .rev() - .skip(1) - .any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred) - { + if item.path.iter().rev().skip(1).any(|(tr, _)| { + anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred + }) { return false; } @@ -545,7 +541,12 @@ pub fn predicate_for_trait_ref<'tcx>( trait_ref: ty::TraitRef<'tcx>, recursion_depth: usize, ) -> PredicateObligation<'tcx> { - Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() } + Obligation { + cause, + param_env, + recursion_depth, + predicate: trait_ref.without_const().to_predicate(), + } } pub fn predicate_for_trait_def( diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index aba09c3c81850..a0cb8446c9217 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -3,7 +3,7 @@ use crate::infer::InferCtxt; use crate::middle::lang_items; use crate::traits::{self, AssocTypeBoundData}; use crate::ty::subst::SubstsRef; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Ident}; @@ -350,7 +350,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.compute_trait_ref(&trait_ref, Elaborate::None); if !data.has_escaping_bound_vars() { - let predicate = trait_ref.to_predicate(); + let predicate = trait_ref.without_const().to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -378,7 +378,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; - self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + trait_ref.without_const().to_predicate(), + )); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c5fbf2896a4a1..0470ab20dc464 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -52,7 +52,7 @@ use std::ops::Deref; use std::ops::Range; use std::slice; use std::{mem, ptr}; -use syntax::ast::{self, Ident, Name, NodeId}; +use syntax::ast::{self, Constness, Ident, Name, NodeId}; use syntax::attr; pub use self::sty::BoundRegion::*; @@ -1072,7 +1072,7 @@ pub enum Predicate<'tcx> { /// A trait predicate will have `Constness::Const` if it originates /// from a bound on a `const fn` without the `?const` opt-out (e.g., /// `const fn foobar() {}`). - Trait(PolyTraitPredicate<'tcx>, ast::Constness), + Trait(PolyTraitPredicate<'tcx>, Constness), /// `where 'a: 'b` RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), @@ -1340,18 +1340,33 @@ pub trait ToPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() }), - ast::Constness::NotConst, + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, ) } } -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate(), ast::Constness::NotConst) + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, + ) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) } } @@ -1707,6 +1722,33 @@ impl<'tcx> ParamEnv<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ConstnessAnd { + pub constness: Constness, + pub value: T, +} + +// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that +// the constness of trait bounds is being propagated correctly. +pub trait WithConstness: Sized { + #[inline] + fn with_constness(self, constness: Constness) -> ConstnessAnd { + ConstnessAnd { constness, value: self } + } + + #[inline] + fn with_const(self) -> ConstnessAnd { + self.with_constness(Constness::Const) + } + + #[inline] + fn without_const(self) -> ConstnessAnd { + self.with_constness(Constness::NotConst) + } +} + +impl WithConstness for T {} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 842361284823d..13f623aadb1a3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -12,7 +12,9 @@ use crate::mir::interpret::Scalar; use crate::mir::Promoted; use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; +use crate::ty::{ + self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, +}; use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; @@ -665,14 +667,16 @@ impl<'tcx> Binder> { pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match *self.skip_binder() { - ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), + ExistentialPredicate::Trait(tr) => { + Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() + } ExistentialPredicate::Projection(p) => { ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))) } ExistentialPredicate::AutoTrait(did) => { let trait_ref = Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); - trait_ref.to_predicate() + trait_ref.without_const().to_predicate() } } } diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index d47e54366b550..8b62403e6ce52 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -2,7 +2,7 @@ use rustc::hir::map as hir_map; use rustc::session::CrateDisambiguator; use rustc::traits::{self}; use rustc::ty::subst::Subst; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -58,6 +58,7 @@ fn sized_constraint_for_ty(tcx: TyCtxt<'tcx>, adtdef: &ty::AdtDef, ty: Ty<'tcx>) def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]), }) + .without_const() .to_predicate(); let predicates = tcx.predicates_of(adtdef.did).predicates; if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7f196b2c4d352..9253c00e5ae27 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -17,7 +17,7 @@ use rustc::traits::astconv_object_safety_violations; use rustc::traits::error_reporting::report_object_safety_error; use rustc::traits::wf::object_region_bounds; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId}; @@ -2980,7 +2980,7 @@ impl<'tcx> Bounds<'tcx> { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]), }); - (trait_ref.to_predicate(), span) + (trait_ref.without_const().to_predicate(), span) }) }); diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 8d6b74c3015c9..367fe0c3cc199 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -5,7 +5,7 @@ use rustc::infer::{InferCtxt, InferOk}; use rustc::session::DiagnosticMessageId; use rustc::traits::{self, TraitEngine}; use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; -use rustc::ty::{self, TraitRef, Ty, TyCtxt}; +use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -124,8 +124,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let obligation = - traits::Obligation::new(cause.clone(), self.param_env, trait_ref.to_predicate()); + let obligation = traits::Obligation::new( + cause.clone(), + self.param_env, + trait_ref.without_const().to_predicate(), + ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 711c285d17e88..c1cf3522b5d9c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -17,7 +17,7 @@ use rustc::traits; use rustc::ty::subst::Subst; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::GenericParamDefKind; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.to_predicate(), + poly_trait_ref.without_const().to_predicate(), ); // Now we want to know if this can be matched diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 67526bb70d125..ff2f150c63330 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -25,6 +25,7 @@ use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::GenericParamDefKind; use rustc::ty::{ self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, + WithConstness, }; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; @@ -1396,7 +1397,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } TraitCandidate(trait_ref) => { - let predicate = trait_ref.to_predicate(); + let predicate = trait_ref.without_const().to_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d6c0d9c77b495..35fffd3bcd45c 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -9,7 +9,7 @@ use rustc::hir::map::Map; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::Obligation; use rustc::ty::print::with_crate_prefix; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -59,7 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.to_predicate(), + poly_trait_ref.without_const().to_predicate(), ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7c1876f5d449c..1e3927f33a77f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -112,7 +112,7 @@ use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSel use rustc::ty::util::{Discr, IntTypeExt, Representability}; use rustc::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, + ToPredicate, Ty, TyCtxt, UserType, WithConstness, }; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -1423,7 +1423,7 @@ fn check_fn<'a, 'tcx>( inherited.register_predicate(traits::Obligation::new( cause, param_env, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), )); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 5e91e98a7dfa5..e4df69993c5d2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -6,7 +6,9 @@ use rustc::middle::lang_items; use rustc::session::parse::feature_err; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{ + self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir::def_id::DefId; @@ -955,7 +957,8 @@ fn receiver_is_implemented( substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), }; - let obligation = traits::Obligation::new(cause, fcx.param_env, trait_ref.to_predicate()); + let obligation = + traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate()); if fcx.predicate_must_hold_modulo_regions(&obligation) { true diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 35f9a4fa68e11..1211075d9429b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -30,7 +30,7 @@ use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; @@ -411,7 +411,8 @@ fn type_param_predicates( // Implied `Self: Trait` and supertrait bounds. if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); - extend = Some((identity_trait_ref.to_predicate(), item.span)); + extend = + Some((identity_trait_ref.without_const().to_predicate(), item.span)); } generics } @@ -2056,7 +2057,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { let span = tcx.def_span(def_id); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(), + ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(), span, )))); } @@ -2230,7 +2231,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.push((trait_ref.to_poly_trait_ref().to_predicate(), tcx.def_span(def_id))); + predicates.push(( + trait_ref.to_poly_trait_ref().without_const().to_predicate(), + tcx.def_span(def_id), + )); } // Collect the region predicates that were declared inline as diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 525b1b2e6ecf7..18ebd254507ea 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,7 +1,7 @@ use rustc::infer::InferOk; use rustc::traits; use rustc::ty::subst::Subst; -use rustc::ty::ToPredicate; +use rustc::ty::{ToPredicate, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_span::DUMMY_SP; @@ -64,7 +64,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { match infcx.evaluate_obligation(&traits::Obligation::new( cause, param_env, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), )) { Ok(eval_result) => eval_result.may_apply(), Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no From adbd01e84ad791ef370dc1d2baa726603f42094a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:33 -0800 Subject: [PATCH 13/25] Track constness while lowering bounds --- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/astconv.rs | 54 +++++++++++++++++++++----------- src/librustc_typeck/check/mod.rs | 11 +++++++ src/librustc_typeck/collect.rs | 44 ++++++++++++++++++++++---- src/librustc_typeck/lib.rs | 1 + 5 files changed, 86 insertions(+), 26 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4b2e90ed83de2..a914537d13408 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // The traits' privacy in bodies is already checked as a part of trait object types. let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref); - for (trait_predicate, _) in bounds.trait_bounds { + for (trait_predicate, _, _) in bounds.trait_bounds { if self.visit_trait(*trait_predicate.skip_binder()) { return; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9253c00e5ae27..6726a1461052b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -31,7 +31,7 @@ use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use smallvec::SmallVec; -use syntax::ast; +use syntax::ast::{self, Constness}; use syntax::util::lev_distance::find_best_match_for_name; use std::collections::BTreeSet; @@ -49,6 +49,8 @@ pub trait AstConv<'tcx> { fn item_def_id(&self) -> Option; + fn default_constness_for_trait_bounds(&self) -> Constness; + /// Returns predicates in scope of the form `X: Foo`, where `X` is /// a type parameter `X` with the given id `def_id`. This is a /// subset of the full set of predicates. @@ -919,6 +921,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, trait_ref: &hir::TraitRef<'_>, span: Span, + constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, @@ -947,7 +950,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); - bounds.trait_bounds.push((poly_trait_ref, span)); + bounds.trait_bounds.push((poly_trait_ref, span, constness)); let mut dup_bindings = FxHashMap::default(); for binding in &assoc_bindings { @@ -993,12 +996,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn instantiate_poly_trait_ref( &self, poly_trait_ref: &hir::PolyTraitRef<'_>, + constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, ) -> Option> { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, + constness, self_ty, bounds, false, @@ -1181,18 +1186,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut trait_bounds = Vec::new(); let mut region_bounds = Vec::new(); + let constness = self.default_constness_for_trait_bounds(); for ast_bound in ast_bounds { match *ast_bound { hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push(b) + trait_bounds.push((b, constness)) + } + hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { + trait_bounds.push((b, Constness::NotConst)) } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::Outlives(ref l) => region_bounds.push(l), } } - for bound in trait_bounds { - let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds); + for (bound, constness) in trait_bounds { + let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds); } bounds.region_bounds.extend( @@ -1226,7 +1235,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut bounds = Bounds::default(); self.add_bounds(param_ty, ast_bounds, &mut bounds); - bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id()); + bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } @@ -1417,15 +1426,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - let cur_potential_assoc_types = - self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds); + let cur_potential_assoc_types = self.instantiate_poly_trait_ref( + trait_bound, + Constness::NotConst, + dummy_self, + &mut bounds, + ); potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten()); } // Expand trait aliases recursively and check that only one regular (non-auto) trait // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned()); + let expanded_traits = traits::expand_trait_aliases( + tcx, + bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)), + ); let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); if regular_traits.len() > 1 { @@ -1481,16 +1496,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let regular_traits_refs_spans = bounds .trait_bounds .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span, constness) in regular_traits_refs_spans { + assert_eq!(constness, ast::Constness::NotConst); - for (base_trait_ref, span) in regular_traits_refs_spans { for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { debug!( "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref ); match trait_ref { - ty::Predicate::Trait(pred, constness) => { + ty::Predicate::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) .filter(|item| item.kind == ty::AssocKind::Type) @@ -2949,7 +2966,7 @@ pub struct Bounds<'tcx> { /// A list of trait bounds. So if you had `T: Debug` this would be /// `T: Debug`. Note that the self-type is explicit here. - pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>, + pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>, /// A list of projection equality bounds. So if you had `T: /// Iterator` this would include ` Bounds<'tcx> { let outlives = ty::OutlivesPredicate(param_ty, region_bound); (ty::Binder::bind(outlives).to_predicate(), span) }) - .chain( - self.trait_bounds - .iter() - .map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)), - ) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(); + (predicate, span) + })) .chain( self.projection_bounds .iter() diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e3927f33a77f..5e1b3a76fd28f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,6 +90,7 @@ pub mod writeback; use crate::astconv::{AstConv, PathSeg}; use crate::middle::lang_items; use crate::namespace::Namespace; +use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -2612,6 +2613,16 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { None } + fn default_constness_for_trait_bounds(&self) -> ast::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + ast::Constness::NotConst + } + } + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1211075d9429b..45d969a3d574f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -20,6 +20,7 @@ use crate::constrained_generic_params as cgp; use crate::lint; use crate::middle::resolve_lifetime as rl; use crate::middle::weak_lang_items; +use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::mir::mono::Linkage; @@ -288,6 +289,22 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { Some(self.item_def_id) } + fn default_constness_for_trait_bounds(&self) -> ast::Constness { + // FIXME: refactor this into a method + let hir_id = self + .tcx + .hir() + .as_local_hir_id(self.item_def_id) + .expect("Non-local call to local provider is_const_fn"); + + let node = self.tcx.hir().get(hir_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + ast::Constness::NotConst + } + } + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id)) } @@ -454,6 +471,7 @@ impl ItemCtxt<'tcx> { ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, ) -> Vec<(ty::Predicate<'tcx>, Span)> { + let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics .params .iter() @@ -462,7 +480,7 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) - .flat_map(|b| predicates_from_bound(self, ty, b)); + .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics .where_clause @@ -482,7 +500,7 @@ impl ItemCtxt<'tcx> { }; bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) - .flat_map(|(bt, b)| predicates_from_bound(self, bt, b)); + .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } @@ -2107,6 +2125,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); + let constness = icx.default_constness_for_trait_bounds(); const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); @@ -2308,11 +2327,18 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat for bound in bound_pred.bounds.iter() { match bound { - &hir::GenericBound::Trait(ref poly_trait_ref, _) => { + &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::None => constness, + hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"), + }; + let mut bounds = Bounds::default(); let _ = AstConv::instantiate_poly_trait_ref( &icx, poly_trait_ref, + constness, ty, &mut bounds, ); @@ -2488,11 +2514,18 @@ fn predicates_from_bound<'tcx>( astconv: &dyn AstConv<'tcx>, param_ty: Ty<'tcx>, bound: &'tcx hir::GenericBound<'tcx>, + constness: ast::Constness, ) -> Vec<(ty::Predicate<'tcx>, Span)> { match *bound { - hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => { + hir::GenericBound::Trait(ref tr, modifier) => { + let constness = match modifier { + hir::TraitBoundModifier::Maybe => return vec![], + hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst, + hir::TraitBoundModifier::None => constness, + }; + let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds); + let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); bounds.predicates(astconv.tcx(), param_ty) } hir::GenericBound::Outlives(ref lifetime) => { @@ -2500,7 +2533,6 @@ fn predicates_from_bound<'tcx>( let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)] } - hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![], } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 95cd3c631ed22..b3cf5f21fab9b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -382,6 +382,7 @@ pub fn hir_trait_to_predicates<'tcx>( &item_cx, hir_trait, DUMMY_SP, + syntax::ast::Constness::NotConst, tcx.types.err, &mut bounds, true, From 3b1a9d35c8ee396d2c546603347b5dc65d619cdf Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:35 -0800 Subject: [PATCH 14/25] Ignore filelength for `astconv` --- src/librustc_typeck/astconv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6726a1461052b..9397d183493b1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3,6 +3,8 @@ //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an //! instance of `AstConv`. +// ignore-tidy-filelength + use crate::collect::PlaceholderHirTyCollector; use crate::lint; use crate::middle::lang_items::SizedTraitLangItem; From 0ac4ba0eed776599e2d9f2ef76f6ae94a4471a4e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 20 Jan 2020 01:20:45 -0800 Subject: [PATCH 15/25] Parse `?const ?Trait` --- src/librustc_ast_lowering/lib.rs | 9 +++++++-- src/librustc_ast_passes/ast_validation.rs | 17 +++++++++++++---- src/librustc_parse/parser/ty.rs | 23 +++++------------------ src/libsyntax/ast.rs | 5 +++++ 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 90560c371e292..bc922fa0f55a3 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1254,7 +1254,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => { Some(this.lower_poly_trait_ref(ty, itctx.reborrow())) } - GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, + GenericBound::Trait(_, TraitBoundModifier::Maybe) + | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + None + } GenericBound::Outlives(ref lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2297,8 +2300,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier { match f { TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, + TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { + hir::TraitBoundModifier::Maybe + } } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23cb97348339d..9b71704f52d43 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -917,11 +917,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound) { - if let GenericBound::Trait(_, TraitBoundModifier::MaybeConst) = bound { - if let Some(ctx) = self.bound_context { - let msg = format!("`?const` is not permitted in {}", ctx.description()); - self.err_handler().span_err(bound.span(), &msg); + match bound { + GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { + if let Some(ctx) = self.bound_context { + let msg = format!("`?const` is not permitted in {}", ctx.description()); + self.err_handler().span_err(bound.span(), &msg); + } + } + + GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + self.err_handler() + .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); } + + _ => {} } visit::walk_param_bound(self, bound) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 9c9180778e522..efd8acc933aa8 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -27,17 +27,13 @@ struct BoundModifiers { } impl BoundModifiers { - fn to_trait_bound_modifier(&self) -> Result { - let modifier = match (self.maybe, self.maybe_const) { + fn to_trait_bound_modifier(&self) -> TraitBoundModifier { + match (self.maybe, self.maybe_const) { (None, None) => TraitBoundModifier::None, (Some(_), None) => TraitBoundModifier::Maybe, (None, Some(_)) => TraitBoundModifier::MaybeConst, - (Some(_), Some(_)) => { - return Err("`?const` and `?` are mutually exclusive"); - } - }; - - Ok(modifier) + (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe, + } } } @@ -563,16 +559,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; } - let modifier = match modifiers.to_trait_bound_modifier() { - Ok(m) => m, - Err(msg) => { - self.struct_span_err(lo.to(self.prev_span), msg).emit(); - - // Continue compilation as if the user had written `?Trait`. - TraitBoundModifier::Maybe - } - }; - + let modifier = modifiers.to_trait_bound_modifier(); let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); Ok(GenericBound::Trait(poly_trait, modifier)) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 88bfb8ccb9525..5f38ac4cc0f42 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -279,6 +279,11 @@ pub enum TraitBoundModifier { /// `?const Trait` MaybeConst, + + /// `?const ?Trait` + // + // This parses but will be rejected during AST validation. + MaybeConstMaybe, } /// The AST represents all type param bounds as types. From 23ea42cfd14e185f3af2232083318fdca90a4b6c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:34 -0800 Subject: [PATCH 16/25] Update tests --- .../feature-gate.gated.stderr | 8 ++--- .../const-trait-bound-opt-out/feature-gate.rs | 5 +-- .../feature-gate.stock.stderr | 10 ++---- .../in-impl-trait.rs | 4 --- .../in-impl-trait.stderr | 32 +++---------------- .../in-trait-bounds.rs | 1 - .../in-trait-bounds.stderr | 8 +---- .../in-trait-object.rs | 3 -- .../in-trait-object.stderr | 24 ++------------ .../with-maybe-sized.rs | 1 - .../with-maybe-sized.stderr | 8 +---- .../inherent-impl.rs | 9 ++++-- .../inherent-impl.stderr | 30 ++++++++++++++--- 13 files changed, 49 insertions(+), 94 deletions(-) diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 0bf337ad08dbf..e4f4d4262b64d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,8 +1,8 @@ -error: `?const` on trait bounds is not yet implemented - --> $DIR/feature-gate.rs:11:29 +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:16:1 | -LL | const fn get_assoc_const() -> i32 { ::CONST } - | ^^^^^^^^ +LL | fn main() {} + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index cf1ed30da0fcc..d600b53e44875 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -3,6 +3,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] +#![feature(rustc_attrs)] trait T { const CONST: i32; @@ -10,6 +11,6 @@ trait T { const fn get_assoc_const() -> i32 { ::CONST } //[stock]~^ ERROR `?const` on trait bounds is experimental -//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented -fn main() {} +#[rustc_error] +fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index 64388004b5b72..fbd3840cb1d2b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:11:29 + --> $DIR/feature-gate.rs:12:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ @@ -7,12 +7,6 @@ LL | const fn get_assoc_const() -> i32 { ::CONST } = note: for more information, see https://github.com/rust-lang/rust/issues/67794 = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable -error: `?const` on trait bounds is not yet implemented - --> $DIR/feature-gate.rs:11:29 - | -LL | const fn get_assoc_const() -> i32 { ::CONST } - | ^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs index e4e6bedd93746..f5561a922ddcd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs @@ -8,18 +8,14 @@ impl T for S {} fn rpit() -> impl ?const T { S } //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn apit(_: impl ?const T) {} //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn apit_assoc_bound(_: impl IntoIterator) {} //~^ ERROR `?const` is not permitted in `impl Trait` -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr index f4abd4b714e8a..06cd00a956a2d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr @@ -5,46 +5,22 @@ LL | fn rpit() -> impl ?const T { S } | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:13:17 + --> $DIR/in-impl-trait.rs:12:17 | LL | fn apit(_: impl ?const T) {} | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:17:50 + --> $DIR/in-impl-trait.rs:15:50 | LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } | ^^^^^^^^ error: `?const` is not permitted in `impl Trait` - --> $DIR/in-impl-trait.rs:21:48 + --> $DIR/in-impl-trait.rs:18:48 | LL | fn apit_assoc_bound(_: impl IntoIterator) {} | ^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:9:19 - | -LL | fn rpit() -> impl ?const T { S } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:13:17 - | -LL | fn apit(_: impl ?const T) {} - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:17:50 - | -LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-impl-trait.rs:21:48 - | -LL | fn apit_assoc_bound(_: impl IntoIterator) {} - | ^^^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs index 4523b46bc51f6..fc9ed5b1dc22e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs @@ -4,6 +4,5 @@ trait Super {} trait T: ?const Super {} //~^ ERROR `?const` is not permitted in supertraits -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr index 8003361be7d2e..a0d8f95acd2a8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr @@ -4,11 +4,5 @@ error: `?const` is not permitted in supertraits LL | trait T: ?const Super {} | ^^^^^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-bounds.rs:5:10 - | -LL | trait T: ?const Super {} - | ^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs index 6cfca71548674..b3d1f48ace147 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs @@ -9,14 +9,11 @@ impl T for S {} // An inherent impl for the trait object `?const T`. impl ?const T {} //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn trait_object() -> &'static dyn ?const T { &S } //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn trait_object_in_apit(_: impl IntoIterator>) {} //~^ ERROR `?const` is not permitted in trait objects -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr index c059f16902250..331fe0423fa94 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr @@ -5,34 +5,16 @@ LL | impl ?const T {} | ^^^^^^^^ error: `?const` is not permitted in trait objects - --> $DIR/in-trait-object.rs:14:35 + --> $DIR/in-trait-object.rs:13:35 | LL | fn trait_object() -> &'static dyn ?const T { &S } | ^^^^^^^^ error: `?const` is not permitted in trait objects - --> $DIR/in-trait-object.rs:18:61 + --> $DIR/in-trait-object.rs:16:61 | LL | fn trait_object_in_apit(_: impl IntoIterator>) {} | ^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:10:6 - | -LL | impl ?const T {} - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:14:35 - | -LL | fn trait_object() -> &'static dyn ?const T { &S } - | ^^^^^^^^ - -error: `?const` on trait bounds is not yet implemented - --> $DIR/in-trait-object.rs:18:61 - | -LL | fn trait_object_in_apit(_: impl IntoIterator>) {} - | ^^^^^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs index 425784f4e4326..c2c8689e2942b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs @@ -3,6 +3,5 @@ struct S(std::marker::PhantomData); //~^ ERROR `?const` and `?` are mutually exclusive -//~| ERROR `?const` on trait bounds is not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr index 44f6d464ae6a8..e8e9d6c1e7621 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr @@ -4,11 +4,5 @@ error: `?const` and `?` are mutually exclusive LL | struct S(std::marker::PhantomData); | ^^^^^^^^^^^^^ -error: `?const` on trait bounds is not yet implemented - --> $DIR/with-maybe-sized.rs:4:13 - | -LL | struct S(std::marker::PhantomData); - | ^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs index 9cffe75addd63..7f064c0c53ade 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs @@ -1,5 +1,3 @@ -// compile-flags: -Z parse-only - #![feature(const_trait_impl)] #![feature(const_trait_bound_opt_out)] #![allow(incomplete_features)] @@ -8,7 +6,12 @@ struct S; trait T {} +impl const S {} +//~^ ERROR inherent impls cannot be `const` +//~| ERROR const trait impls are not yet implemented + impl const T {} -//~^ ERROR `const` cannot modify an inherent impl +//~^ ERROR inherent impls cannot be `const` +//~| ERROR const trait impls are not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr index 1d24557655951..508c6f4c747e1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -1,10 +1,30 @@ -error: `const` cannot modify an inherent impl - --> $DIR/inherent-impl.rs:11:6 +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:9:1 + | +LL | impl const S {} + | ^^^^^^^^^^^^^^^ + | + = note: only trait implementations may be annotated with `const` + +error: inherent impls cannot be `const` + --> $DIR/inherent-impl.rs:13:1 | LL | impl const T {} - | ^^^^^ + | ^^^^^^^^^^^^^^^ + | + = note: only trait implementations may be annotated with `const` + +error: const trait impls are not yet implemented + --> $DIR/inherent-impl.rs:9:1 + | +LL | impl const S {} + | ^^^^^^^^^^^^^^^ + +error: const trait impls are not yet implemented + --> $DIR/inherent-impl.rs:13:1 | - = help: only a trait impl can be `const` +LL | impl const T {} + | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 4 previous errors From 71450c7aadac3a94889744143127962c4e991f60 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 20 Jan 2020 17:57:08 +0100 Subject: [PATCH 17/25] generalize bindings_with_variant_name lint --- .../hair/pattern/check_match.rs | 19 +++------- src/test/ui/lint/lint-uppercase-variables.rs | 10 +++++ .../ui/lint/lint-uppercase-variables.stderr | 38 ++++++++++++++++++- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index eac52da7ba4ae..ced0d5ed9359e 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -67,18 +67,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - - // Check legality of move bindings and `@` patterns. self.check_patterns(false, &loc.pat); } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { - intravisit::walk_body(self, body); - - for param in body.params { - self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(false, ¶m.pat); - } + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + intravisit::walk_param(self, param); + self.check_irrefutable(¶m.pat, "function argument", None); + self.check_patterns(false, ¶m.pat); } } @@ -123,6 +118,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { if !self.tcx.features().bindings_after_at { check_legality_of_bindings_in_at_patterns(self, pat); } + check_for_bindings_named_same_as_variants(self, pat); } fn check_match( @@ -132,11 +128,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { source: hir::MatchSource, ) { for arm in arms { - // First, check legality of move bindings. + // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(arm.guard.is_some(), &arm.pat); - - // Second, perform some lints. - check_for_bindings_named_same_as_variants(self, &arm.pat); } let module = self.tcx.hir().get_module_parent(scrut.hir_id); diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs index 86a39502a81cc..a98b4f2fd4450 100644 --- a/src/test/ui/lint/lint-uppercase-variables.rs +++ b/src/test/ui/lint/lint-uppercase-variables.rs @@ -25,6 +25,16 @@ fn main() { //~^^^ WARN unused variable: `Foo` } + let Foo = foo::Foo::Foo; + //~^ ERROR variable `Foo` should have a snake case name + //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^^ WARN unused variable: `Foo` + + fn in_param(Foo: foo::Foo) {} + //~^ ERROR variable `Foo` should have a snake case name + //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^^ WARN unused variable: `Foo` + test(1); let _ = Something { X: 0 }; diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr index b937832ac622d..a38f3e7626bca 100644 --- a/src/test/ui/lint/lint-uppercase-variables.stderr +++ b/src/test/ui/lint/lint-uppercase-variables.stderr @@ -6,6 +6,18 @@ LL | Foo => {} | = note: `#[warn(bindings_with_variant_name)]` on by default +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | @@ -19,6 +31,18 @@ LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` +warning: unused variable: `Foo` + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: consider prefixing with an underscore: `_Foo` + +warning: unused variable: `Foo` + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: consider prefixing with an underscore: `_Foo` + error: structure field `X` should have a snake case name --> $DIR/lint-uppercase-variables.rs:10:5 | @@ -49,6 +73,18 @@ error: variable `Foo` should have a snake case name LL | Foo => {} | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` -error: aborting due to 4 previous errors +error: variable `Foo` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:28:9 + | +LL | let Foo = foo::Foo::Foo; + | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` + +error: variable `Foo` should have a snake case name + --> $DIR/lint-uppercase-variables.rs:33:17 + | +LL | fn in_param(Foo: foo::Foo) {} + | ^^^ help: convert the identifier to snake case (notice the capitalization): `foo` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0170`. From 53924428692371a175afeaaa5fa410c44f0e06ae Mon Sep 17 00:00:00 2001 From: Vita Batrla Date: Mon, 20 Jan 2020 19:15:37 +0100 Subject: [PATCH 18/25] refactor fix using cfg_if! (fix build on Solaris) --- src/libstd/sys_common/net.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 7e603a8682ba5..135e8308afaea 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -44,6 +44,7 @@ cfg_if::cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "solaris"))] { + use libc::c_uchar; type IpV4MultiCastType = c_uchar; } else { type IpV4MultiCastType = c_int; From 78f0c7fd6433c60d031311dacbf9a117b05e64b3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 20 Jan 2020 19:46:06 +0100 Subject: [PATCH 19/25] check_match: unify some lowering code and fix some ICEs --- src/librustc_mir_build/hair/pattern/_match.rs | 9 ++--- .../hair/pattern/check_match.rs | 33 +++++++++++-------- .../issue-68393-let-pat-assoc-constant.rs | 26 +++++++++++++++ .../issue-68393-let-pat-assoc-constant.stderr | 15 +++++++++ .../issue-68394-let-pat-runtime-value.rs | 5 +++ .../issue-68394-let-pat-runtime-value.stderr | 9 +++++ .../ui/pattern/issue-68396-let-float-bug.rs | 7 ++++ .../pattern/issue-68396-let-float-bug.stderr | 15 +++++++++ 8 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs create mode 100644 src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr create mode 100644 src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs create mode 100644 src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr create mode 100644 src/test/ui/pattern/issue-68396-let-float-bug.rs create mode 100644 src/test/ui/pattern/issue-68396-let-float-bug.stderr diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 8fcaa1e8082fb..20183fd55c871 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -582,15 +582,12 @@ crate struct MatchCheckCtxt<'a, 'tcx> { } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { - crate fn create_and_enter( + crate fn create_and_enter( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, module: DefId, - f: F, - ) -> R - where - F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R, - { + f: impl for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R, + ) -> R { let pattern_arena = TypedArena::default(); f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena }) diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index ced0d5ed9359e..5462d08e3cca9 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -121,6 +121,24 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { check_for_bindings_named_same_as_variants(self, pat); } + fn lower_pattern<'p>( + &self, + cx: &mut MatchCheckCtxt<'p, 'tcx>, + pat: &'tcx hir::Pat<'tcx>, + have_errors: &mut bool, + ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) { + let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables); + patcx.include_lint_checks(); + let pattern = patcx.lower_pattern(pat); + let pattern_ty = pattern.ty; + let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern)); + if !patcx.errors.is_empty() { + *have_errors = true; + patcx.report_inlining_errors(pat.span); + } + (pattern, pattern_ty) + } + fn check_match( &mut self, scrut: &hir::Expr<'_>, @@ -139,14 +157,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let inlined_arms: Vec<_> = arms .iter() .map(|arm| { - let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables); - patcx.include_lint_checks(); - let pattern = patcx.lower_pattern(&arm.pat); - let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern)); - if !patcx.errors.is_empty() { - patcx.report_inlining_errors(arm.pat.span); - have_errors = true; - } + let (pattern, _) = self.lower_pattern(cx, &arm.pat, &mut have_errors); (pattern, &*arm.pat, arm.guard.is_some()) }) .collect(); @@ -171,11 +182,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { - let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables); - patcx.include_lint_checks(); - let pattern = patcx.lower_pattern(pat); - let pattern_ty = pattern.ty; - let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern)); + let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false); let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect(); let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs new file mode 100644 index 0000000000000..95ead6b5d4a61 --- /dev/null +++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs @@ -0,0 +1,26 @@ +pub enum EFoo { + A, +} + +pub trait Foo { + const X: EFoo; +} + +struct Abc; + +impl Foo for Abc { + const X: EFoo = EFoo::A; +} + +struct Def; +impl Foo for Def { + const X: EFoo = EFoo::A; +} + +pub fn test(arg: EFoo, A::X: EFoo) { + //~^ ERROR associated consts cannot be referenced in patterns + let A::X = arg; + //~^ ERROR associated consts cannot be referenced in patterns +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr new file mode 100644 index 0000000000000..54ecc24981f80 --- /dev/null +++ b/src/test/ui/pattern/issue-68393-let-pat-assoc-constant.stderr @@ -0,0 +1,15 @@ +error[E0158]: associated consts cannot be referenced in patterns + --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40 + | +LL | pub fn test(arg: EFoo, A::X: EFoo) { + | ^^^^ + +error[E0158]: associated consts cannot be referenced in patterns + --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9 + | +LL | let A::X = arg; + | ^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0158`. diff --git a/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs new file mode 100644 index 0000000000000..f10a7f2d8a54f --- /dev/null +++ b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs @@ -0,0 +1,5 @@ +fn main() { + let x = 255u8; + let 0u8..=x = 0; + //~^ ERROR runtime values cannot be referenced in patterns +} diff --git a/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr new file mode 100644 index 0000000000000..c1508bd71ff7a --- /dev/null +++ b/src/test/ui/pattern/issue-68394-let-pat-runtime-value.stderr @@ -0,0 +1,9 @@ +error[E0080]: runtime values cannot be referenced in patterns + --> $DIR/issue-68394-let-pat-runtime-value.rs:3:15 + | +LL | let 0u8..=x = 0; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/pattern/issue-68396-let-float-bug.rs b/src/test/ui/pattern/issue-68396-let-float-bug.rs new file mode 100644 index 0000000000000..afc599a4b22b6 --- /dev/null +++ b/src/test/ui/pattern/issue-68396-let-float-bug.rs @@ -0,0 +1,7 @@ +fn main() { + let 1234567890123456789012345678901234567890e-340: f64 = 0.0; + //~^ ERROR could not evaluate float literal (see issue #31407) + + fn param(1234567890123456789012345678901234567890e-340: f64) {} + //~^ ERROR could not evaluate float literal (see issue #31407) +} diff --git a/src/test/ui/pattern/issue-68396-let-float-bug.stderr b/src/test/ui/pattern/issue-68396-let-float-bug.stderr new file mode 100644 index 0000000000000..618aa4b5021f1 --- /dev/null +++ b/src/test/ui/pattern/issue-68396-let-float-bug.stderr @@ -0,0 +1,15 @@ +error[E0080]: could not evaluate float literal (see issue #31407) + --> $DIR/issue-68396-let-float-bug.rs:2:9 + | +LL | let 1234567890123456789012345678901234567890e-340: f64 = 0.0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: could not evaluate float literal (see issue #31407) + --> $DIR/issue-68396-let-float-bug.rs:5:14 + | +LL | fn param(1234567890123456789012345678901234567890e-340: f64) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. From 58eb03d20f08881d06334c38a3ae0da25a8924bc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 20 Jan 2020 22:23:07 +0100 Subject: [PATCH 20/25] check_match: simplify check_arm --- Cargo.lock | 1 + src/librustc_mir_build/Cargo.toml | 1 + .../hair/pattern/check_match.rs | 103 +++++++----------- .../struct-pattern-match-useless.stderr | 4 +- 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48bc269ebb654..cbb40f4e2a25e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3763,6 +3763,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_macros", + "rustc_session", "rustc_span", "rustc_target", "serialize", diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml index f0d1d4c6515ce..a22c4d18d516a 100644 --- a/src/librustc_mir_build/Cargo.toml +++ b/src/librustc_mir_build/Cargo.toml @@ -21,6 +21,7 @@ rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } rustc_macros = { path = "../librustc_macros" } rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index 5462d08e3cca9..49b7c2d41fcbb 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -5,9 +5,6 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack} use super::{PatCtxt, PatKind, PatternError}; use rustc::hir::map::Map; -use rustc::lint; -use rustc::session::parse::feature_err; -use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -15,6 +12,10 @@ use rustc_hir::def::*; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; +use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; +use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; +use rustc_session::parse::feature_err; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span}; use syntax::ast::Mutability; @@ -156,9 +157,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let inlined_arms: Vec<_> = arms .iter() - .map(|arm| { - let (pattern, _) = self.lower_pattern(cx, &arm.pat, &mut have_errors); - (pattern, &*arm.pat, arm.guard.is_some()) + .map(|hir::Arm { pat, guard, .. }| { + (self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some()) }) .collect(); @@ -285,7 +285,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa let ty_path = cx.tcx.def_path_str(edef.did); cx.tcx .struct_span_lint_hir( - lint::builtin::BINDINGS_WITH_VARIANT_NAME, + BINDINGS_WITH_VARIANT_NAME, p.hir_id, p.span, &format!( @@ -310,79 +310,63 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa } /// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(pat: &Pat<'_>) -> bool { - match pat.kind { - hir::PatKind::Binding(.., None) => true, - hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s), - hir::PatKind::Ref(ref s, _) => pat_is_catchall(s), - hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)), +fn pat_is_catchall(pat: &super::Pat<'_>) -> bool { + use super::PatKind::*; + match &*pat.kind { + Binding { subpattern: None, .. } => true, + Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s), + Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)), _ => false, } } +fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option) { + let mut err = tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern"); + if let Some(catchall) = catchall { + // We had a catchall pattern, hint at that. + err.span_label(span, "unreachable pattern"); + err.span_label(catchall, "matches any value"); + } + err.emit(); +} + +fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) { + let msg = match source { + hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern", + hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern", + _ => bug!(), + }; + tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg); +} + /// Check for unreachable patterns. fn check_arms<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, - arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)], + arms: &[(&'p super::Pat<'tcx>, HirId, bool)], source: hir::MatchSource, ) -> Matrix<'p, 'tcx> { let mut seen = Matrix::empty(); let mut catchall = None; - for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() { + for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() { let v = PatStack::from_pattern(pat); - - match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) { + match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) { NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(), hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => { - // check which arm we're on. + // Check which arm we're on. match arm_index { // The arm with the user-specified pattern. - 0 => { - cx.tcx.lint_hir( - lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.hir_id, - pat.span, - "unreachable pattern", - ); - } + 0 => unreachable_pattern(cx.tcx, pat.span, id, None), // The arm with the wildcard pattern. - 1 => { - let msg = match source { - hir::MatchSource::IfLetDesugar { .. } => { - "irrefutable if-let pattern" - } - hir::MatchSource::WhileLetDesugar => { - "irrefutable while-let pattern" - } - _ => bug!(), - }; - cx.tcx.lint_hir( - lint::builtin::IRREFUTABLE_LET_PATTERNS, - hir_pat.hir_id, - pat.span, - msg, - ); - } + 1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source), _ => bug!(), } } hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - let mut err = cx.tcx.struct_span_lint_hir( - lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.hir_id, - pat.span, - "unreachable pattern", - ); - // if we had a catchall pattern, hint at that - if let Some(catchall) = catchall { - err.span_label(pat.span, "unreachable pattern"); - err.span_label(catchall, "matches any value"); - } - err.emit(); + unreachable_pattern(cx.tcx, pat.span, id, catchall); } // Unreachable patterns in try and await expressions occur when one of @@ -392,19 +376,14 @@ fn check_arms<'p, 'tcx>( } Useful(unreachable_subpatterns) => { for pat in unreachable_subpatterns { - cx.tcx.lint_hir( - lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.hir_id, - pat.span, - "unreachable pattern", - ); + unreachable_pattern(cx.tcx, pat.span, id, None); } } UsefulWithWitness(_) => bug!(), } if !has_guard { seen.push(v); - if catchall.is_none() && pat_is_catchall(hir_pat) { + if catchall.is_none() && pat_is_catchall(pat) { catchall = Some(pat.span); } } diff --git a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr index 5b0c9305448a7..0115fc081a970 100644 --- a/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr +++ b/src/test/ui/pattern/usefulness/struct-pattern-match-useless.stderr @@ -1,8 +1,10 @@ error: unreachable pattern --> $DIR/struct-pattern-match-useless.rs:12:9 | +LL | Foo { x: _x, y: _y } => (), + | -------------------- matches any value LL | Foo { .. } => () - | ^^^^^^^^^^ + | ^^^^^^^^^^ unreachable pattern | note: lint level defined here --> $DIR/struct-pattern-match-useless.rs:1:9 From 1b800a567165ab4395daa82e215eaed84be5c8dc Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 21 Jan 2020 10:30:14 +0100 Subject: [PATCH 21/25] trade in outdated comments for correct ones --- src/liballoc/collections/btree/node.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index f190209503d3e..37501a51e16e3 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -392,7 +392,6 @@ impl NodeRef { /// Borrows a view into the values stored in the node. /// The caller must ensure that the node is not the shared root. - /// This function is not public, so doesn't have to support shared roots like `keys` does. fn vals(&self) -> &[V] { self.reborrow().into_val_slice() } @@ -510,7 +509,6 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } /// The caller must ensure that the node is not the shared root. - /// This function is not public, so doesn't have to support shared roots like `keys` does. fn keys_mut(&mut self) -> &mut [K] { unsafe { self.reborrow_mut().into_key_slice_mut() } } @@ -522,6 +520,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// The caller must ensure that the node is not the shared root. fn into_key_slice(self) -> &'a [K] { debug_assert!(!self.is_shared_root()); // We cannot be the shared root, so `as_leaf` is okay. @@ -535,6 +534,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().vals), self.len()) } } + /// The caller must ensure that the node is not the shared root. fn into_slices(self) -> (&'a [K], &'a [V]) { let k = unsafe { ptr::read(&self) }; (k.into_key_slice(), self.into_val_slice()) From 6bd69a10921785aa8ab68e58d9c7a7ea1ff6ef96 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 21 Jan 2020 01:42:45 -0800 Subject: [PATCH 22/25] Add comment explaining `MaybeConstMaybe` lowering --- src/librustc_ast_lowering/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index bc922fa0f55a3..7163bf985ab97 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1254,6 +1254,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => { Some(this.lower_poly_trait_ref(ty, itctx.reborrow())) } + // `?const ?Bound` will cause an error during AST validation + // anyways, so treat it like `?Bound` as compilation proceeds. GenericBound::Trait(_, TraitBoundModifier::Maybe) | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { None @@ -2301,6 +2303,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match f { TraitBoundModifier::None => hir::TraitBoundModifier::None, TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, + + // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a + // placeholder for compilation to proceed. TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { hir::TraitBoundModifier::Maybe } From 14c002edb6a2e336dca09dca96df2b7228db95a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 21 Jan 2020 15:33:17 +0100 Subject: [PATCH 23/25] tidy: fix most clippy warnings --- src/tools/tidy/src/debug_artifacts.rs | 2 +- src/tools/tidy/src/error_codes_check.rs | 4 ++-- src/tools/tidy/src/features.rs | 4 ++-- src/tools/tidy/src/features/version.rs | 2 +- src/tools/tidy/src/style.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs index 4664e2ef9a51c..408be83b926e2 100644 --- a/src/tools/tidy/src/debug_artifacts.rs +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; -const GRAPHVIZ_POSTFLOW_MSG: &'static str = "`borrowck_graphviz_postflow` attribute in test"; +const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test"; pub fn check(path: &Path, bad: &mut bool) { let test_dir: PathBuf = path.join("test"); diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index ebaa81d2a8dbe..428c57d3ee822 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -53,7 +53,7 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap, path: & error_codes.insert(err_code.clone(), false); } // Now we extract the tests from the markdown file! - let md = some_or_continue!(s.splitn(2, "include_str!(\"").skip(1).next()); + let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1)); let md_file_name = some_or_continue!(md.splitn(2, "\")").next()); let path = some_or_continue!(path.parent()).join(md_file_name); match read_to_string(&path) { @@ -84,7 +84,7 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap bool { } } } - return false; + false } pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { @@ -344,7 +344,7 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features } None } else { - let s = issue_str.split('(').nth(1).unwrap().split(')').nth(0).unwrap(); + let s = issue_str.split('(').nth(1).unwrap().split(')').next().unwrap(); Some(s.parse().unwrap()) }; Some((name.to_owned(), Feature { level, since, has_gate_test: false, tracking_issue })) diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index c8c39ad27e09f..620be2f985230 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -38,7 +38,7 @@ impl FromStr for Version { let parts = [part()?, part()?, part()?]; - if let Some(_) = iter.next() { + if iter.next().is_some() { // Ensure we don't have more than 3 parts. return Err(ParseVersionError::WrongNumberOfParts); } diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index b15c29921d2b2..4247fcb3b7f53 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -58,7 +58,7 @@ enum LIUState { fn line_is_url(columns: usize, line: &str) -> bool { // more basic check for error_codes.rs, to avoid complexity in implementing two state machines if columns == ERROR_CODE_COLS { - return line.starts_with("[") && line.contains("]:") && line.contains("http"); + return line.starts_with('[') && line.contains("]:") && line.contains("http"); } use self::LIUState::*; From 3e947ef031ae05c4ed56bbd6b3380bef644923f1 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 21 Jan 2020 16:12:19 +0100 Subject: [PATCH 24/25] Declare unsafe functions that can no longer handle shared roots --- src/liballoc/collections/btree/node.rs | 8 ++++---- src/liballoc/collections/btree/search.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 37501a51e16e3..d9cdebb4f7354 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -386,7 +386,7 @@ impl NodeRef { /// Borrows a view into the keys stored in the node. /// The caller must ensure that the node is not the shared root. - pub fn keys(&self) -> &[K] { + pub unsafe fn keys(&self) -> &[K] { self.reborrow().into_key_slice() } @@ -521,10 +521,10 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// The caller must ensure that the node is not the shared root. - fn into_key_slice(self) -> &'a [K] { + unsafe fn into_key_slice(self) -> &'a [K] { debug_assert!(!self.is_shared_root()); // We cannot be the shared root, so `as_leaf` is okay. - unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len()) } + slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len()) } /// The caller must ensure that the node is not the shared root. @@ -537,7 +537,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// The caller must ensure that the node is not the shared root. fn into_slices(self) -> (&'a [K], &'a [V]) { let k = unsafe { ptr::read(&self) }; - (k.into_key_slice(), self.into_val_slice()) + (unsafe { k.into_key_slice() }, self.into_val_slice()) } } diff --git a/src/liballoc/collections/btree/search.rs b/src/liballoc/collections/btree/search.rs index 25e206f4f73db..579624cdd2b6a 100644 --- a/src/liballoc/collections/btree/search.rs +++ b/src/liballoc/collections/btree/search.rs @@ -64,9 +64,9 @@ where // Using `keys()` is fine here even if BorrowType is mutable, as all we return // is an index -- not a reference. let len = node.len(); - // Skip search for empty nodes because `keys()` does not work on shared roots. if len > 0 { - for (i, k) in node.keys().iter().enumerate() { + let keys = unsafe { node.keys() }; // safe because a non-empty node cannot be the shared root + for (i, k) in keys.iter().enumerate() { match key.cmp(k.borrow()) { Ordering::Greater => {} Ordering::Equal => return (i, true), From 32a81f774204dc77dbe11b011cbe769b4fd61476 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 21 Jan 2020 17:04:43 +0100 Subject: [PATCH 25/25] lowering: cleanup some hofs --- src/librustc_ast_lowering/expr.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index a24bb52150a72..5dc855e935c07 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -848,10 +848,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_catch_scope(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { let len = self.catch_scopes.len(); self.catch_scopes.push(catch_id); @@ -867,10 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> { result } - fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_loop_scope(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { // We're no longer in the base loop's condition; we're in another loop. let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; @@ -892,10 +886,7 @@ impl<'hir> LoweringContext<'_, 'hir> { result } - fn with_loop_condition_scope(&mut self, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { + fn with_loop_condition_scope(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = true;