diff --git a/Cargo.lock b/Cargo.lock index 2e46d43a79098..0666abadcba33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -676,6 +676,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ + "colored", "diff", "getopts", "glob", @@ -688,6 +689,7 @@ dependencies = [ "serde_json", "tracing", "tracing-subscriber", + "unified-diff", "walkdir", "winapi 0.3.9", ] @@ -5526,6 +5528,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unified-diff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496a3d395ed0c30f411ceace4a91f7d93b148fb5a9b383d5d4cff7850f048d5f" +dependencies = [ + "diff", +] + [[package]] name = "unstable-book-gen" version = "0.1.0" diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 725c144257c4c..6d2ab0e5f5a80 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -732,11 +732,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Can't be caught in typeck if the array length is generic. if e_len == 0 { tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); - } else if !e_len.is_power_of_two() { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` of non-power-of-two length", - ty - )); } else if e_len > MAX_SIMD_LANES { tcx.sess.fatal(&format!( "monomorphising SIMD type `{}` of length greater than {}", diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e63fd4ce6357d..7aee718bfa962 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1422,7 +1422,7 @@ impl<'a> Resolver<'a> { fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId { loop { - match ctxt.outer_expn().expn_data().macro_def_id { + match ctxt.outer_expn_data().macro_def_id { Some(def_id) => return def_id, None => ctxt.remove_mark(), }; diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 5d7f5bf1c7b80..0010d59f710cd 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1161,15 +1161,6 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { if len == 0 { struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); return; - } else if !len.is_power_of_two() { - struct_span_err!( - tcx.sess, - sp, - E0075, - "SIMD vector length must be a power of two" - ) - .emit(); - return; } else if len > MAX_SIMD_LANES { struct_span_err!( tcx.sess, diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index eb8ec7cd2e477..9a7119470f370 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -77,9 +77,8 @@ impl LeafNode { } } - /// Creates a new boxed `LeafNode`. Unsafe because all nodes should really be hidden behind - /// `BoxedNode`, preventing accidental dropping of uninitialized keys and values. - unsafe fn new() -> Box { + /// Creates a new boxed `LeafNode`. + fn new() -> Box { unsafe { let mut leaf = Box::new_uninit(); LeafNode::init(leaf.as_mut_ptr()); @@ -107,10 +106,9 @@ struct InternalNode { impl InternalNode { /// Creates a new boxed `InternalNode`. /// - /// This is unsafe for two reasons. First, it returns an owned `InternalNode` in a box, risking - /// dropping of uninitialized fields. Second, an invariant of internal nodes is that `len + 1` - /// edges are initialized and valid, meaning that even when the node is empty (having a - /// `len` of 0), there must be one initialized and valid edge. This function does not set up + /// # Safety + /// An invariant of internal nodes is that they have at least one + /// initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Box { unsafe { @@ -144,7 +142,7 @@ impl Root { impl NodeRef { fn new_leaf() -> Self { - Self::from_new_leaf(unsafe { LeafNode::new() }) + Self::from_new_leaf(LeafNode::new()) } fn from_new_leaf(leaf: Box>) -> Self { @@ -156,10 +154,13 @@ impl NodeRef { fn new_internal(child: Root) -> Self { let mut new_node = unsafe { InternalNode::new() }; new_node.edges[0].write(child.node); - NodeRef::from_new_internal(new_node, child.height + 1) + unsafe { NodeRef::from_new_internal(new_node, child.height + 1) } } - fn from_new_internal(internal: Box>, height: usize) -> Self { + /// # Safety + /// `height` must not be zero. + unsafe fn from_new_internal(internal: Box>, height: usize) -> Self { + debug_assert!(height > 0); let node = NonNull::from(Box::leak(internal)).cast(); let mut this = NodeRef { height, node, _marker: PhantomData }; this.borrow_mut().correct_all_childrens_parent_links(); @@ -1080,14 +1081,12 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// - All the key-value pairs to the right of this handle are put into a newly /// allocated node. pub fn split(mut self) -> SplitResult<'a, K, V, marker::Leaf> { - unsafe { - let mut new_node = LeafNode::new(); + let mut new_node = LeafNode::new(); - let kv = self.split_leaf_data(&mut new_node); + let kv = self.split_leaf_data(&mut new_node); - let right = NodeRef::from_new_leaf(new_node); - SplitResult { left: self.node, kv, right } - } + let right = NodeRef::from_new_leaf(new_node); + SplitResult { left: self.node, kv, right } } /// Removes the key-value pair pointed to by this handle and returns it, along with the edge diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 2dd5e813d6fb7..5b113610a5d3f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -9,7 +9,7 @@ mod private { pub trait Sealed {} } -/// Supporting trait for inherent methods of `f32` and `f64` such as `round_unchecked_to`. +/// Supporting trait for inherent methods of `f32` and `f64` such as `to_int_unchecked`. /// Typically doesn’t need to be used directly. #[unstable(feature = "convert_float_to_int", issue = "67057")] pub trait FloatToInt: private::Sealed + Sized { diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 31e39b5ad0421..b95511e43d844 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -29,7 +29,7 @@ pub use crate::sys::wasi_ext as wasi; // If we're not documenting libstd then we just expose the main modules as we otherwise would. #[cfg(not(doc))] -#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))] +#[cfg(any(unix, target_os = "hermit"))] #[stable(feature = "rust1", since = "1.0.0")] pub use crate::sys::ext as unix; diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 0964b6335aa79..33d6a39af07f6 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,6 +1,6 @@ use super::{sockaddr_un, SocketAddr}; use crate::convert::TryFrom; -use crate::io::{self, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; @@ -68,7 +68,7 @@ pub(super) fn recv_vectored_with_ancillary_from( pub(super) fn send_vectored_with_ancillary_to( socket: &Socket, path: Option<&Path>, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result { unsafe { @@ -78,7 +78,7 @@ pub(super) fn send_vectored_with_ancillary_to( let mut msg: libc::msghdr = zeroed(); msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = msg_namelen; - msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); cfg_if::cfg_if! { if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { @@ -567,7 +567,7 @@ impl<'a> SocketAncillary<'a> { /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary}; /// use std::os::unix::io::AsRawFd; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixStream::connect("/tmp/sock")?; @@ -577,7 +577,7 @@ impl<'a> SocketAncillary<'a> { /// ancillary.add_fds(&[sock.as_raw_fd()][..]); /// /// let mut buf = [1; 8]; - /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// let mut bufs = &mut [IoSlice::new(&mut buf[..])][..]; /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; /// Ok(()) /// } diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 0f532c47c8f92..a8c13fbb87480 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -19,7 +19,7 @@ use super::{sockaddr_un, SocketAddr}; target_os = "netbsd", target_os = "openbsd", ))] -use crate::io::IoSliceMut; +use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; @@ -506,23 +506,24 @@ impl UnixDatagram { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock") + /// .expect("send_vectored_with_ancillary_to function failed"); /// Ok(()) /// } /// ``` @@ -538,7 +539,7 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, path: P, ) -> io::Result { @@ -554,23 +555,24 @@ impl UnixDatagram { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary) + /// .expect("send_vectored_with_ancillary function failed"); /// Ok(()) /// } /// ``` @@ -586,7 +588,7 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result { send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 9fe6b85837e33..fc08edacb828d 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -530,23 +530,24 @@ impl UnixStream { /// ```no_run /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary}; - /// use std::io::IoSliceMut; + /// use std::io::IoSlice; /// /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), + /// let buf1 = [1; 8]; + /// let buf2 = [2; 16]; + /// let buf3 = [3; 8]; + /// let bufs = &[ + /// IoSlice::new(&buf1), + /// IoSlice::new(&buf2), + /// IoSlice::new(&buf3), /// ][..]; /// let fds = [0, 1, 2]; /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ancillary.add_fds(&fds[..]); - /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary) + /// .expect("send_vectored_with_ancillary function failed"); /// Ok(()) /// } /// ``` @@ -562,7 +563,7 @@ impl UnixStream { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, - bufs: &mut [IoSliceMut<'_>], + bufs: &[IoSlice<'_>], ancillary: &mut SocketAncillary<'_>, ) -> io::Result { send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 97a016904b4a4..bd9b6dd727b96 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -485,14 +485,14 @@ fn test_unix_datagram_peek_from() { fn test_send_vectored_fds_unix_stream() { let (s1, s2) = or_panic!(UnixStream::pair()); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); - let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; @@ -542,8 +542,8 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { or_panic!(bsock2.set_passcred(true)); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); @@ -554,7 +554,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = - or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; @@ -603,15 +603,15 @@ fn test_send_vectored_with_ancillary_unix_datagram() { let bsock1 = or_panic!(UnixDatagram::bind(&path1)); let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + let buf1 = [1; 8]; + let bufs_send = &[IoSlice::new(&buf1[..])][..]; let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); or_panic!(bsock1.connect(&path2)); - let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1)); assert_eq!(usize, 8); let mut buf2 = [0; 8]; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index d9f5b5bfa3ae2..de6942968ea0d 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -263,6 +263,8 @@ crate struct RenderOptions { crate document_private: bool, /// Document items that have `doc(hidden)`. crate document_hidden: bool, + /// If `true`, generate a JSON file in the crate folder instead of HTML redirection files. + crate generate_redirect_map: bool, crate unstable_features: rustc_feature::UnstableFeatures, } @@ -570,6 +572,7 @@ impl Options { let document_private = matches.opt_present("document-private-items"); let document_hidden = matches.opt_present("document-hidden-items"); let run_check = matches.opt_present("check"); + let generate_redirect_map = matches.opt_present("generate-redirect-map"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -627,6 +630,7 @@ impl Options { generate_search_filter, document_private, document_hidden, + generate_redirect_map, unstable_features: rustc_feature::UnstableFeatures::from_environment( crate_name.as_deref(), ), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4e762a40f0849..394c57c7214e7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -111,6 +111,10 @@ crate struct Context<'tcx> { /// real location of an item. This is used to allow external links to /// publicly reused items to redirect to the right location. crate render_redirect_pages: bool, + /// `None` by default, depends on the `generate-redirect-map` option flag. If this field is set + /// to `Some(...)`, it'll store redirections and then generate a JSON file at the top level of + /// the crate. + crate redirections: Option>>>, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, /// Tracks section IDs for `Deref` targets so they match in both the main @@ -404,6 +408,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { static_root_path, generate_search_filter, unstable_features, + generate_redirect_map, .. } = options; @@ -509,6 +514,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { all: Rc::new(RefCell::new(AllTypes::new())), errors: Rc::new(receiver), cache: Rc::new(cache), + redirections: if generate_redirect_map { Some(Default::default()) } else { None }, }; CURRENT_DEPTH.with(|s| s.set(0)); @@ -587,6 +593,15 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; + if let Some(redirections) = self.redirections.take() { + if !redirections.borrow().is_empty() { + let redirect_map_path = + self.dst.join(&*krate.name.as_str()).join("redirect-map.json"); + let paths = serde_json::to_string(&*redirections.borrow()).unwrap(); + self.shared.ensure_dir(&self.dst.join(&*krate.name.as_str()))?; + self.shared.fs.write(&redirect_map_path, paths.as_bytes())?; + } + } // Flush pending errors. Arc::get_mut(&mut self.shared).unwrap().fs.close(); @@ -675,9 +690,17 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // to the new one (without). if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); - let redir_dst = self.dst.join(redir_name); - let v = layout::redirect(file_name); - self.shared.fs.write(&redir_dst, v.as_bytes())?; + if let Some(ref redirections) = self.redirections { + let crate_name = &self.shared.layout.krate; + redirections.borrow_mut().insert( + format!("{}/{}", crate_name, redir_name), + format!("{}/{}", crate_name, file_name), + ); + } else { + let v = layout::redirect(file_name); + let redir_dst = self.dst.join(redir_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; + } } } Ok(()) @@ -1588,17 +1611,27 @@ impl Context<'_> { &self.shared.style_files, ) } else { - let mut url = self.root_path(); if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) { + let mut path = String::new(); for name in &names[..names.len() - 1] { - url.push_str(name); - url.push('/'); + path.push_str(name); + path.push('/'); + } + path.push_str(&item_path(ty, names.last().unwrap())); + match self.redirections { + Some(ref redirections) => { + let mut current_path = String::new(); + for name in &self.current { + current_path.push_str(name); + current_path.push('/'); + } + current_path.push_str(&item_path(ty, names.last().unwrap())); + redirections.borrow_mut().insert(current_path, path); + } + None => return layout::redirect(&format!("{}{}", self.root_path(), path)), } - url.push_str(&item_path(ty, names.last().unwrap())); - layout::redirect(&url) - } else { - String::new() } + String::new() } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6b37643a39580..c0e91a05dff54 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -497,6 +497,13 @@ fn opts() -> Vec { o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH") }), unstable("check", |o| o.optflag("", "check", "Run rustdoc checks")), + unstable("generate-redirect-map", |o| { + o.optflag( + "", + "generate-redirect-map", + "Generate JSON file at the top level instead of generating HTML redirection files", + ) + }), ] } diff --git a/src/test/run-make-fulldeps/rustdoc-map-file/Makefile b/src/test/run-make-fulldeps/rustdoc-map-file/Makefile new file mode 100644 index 0000000000000..ce977fa0cea55 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-map-file/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + $(RUSTDOC) -Z unstable-options --generate-redirect-map foo.rs -o "$(TMPDIR)/out" + "$(PYTHON)" validate_json.py "$(TMPDIR)/out" diff --git a/src/test/run-make-fulldeps/rustdoc-map-file/expected.json b/src/test/run-make-fulldeps/rustdoc-map-file/expected.json new file mode 100644 index 0000000000000..6b1ccbeac3010 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-map-file/expected.json @@ -0,0 +1,5 @@ +{ + "foo/macro.foo!.html": "foo/macro.foo.html", + "foo/private/struct.Quz.html": "foo/struct.Quz.html", + "foo/hidden/struct.Bar.html": "foo/struct.Bar.html" +} diff --git a/src/test/run-make-fulldeps/rustdoc-map-file/foo.rs b/src/test/run-make-fulldeps/rustdoc-map-file/foo.rs new file mode 100644 index 0000000000000..e12b9d2292c51 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-map-file/foo.rs @@ -0,0 +1,16 @@ +pub use private::Quz; +pub use hidden::Bar; + +mod private { + pub struct Quz; +} + +#[doc(hidden)] +pub mod hidden { + pub struct Bar; +} + +#[macro_export] +macro_rules! foo { + () => {} +} diff --git a/src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py b/src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py new file mode 100755 index 0000000000000..5c14c90b70d37 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-map-file/validate_json.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +import os +import sys +import json + + +def find_redirect_map_file(folder, errors): + for root, dirs, files in os.walk(folder): + for name in files: + if not name.endswith("redirect-map.json"): + continue + with open(os.path.join(root, name)) as f: + data = json.load(f) + with open("expected.json") as f: + expected = json.load(f) + for key in expected: + if expected[key] != data.get(key): + errors.append("Expected `{}` for key `{}`, found: `{}`".format( + expected[key], key, data.get(key))) + else: + del data[key] + for key in data: + errors.append("Extra data not expected: key: `{}`, data: `{}`".format( + key, data[key])) + return True + return False + + +if len(sys.argv) != 2: + print("Expected doc directory to check!") + sys.exit(1) + +errors = [] +if not find_redirect_map_file(sys.argv[1], errors): + print("Didn't find the map file in `{}`...".format(sys.argv[1])) + sys.exit(1) +for err in errors: + print("=> {}".format(err)) +if len(errors) != 0: + sys.exit(1) diff --git a/src/test/rustdoc/redirect-map-empty.rs b/src/test/rustdoc/redirect-map-empty.rs new file mode 100644 index 0000000000000..e9d021e0fa862 --- /dev/null +++ b/src/test/rustdoc/redirect-map-empty.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z unstable-options --generate-redirect-map + +#![crate_name = "foo"] + +// @!has foo/redirect-map.json +pub struct Foo; diff --git a/src/test/rustdoc/redirect-map.rs b/src/test/rustdoc/redirect-map.rs new file mode 100644 index 0000000000000..b7f16b64e3850 --- /dev/null +++ b/src/test/rustdoc/redirect-map.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z unstable-options --generate-redirect-map + +#![crate_name = "foo"] + +// @!has foo/private/struct.Quz.html +// @!has foo/hidden/struct.Bar.html +// @has foo/redirect-map.json +pub use private::Quz; +pub use hidden::Bar; + +mod private { + pub struct Quz; +} + +#[doc(hidden)] +pub mod hidden { + pub struct Bar; +} + +#[macro_export] +macro_rules! foo { + () => {} +} diff --git a/src/test/ui/simd/issue-17170.rs b/src/test/ui/simd/issue-17170.rs index 49cfbab9a3e6f..8d70dacdc9010 100644 --- a/src/test/ui/simd/issue-17170.rs +++ b/src/test/ui/simd/issue-17170.rs @@ -1,8 +1,8 @@ +// run-pass #![feature(repr_simd)] #[repr(simd)] struct T(f64, f64, f64); -//~^ ERROR SIMD vector length must be a power of two static X: T = T(0.0, 0.0, 0.0); diff --git a/src/test/ui/simd/issue-17170.stderr b/src/test/ui/simd/issue-17170.stderr deleted file mode 100644 index b35c3c4dc980d..0000000000000 --- a/src/test/ui/simd/issue-17170.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0075]: SIMD vector length must be a power of two - --> $DIR/issue-17170.rs:4:1 - | -LL | struct T(f64, f64, f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: monomorphising SIMD type `T` of non-power-of-two length - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0075`. diff --git a/src/test/ui/simd/issue-39720.rs b/src/test/ui/simd/issue-39720.rs index 7d5969265121c..8cf841f937121 100644 --- a/src/test/ui/simd/issue-39720.rs +++ b/src/test/ui/simd/issue-39720.rs @@ -1,3 +1,4 @@ +// run-pass // ignore-emscripten FIXME(#45351) #![feature(repr_simd, platform_intrinsics)] @@ -5,12 +6,10 @@ #[repr(simd)] #[derive(Copy, Clone, Debug)] pub struct Char3(pub i8, pub i8, pub i8); -//~^ ERROR SIMD vector length must be a power of two #[repr(simd)] #[derive(Copy, Clone, Debug)] pub struct Short3(pub i16, pub i16, pub i16); -//~^ ERROR SIMD vector length must be a power of two extern "platform-intrinsic" { fn simd_cast(x: T) -> U; diff --git a/src/test/ui/simd/issue-39720.stderr b/src/test/ui/simd/issue-39720.stderr deleted file mode 100644 index 355ceff00508a..0000000000000 --- a/src/test/ui/simd/issue-39720.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0075]: SIMD vector length must be a power of two - --> $DIR/issue-39720.rs:7:1 - | -LL | pub struct Char3(pub i8, pub i8, pub i8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0075]: SIMD vector length must be a power of two - --> $DIR/issue-39720.rs:12:1 - | -LL | pub struct Short3(pub i16, pub i16, pub i16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0075`. diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs index 3a0b9e02663d8..9b645d363e932 100644 --- a/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs +++ b/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.rs @@ -1,9 +1,7 @@ -// build-fail +// run-pass #![feature(repr_simd, platform_intrinsics)] -// error-pattern:monomorphising SIMD type `Simd<3_usize>` of non-power-of-two length - #[repr(simd)] struct Simd([f32; N]); diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.stderr b/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.stderr deleted file mode 100644 index 82cc0d8714aba..0000000000000 --- a/src/test/ui/simd/simd-type-generic-monomorphisation-power-of-two.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: monomorphising SIMD type `Simd<3_usize>` of non-power-of-two length - -error: aborting due to previous error - diff --git a/src/test/ui/simd/simd-type.rs b/src/test/ui/simd/simd-type.rs index cc7443d04856c..73d032a0c8e55 100644 --- a/src/test/ui/simd/simd-type.rs +++ b/src/test/ui/simd/simd-type.rs @@ -10,7 +10,7 @@ struct empty; //~ ERROR SIMD vector cannot be empty struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty #[repr(simd)] -struct pow2([f32; 7]); //~ ERROR SIMD vector length must be a power of two +struct pow2([f32; 7]); #[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous diff --git a/src/test/ui/simd/simd-type.stderr b/src/test/ui/simd/simd-type.stderr index 8b15ef05e032b..823f10f5daf20 100644 --- a/src/test/ui/simd/simd-type.stderr +++ b/src/test/ui/simd/simd-type.stderr @@ -10,12 +10,6 @@ error[E0075]: SIMD vector cannot be empty LL | struct empty2([f32; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0075]: SIMD vector length must be a power of two - --> $DIR/simd-type.rs:13:1 - | -LL | struct pow2([f32; 7]); - | ^^^^^^^^^^^^^^^^^^^^^^ - error[E0076]: SIMD vector should be homogeneous --> $DIR/simd-type.rs:16:1 | @@ -40,7 +34,7 @@ error[E0075]: SIMD vector cannot have more than 32768 elements LL | struct TooBig([f32; 65536]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0075, E0076, E0077. For more information about an error, try `rustc --explain E0075`. diff --git a/src/tools/cargo b/src/tools/cargo index 572e201536dc2..c68432f1e5cbb 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 572e201536dc2e4920346e28037b63c0f4d88b3c +Subproject commit c68432f1e5cbbc09833699a951b1b5b059651dff diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 209254a5d5e2f..1ab560ac09d4e 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,7 +5,9 @@ version = "0.0.0" edition = "2018" [dependencies] +colored = "2" diff = "0.1.10" +unified-diff = "0.2.1" getopts = "0.2" tracing = "0.1" tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 723c7f8683219..2e7b42b6c7cf2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -13,6 +13,7 @@ use crate::header::TestProps; use crate::json; use crate::util::get_pointer_width; use crate::util::{logv, PathBufExt}; +use crate::ColorConfig; use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; @@ -2440,12 +2441,43 @@ impl<'test> TestCx<'test> { } }) }; - let mut diff = Command::new("diff"); - // diff recursively, showing context, and excluding .css files - diff.args(&["-u", "-r", "-x", "*.css"]).args(&[&compare_dir, out_dir]); - let output = if let Some(pager) = pager { - let diff_pid = diff.stdout(Stdio::piped()).spawn().expect("failed to run `diff`"); + let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); + + { + let mut diff_output = File::create(&diff_filename).unwrap(); + for entry in walkdir::WalkDir::new(out_dir) { + let entry = entry.expect("failed to read file"); + let extension = entry.path().extension().and_then(|p| p.to_str()); + if entry.file_type().is_file() + && (extension == Some("html".into()) || extension == Some("js".into())) + { + let expected_path = + compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); + let expected = + if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; + let actual_path = entry.path(); + let actual = std::fs::read(&actual_path).unwrap(); + diff_output + .write_all(&unified_diff::diff( + &expected, + &expected_path.to_string_lossy(), + &actual, + &actual_path.to_string_lossy(), + 3, + )) + .unwrap(); + } + } + } + + match self.config.color { + ColorConfig::AlwaysColor => colored::control::set_override(true), + ColorConfig::NeverColor => colored::control::set_override(false), + _ => {} + } + + if let Some(pager) = pager { let pager = pager.trim(); if self.config.verbose { eprintln!("using pager {}", pager); @@ -2453,24 +2485,48 @@ impl<'test> TestCx<'test> { let output = Command::new(pager) // disable paging; we want this to be non-interactive .env("PAGER", "") - .stdin(diff_pid.stdout.unwrap()) + .stdin(File::open(&diff_filename).unwrap()) // Capture output and print it explicitly so it will in turn be // captured by libtest. .output() .unwrap(); assert!(output.status.success()); - output + println!("{}", String::from_utf8_lossy(&output.stdout)); + eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { - eprintln!("warning: no pager configured, falling back to `diff --color`"); + use colored::Colorize; + eprintln!("warning: no pager configured, falling back to unified diff"); eprintln!( "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`" ); - let output = diff.arg("--color").output().unwrap(); - assert!(output.status.success() || output.status.code() == Some(1)); - output + let mut out = io::stdout(); + let mut diff = BufReader::new(File::open(&diff_filename).unwrap()); + let mut line = Vec::new(); + loop { + line.truncate(0); + match diff.read_until(b'\n', &mut line) { + Ok(0) => break, + Ok(_) => {} + Err(e) => eprintln!("ERROR: {:?}", e), + } + match String::from_utf8(line.clone()) { + Ok(line) => { + if line.starts_with("+") { + write!(&mut out, "{}", line.green()).unwrap(); + } else if line.starts_with("-") { + write!(&mut out, "{}", line.red()).unwrap(); + } else if line.starts_with("@") { + write!(&mut out, "{}", line.blue()).unwrap(); + } else { + out.write_all(line.as_bytes()).unwrap(); + } + } + Err(_) => { + write!(&mut out, "{}", String::from_utf8_lossy(&line).reversed()).unwrap(); + } + } + } }; - println!("{}", String::from_utf8_lossy(&output.stdout)); - eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } fn run_rustdoc_json_test(&self) { diff --git a/triagebot.toml b/triagebot.toml index c0cf50e516700..8b6157cd4aae2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -102,6 +102,15 @@ message_on_add = """\ """ message_on_remove = "Issue #{number}'s prioritization request has been removed." +[notify-zulip."T-rustdoc"] +required_labels = ["I-nominated"] +zulip_stream = 266220 # #rustdoc +topic = "nominated: #{number}" +message_on_add = """\ +@*T-rustdoc* issue #{number} "{title}" has been nominated for `T-rustdoc` discussion. +""" +message_on_remove = "Issue #{number}'s nomination request has been removed." + [github-releases] format = "rustc" project-name = "Rust"