From 5c20ef433b48fce78c07208710bcc8b53965eeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 17 Jun 2020 00:00:00 +0000 Subject: [PATCH 01/13] bootstrap: Configurable musl libdir Make it possible to customize the location of musl libdir using musl-libdir in config.toml, e.g., to use lib64 instead of lib. --- config.toml.example | 9 ++++++--- src/bootstrap/compile.rs | 6 +++--- src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 9 +++++++++ src/bootstrap/sanity.rs | 8 ++++---- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/config.toml.example b/config.toml.example index d995554913f84..6214f2a68c596 100644 --- a/config.toml.example +++ b/config.toml.example @@ -359,7 +359,7 @@ # nightly features #channel = "dev" -# The root location of the MUSL installation directory. +# The root location of the musl installation directory. #musl-root = "..." # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix @@ -502,12 +502,15 @@ # only use static libraries. If unset, the target's default linkage is used. #crt-static = false -# The root location of the MUSL installation directory. The library directory +# The root location of the musl installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note -# that this option only makes sense for MUSL targets that produce statically +# that this option only makes sense for musl targets that produce statically # linked binaries #musl-root = "..." +# The full path to the musl libdir. +#musl-libdir = musl-root/lib + # The root location of the `wasm32-wasi` sysroot. #wasi-root = "..." diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c9c75aed7b0fb..62bca0015c063 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -133,7 +133,7 @@ fn copy_third_party_objects( // To do that we have to distribute musl startup objects as a part of Rust toolchain // and link with them manually in the self-contained mode. if target.contains("musl") { - let srcdir = builder.musl_root(target).unwrap().join("lib"); + let srcdir = builder.musl_libdir(target).unwrap(); for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { copy_and_stamp(&srcdir, obj); } @@ -219,8 +219,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, ca // Help the libc crate compile by assisting it in finding various // sysroot native libraries. if target.contains("musl") { - if let Some(p) = builder.musl_root(target) { - let root = format!("native={}/lib", p.to_str().unwrap()); + if let Some(p) = builder.musl_libdir(target) { + let root = format!("native={}", p.to_str().unwrap()); cargo.rustflag("-L").rustflag(&root); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 771f952abc013..ff545a6ddcf47 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -173,6 +173,7 @@ pub struct Target { pub ndk: Option, pub crt_static: Option, pub musl_root: Option, + pub musl_libdir: Option, pub wasi_root: Option, pub qemu_rootfs: Option, pub no_std: bool, @@ -363,6 +364,7 @@ struct TomlTarget { android_ndk: Option, crt_static: Option, musl_root: Option, + musl_libdir: Option, wasi_root: Option, qemu_rootfs: Option, no_std: Option, @@ -631,6 +633,7 @@ impl Config { target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static; target.musl_root = cfg.musl_root.clone().map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from); target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d8a036caef88..32f6e9605e765 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -877,6 +877,15 @@ impl Build { .map(|p| &**p) } + /// Returns the "musl libdir" for this `target`. + fn musl_libdir(&self, target: Interned) -> Option { + let t = self.config.target_config.get(&target)?; + if let libdir @ Some(_) = &t.musl_libdir { + return libdir.clone(); + } + self.musl_root(target).map(|root| root.join("lib")) + } + /// Returns the sysroot for the wasi target, if defined fn wasi_root(&self, target: Interned) -> Option<&Path> { self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 74b47d0772837..3301d41cfeefa 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -199,10 +199,10 @@ pub fn check(build: &mut Build) { let target = build.config.target_config.entry(target.clone()).or_default(); target.musl_root = Some("/usr".into()); } - match build.musl_root(*target) { - Some(root) => { - if fs::metadata(root.join("lib/libc.a")).is_err() { - panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); + match build.musl_libdir(*target) { + Some(libdir) => { + if fs::metadata(libdir.join("libc.a")).is_err() { + panic!("couldn't find libc.a in musl libdir: {}", libdir.display()); } } None => panic!( From 7cac20995eb2ed411dfea26a5391f12134877b11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jun 2020 12:21:38 +0200 Subject: [PATCH 02/13] add missing doc links --- src/libcore/mem/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 066bb8b3dc787..2f70515fce357 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -364,6 +364,7 @@ pub fn size_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html +/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html /// /// # Examples /// @@ -498,6 +499,7 @@ pub fn align_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html +/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html /// /// # Examples /// From 55d207a44fef01848fe7224869c97bc786bfd89c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jun 2020 12:23:37 +0200 Subject: [PATCH 03/13] tweak wording --- src/libcore/mem/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 2f70515fce357..70159402b6278 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -358,7 +358,7 @@ pub fn size_of_val(val: &T) -> usize { /// - an (unstable) [extern type], then this function is always safe to /// call, but may panic or otherwise return the wrong value, as the /// extern type's layout is not known. This is the same behavior as -/// [`size_of_val`] on a reference to an extern type tail. +/// [`size_of_val`] on a reference to a type with extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [slice]: ../../std/primitive.slice.html @@ -493,7 +493,7 @@ pub fn align_of_val(val: &T) -> usize { /// - an (unstable) [extern type], then this function is always safe to /// call, but may panic or otherwise return the wrong value, as the /// extern type's layout is not known. This is the same behavior as -/// [`align_of_val`] on a reference to an extern type tail. +/// [`align_of_val`] on a reference to a type with extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [slice]: ../../std/primitive.slice.html From cb8c94c523d7ff407f9520a6555ea829c1232a50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jun 2020 21:01:28 +0200 Subject: [PATCH 04/13] improve grammar Co-authored-by: Bastian Kauschke --- src/libcore/mem/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 70159402b6278..157dd5bc3cc89 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -358,7 +358,7 @@ pub fn size_of_val(val: &T) -> usize { /// - an (unstable) [extern type], then this function is always safe to /// call, but may panic or otherwise return the wrong value, as the /// extern type's layout is not known. This is the same behavior as -/// [`size_of_val`] on a reference to a type with extern type tail. +/// [`size_of_val`] on a reference to a type with an extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [slice]: ../../std/primitive.slice.html @@ -493,7 +493,7 @@ pub fn align_of_val(val: &T) -> usize { /// - an (unstable) [extern type], then this function is always safe to /// call, but may panic or otherwise return the wrong value, as the /// extern type's layout is not known. This is the same behavior as -/// [`align_of_val`] on a reference to a type with extern type tail. +/// [`align_of_val`] on a reference to a type with an extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [slice]: ../../std/primitive.slice.html From f44b8b96aa30d03c8e4de56a13f656a422910dec Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Wed, 24 Jun 2020 14:52:18 +0200 Subject: [PATCH 05/13] Document the Self keyword --- src/libstd/keyword_docs.rs | 59 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a4996d9eee810..74b7837593489 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1019,11 +1019,66 @@ mod self_keyword {} /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type /// definition. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// Within a type definition: +/// +/// ``` +/// # #![allow(dead_code)] +/// struct Node { +/// elem: i32, +/// // `Self` is a `Node` here. +/// next: Option>, +/// } +/// ``` +/// +/// In an [`impl`] block: +/// +/// ``` +/// struct Foo(i32); +/// +/// impl Foo { +/// fn new() -> Self { +/// Self(0) +/// } +/// } +/// +/// assert_eq!(Foo::new().0, Foo(0).0); +/// ``` +/// +/// Generic parameters are implicit with `Self`: +/// +/// ``` +/// # #![allow(dead_code)] +/// struct Wrap { +/// elem: T, +/// } +/// +/// impl Wrap { +/// fn new(elem: T) -> Self { +/// Self { elem } +/// } +/// } +/// ``` +/// +/// In a [`trait`] definition and related [`impl`] block: +/// +/// ``` +/// trait Example { +/// fn example() -> Self; +/// } +/// +/// struct Foo(i32); +/// +/// impl Example for Foo { +/// fn example() -> Self { +/// Self(42) +/// } +/// } +/// +/// assert_eq!(Foo::example().0, Foo(42).0); +/// ``` /// /// [`impl`]: keyword.impl.html /// [`trait`]: keyword.trait.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod self_upper_keyword {} #[doc(keyword = "static")] From 5232e2025f809aa64ce3f2ba8c31004b90800485 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Thu, 25 Jun 2020 11:40:07 +0200 Subject: [PATCH 06/13] Document the super keyword --- src/libstd/keyword_docs.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a4996d9eee810..25868c9cfebfd 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1147,10 +1147,26 @@ mod struct_keyword {} // /// The parent of the current [module]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// ```rust +/// # #![allow(dead_code)] +/// # fn main() {} +/// mod a { +/// pub fn foo() {} +/// } +/// mod b { +/// pub fn foo() { +/// super::a::foo(); // call a's foo function +/// } +/// } +/// ``` +/// +/// It is also possible to use `super` multiple times: `super::super::foo`, +/// going up the ancestor chain. +/// +/// See the [Reference] for more information. /// /// [module]: ../reference/items/modules.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// [Reference]: ../reference/paths.html#super mod super_keyword {} #[doc(keyword = "trait")] From 8b368dbcbb1ee67553f72837b0e9893e6912a5a9 Mon Sep 17 00:00:00 2001 From: Andrew Paverd Date: Thu, 25 Jun 2020 15:45:24 +0100 Subject: [PATCH 07/13] Bootstrap: fallback detection of Windows --- src/bootstrap/bootstrap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 82a755c7892b1..1949d70e5deea 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -184,6 +184,7 @@ def default_build_triple(): ostype = require(["uname", "-s"], exit=required) cputype = require(['uname', '-m'], exit=required) + # If we do not have `uname`, assume Windows. if ostype is None or cputype is None: return 'x86_64-pc-windows-msvc' @@ -236,6 +237,11 @@ def default_build_triple(): if ostype.endswith('WOW64'): cputype = 'x86_64' ostype = 'pc-windows-gnu' + elif sys.platform == 'win32': + # Some Windows platforms might have a `uname` command that returns a + # non-standard string (e.g. gnuwin32 tools returns `windows32`). In + # these cases, fall back to using sys.platform. + return 'x86_64-pc-windows-msvc' else: err = "unknown OS type: {}".format(ostype) sys.exit(err) From 1a355a21ebbe70ebfa2856dee2becc18d9ab3b13 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 25 Jun 2020 19:08:06 +0200 Subject: [PATCH 08/13] Document some invariants correctly/more --- src/librustc_mir/transform/const_prop.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index eb614170baae5..c7125a35165cf 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -350,14 +350,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } fn get_const(&self, place: Place<'tcx>) -> Option> { - let op = self.ecx.eval_place_to_op(place, None).ok(); + let op = match self.ecx.eval_place_to_op(place, None) { + Ok(op) => op, + Err(e) => { + trace!("get_const failed: {}", e); + return None; + } + }; // Try to read the local as an immediate so that if it is representable as a scalar, we can // handle it as such, but otherwise, just return the value as is. - match op.map(|ret| self.ecx.try_read_immediate(ret)) { - Some(Ok(Ok(imm))) => Some(imm.into()), + Some(match self.ecx.try_read_immediate(op) { + Ok(Ok(imm)) => imm.into(), _ => op, - } + }) } /// Remove `local` from the pool of `Locals`. Allows writing to them, @@ -857,8 +863,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { let can_const_prop = self.can_const_prop[place.local]; if let Some(()) = self.const_prop(rval, place_layout, source_info, place) { - // This will return None for variables that are from other blocks, - // so it should be okay to propagate from here on down. + // This will return None if the above `const_prop` invocation only "wrote" a + // type whose creation requires no write. E.g. a generator whose initial state + // consists solely of uninitialized memory (so it doesn't capture any locals). if let Some(value) = self.get_const(place) { if self.should_const_prop(value) { trace!("replacing {:?} with {:?}", rval, value); From 42062a58026cdb245e3eb365af726f2d9f4946af Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 22 Jun 2020 20:12:11 +0200 Subject: [PATCH 09/13] Shortcuts for min/max on ordinary BTreeMap/BTreeSet iterators --- src/liballoc/collections/btree/map.rs | 40 +++++++++++++++++++++++++++ src/liballoc/collections/btree/set.rs | 35 +++++++++++++++++++++++ src/liballoc/tests/btree/map.rs | 35 +++++++++++++++++++++++ src/liballoc/tests/btree/set.rs | 31 +++++++++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 34cacebe79636..bb9091a66594b 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1396,6 +1396,14 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { fn last(mut self) -> Option<(&'a K, &'a V)> { self.next_back() } + + fn min(mut self) -> Option<(&'a K, &'a V)> { + self.next() + } + + fn max(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1458,6 +1466,14 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { fn last(mut self) -> Option<(&'a K, &'a mut V)> { self.next_back() } + + fn min(mut self) -> Option<(&'a K, &'a mut V)> { + self.next() + } + + fn max(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1595,6 +1611,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn last(mut self) -> Option<&'a K> { self.next_back() } + + fn min(mut self) -> Option<&'a K> { + self.next() + } + + fn max(mut self) -> Option<&'a K> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1768,6 +1792,14 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { fn last(mut self) -> Option<(&'a K, &'a V)> { self.next_back() } + + fn min(mut self) -> Option<(&'a K, &'a V)> { + self.next() + } + + fn max(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1853,6 +1885,14 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { fn last(mut self) -> Option<(&'a K, &'a mut V)> { self.next_back() } + + fn min(mut self) -> Option<(&'a K, &'a mut V)> { + self.next() + } + + fn max(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 525ef38c32fa2..d8959966fe5ad 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1291,12 +1291,22 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option<&'a T> { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn last(mut self) -> Option<&'a T> { self.next_back() } + + fn min(mut self) -> Option<&'a T> { + self.next() + } + + fn max(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> DoubleEndedIterator for Iter<'a, T> { @@ -1321,6 +1331,7 @@ impl Iterator for IntoIter { fn next(&mut self) -> Option { self.iter.next().map(|(k, _)| k) } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } @@ -1359,6 +1370,14 @@ impl<'a, T> Iterator for Range<'a, T> { fn last(mut self) -> Option<&'a T> { self.next_back() } + + fn min(mut self) -> Option<&'a T> { + self.next() + } + + fn max(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "btree_range", since = "1.17.0")] @@ -1429,6 +1448,10 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { }; (self_len.saturating_sub(other_len), Some(self_len)) } + + fn min(mut self) -> Option<&'a T> { + self.next() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1460,6 +1483,10 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { // the number of elements to less than half the range of usize. (0, Some(a_len + b_len)) } + + fn min(mut self) -> Option<&'a T> { + self.next() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1516,6 +1543,10 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { IntersectionInner::Answer(Some(_)) => (1, Some(1)), } } + + fn min(mut self) -> Option<&'a T> { + self.next() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1541,6 +1572,10 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { // No checked_add - see SymmetricDifference::size_hint. (max(a_len, b_len), Some(a_len + b_len)) } + + fn min(mut self) -> Option<&'a T> { + self.next() + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 731a1b5f875b7..682d829d219f3 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -309,6 +309,41 @@ fn test_iter_mixed() { test(size, map.into_iter()); } +#[test] +fn test_iter_min_max() { + let mut a = BTreeMap::new(); + assert_eq!(a.iter().min(), None); + assert_eq!(a.iter().max(), None); + assert_eq!(a.iter_mut().min(), None); + assert_eq!(a.iter_mut().max(), None); + assert_eq!(a.range(..).min(), None); + assert_eq!(a.range(..).max(), None); + assert_eq!(a.range_mut(..).min(), None); + assert_eq!(a.range_mut(..).max(), None); + assert_eq!(a.keys().min(), None); + assert_eq!(a.keys().max(), None); + assert_eq!(a.values().min(), None); + assert_eq!(a.values().max(), None); + assert_eq!(a.values_mut().min(), None); + assert_eq!(a.values_mut().max(), None); + a.insert(1, 42); + a.insert(2, 24); + assert_eq!(a.iter().min(), Some((&1, &42))); + assert_eq!(a.iter().max(), Some((&2, &24))); + assert_eq!(a.iter_mut().min(), Some((&1, &mut 42))); + assert_eq!(a.iter_mut().max(), Some((&2, &mut 24))); + assert_eq!(a.range(..).min(), Some((&1, &42))); + assert_eq!(a.range(..).max(), Some((&2, &24))); + assert_eq!(a.range_mut(..).min(), Some((&1, &mut 42))); + assert_eq!(a.range_mut(..).max(), Some((&2, &mut 24))); + assert_eq!(a.keys().min(), Some(&1)); + assert_eq!(a.keys().max(), Some(&2)); + assert_eq!(a.values().min(), Some(&24)); + assert_eq!(a.values().max(), Some(&42)); + assert_eq!(a.values_mut().min(), Some(&mut 24)); + assert_eq!(a.values_mut().max(), Some(&mut 42)); +} + fn range_keys(map: &BTreeMap, range: impl RangeBounds) -> Vec { map.range(range) .map(|(&k, &v)| { diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 75251ca0d51e9..b6c34b7c6c346 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -33,6 +33,37 @@ fn test_hash() { assert_eq!(hash(&x), hash(&y)); } +#[test] +fn test_iter_min_max() { + let mut a = BTreeSet::new(); + assert_eq!(a.iter().min(), None); + assert_eq!(a.iter().max(), None); + assert_eq!(a.range(..).min(), None); + assert_eq!(a.range(..).max(), None); + assert_eq!(a.difference(&BTreeSet::new()).min(), None); + assert_eq!(a.difference(&BTreeSet::new()).max(), None); + assert_eq!(a.intersection(&a).min(), None); + assert_eq!(a.intersection(&a).max(), None); + assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), None); + assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), None); + assert_eq!(a.union(&a).min(), None); + assert_eq!(a.union(&a).max(), None); + a.insert(1); + a.insert(2); + assert_eq!(a.iter().min(), Some(&1)); + assert_eq!(a.iter().max(), Some(&2)); + assert_eq!(a.range(..).min(), Some(&1)); + assert_eq!(a.range(..).max(), Some(&2)); + assert_eq!(a.difference(&BTreeSet::new()).min(), Some(&1)); + assert_eq!(a.difference(&BTreeSet::new()).max(), Some(&2)); + assert_eq!(a.intersection(&a).min(), Some(&1)); + assert_eq!(a.intersection(&a).max(), Some(&2)); + assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), Some(&1)); + assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), Some(&2)); + assert_eq!(a.union(&a).min(), Some(&1)); + assert_eq!(a.union(&a).max(), Some(&2)); +} + fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where F: FnOnce(&BTreeSet, &BTreeSet, &mut dyn FnMut(&i32) -> bool) -> bool, From 6f8bec93990434b5da5060f05d1e9fa7116bc743 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 13 May 2020 00:21:54 -0400 Subject: [PATCH 10/13] Warn if linking to a private item --- src/librustdoc/lib.rs | 1 + .../passes/collect_intra_doc_links.rs | 30 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index de6fa3dbd4a89..4961dc2d4bcea 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -34,6 +34,7 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_mir; extern crate rustc_parse; +extern crate rustc_privacy; extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span as rustc_span; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f5b2f1bb5b178..a19d3afc2e3b1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -178,6 +178,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let result = cx.enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) }); + debug!("{} resolved to {:?} in namespace {:?}", path_str, ns, result); let result = match result { Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), _ => result.map_err(|_| ErrorKind::ResolutionFailure), @@ -202,7 +203,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } return Ok((res, Some(path_str.to_owned()))); } - _ => return Ok((res, extra_fragment.clone())), + other => { + debug!("failed to resolve {} in namespace {:?} (got {:?})", path_str, ns, other); + debug!("extra_fragment is {:?}", extra_fragment); + return Ok((res, extra_fragment.clone())); + } }; if value != (ns == ValueNS) { @@ -555,9 +560,11 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else { (parts[0].to_owned(), None) }; + let resolved_self; + let mut path_str; let (res, fragment) = { let mut kind = None; - let mut path_str = if let Some(prefix) = + path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"] .iter() .find(|p| link.starts_with(**p)) @@ -614,7 +621,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let base_node = if item.is_mod() && item.attrs.inner_docs { None } else { parent_node }; - let resolved_self; // replace `Self` with suitable item's parent name if path_str.starts_with("Self::") { if let Some(ref name) = parent_name { @@ -760,6 +766,24 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { item.attrs.links.push((ori_link, None, fragment)); } else { + // ~~WRONG: TODO: I think this happens too late and we need to instead put this in `self.resolve`~~ + debug!("item {:?} resolved to {:?}", item, res); + if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) { + let hir_id = self.cx.tcx.hir().as_local_hir_id(local); + if !self.cx.tcx.privacy_access_levels(rustc_hir::def_id::LOCAL_CRATE).is_exported(hir_id) { + let item_name = item.name.as_deref().unwrap_or(""); + build_diagnostic( + cx, + &item, + path_str, + &dox, + link_range, + &format!("public documentation for `{}` links to a private item", item_name), + "this item is private", + None, + ); + } + } let id = register_res(cx, res); item.attrs.links.push((ori_link, Some(id), fragment)); } From 20552c811a99a561f23b5918de9ffd95a06f815c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 30 May 2020 11:35:35 -0400 Subject: [PATCH 11/13] Generate docs for links to private items when passed --document-private - Pass around document_private a lot more - Add tests + Add tests for intra-doc links to private items + Add ignored tests for warnings in reference links --- src/librustdoc/config.rs | 14 ++++------ src/librustdoc/core.rs | 15 +++++----- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render.rs | 3 +- src/librustdoc/html/render/cache.rs | 6 ++++ src/librustdoc/lib.rs | 1 - .../passes/collect_intra_doc_links.rs | 28 +++++++++++++------ .../intra-links-private.public.stderr | 10 +++++++ src/test/rustdoc-ui/intra-links-private.rs | 10 +++++++ .../reference-link-has-one-warning.rs | 6 ++++ .../reference-link-has-one-warning.stderr | 10 +++++++ 11 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 src/test/rustdoc-ui/intra-links-private.public.stderr create mode 100644 src/test/rustdoc-ui/intra-links-private.rs create mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.rs create mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.stderr diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5dbcc5c9ec8b9..35b15cf717cee 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -123,10 +123,6 @@ pub struct Options { /// /// Be aware: This option can come both from the CLI and from crate attributes! pub default_passes: DefaultPassOption, - /// Document items that have lower than `pub` visibility. - pub document_private: bool, - /// Document items that have `doc(hidden)`. - pub document_hidden: bool, /// Any passes manually selected by the user. /// /// Be aware: This option can come both from the CLI and from crate attributes! @@ -177,8 +173,6 @@ impl fmt::Debug for Options { .field("test_args", &self.test_args) .field("persist_doctests", &self.persist_doctests) .field("default_passes", &self.default_passes) - .field("document_private", &self.document_private) - .field("document_hidden", &self.document_hidden) .field("manual_passes", &self.manual_passes) .field("display_warnings", &self.display_warnings) .field("show_coverage", &self.show_coverage) @@ -250,6 +244,10 @@ pub struct RenderOptions { pub generate_search_filter: bool, /// Option (disabled by default) to generate files used by RLS and some other tools. pub generate_redirect_pages: bool, + /// Document items that have lower than `pub` visibility. + pub document_private: bool, + /// Document items that have `doc(hidden)`. + pub document_hidden: bool, } impl Options { @@ -567,8 +565,6 @@ impl Options { should_test, test_args, default_passes, - document_private, - document_hidden, manual_passes, display_warnings, show_coverage, @@ -597,6 +593,8 @@ impl Options { markdown_playground_url, generate_search_filter, generate_redirect_pages, + document_private, + document_hidden, }, output_format, }) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1690b946bb625..8ab6c74289d17 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -62,6 +62,8 @@ pub struct DocContext<'tcx> { // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. pub generated_synthetics: RefCell, DefId)>>, pub auto_traits: Vec, + /// The options given to rustdoc that could be relevant to a pass. + pub render_options: RenderOptions, } impl<'tcx> DocContext<'tcx> { @@ -281,8 +283,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt describe_lints, lint_cap, mut default_passes, - mut document_private, - document_hidden, mut manual_passes, display_warnings, render_options, @@ -448,6 +448,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .cloned() .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) .collect(), + render_options, }; debug!("crate: {:?}", tcx.hir().krate()); @@ -524,7 +525,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } if attr.is_word() && name == sym::document_private_items { - document_private = true; + ctxt.render_options.document_private = true; } } @@ -544,9 +545,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt for p in passes { let run = match p.condition { Always => true, - WhenDocumentPrivate => document_private, - WhenNotDocumentPrivate => !document_private, - WhenNotDocumentHidden => !document_hidden, + WhenDocumentPrivate => ctxt.render_options.document_private, + WhenNotDocumentPrivate => !ctxt.render_options.document_private, + WhenNotDocumentHidden => !ctxt.render_options.document_hidden, }; if run { debug!("running pass {}", p.pass.name); @@ -556,7 +557,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt ctxt.sess().abort_if_errors(); - (krate, ctxt.renderinfo.into_inner(), render_options) + (krate, ctxt.renderinfo.into_inner(), ctxt.render_options) }) }) }) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e60ff37fd279a..a453a8b3dcb2a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -468,7 +468,7 @@ impl clean::Path { pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { let cache = cache(); - if !did.is_local() && !cache.access_levels.is_public(did) { + if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private { return None; } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1681b73d0c257..04c4685213b2e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -469,6 +469,7 @@ pub fn run( static_root_path, generate_search_filter, generate_redirect_pages, + document_private, .. } = options; @@ -546,7 +547,7 @@ pub fn run( scx.ensure_dir(&dst)?; krate = sources::render(&dst, &mut scx, krate)?; let (new_crate, index, cache) = - Cache::from_krate(renderinfo, &extern_html_root_urls, &dst, krate); + Cache::from_krate(renderinfo, document_private, &extern_html_root_urls, &dst, krate); krate = new_crate; let cache = Arc::new(cache); let mut cx = Context { diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 225940773413e..1b5c8a9378e41 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -91,6 +91,10 @@ crate struct Cache { /// The version of the crate being documented, if given from the `--crate-version` flag. pub crate_version: Option, + /// Whether to document private items. + /// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions. + pub document_private: bool, + // Private fields only used when initially crawling a crate to build a cache stack: Vec, parent_stack: Vec, @@ -126,6 +130,7 @@ crate struct Cache { impl Cache { pub fn from_krate( renderinfo: RenderInfo, + document_private: bool, extern_html_root_urls: &BTreeMap, dst: &Path, mut krate: clean::Crate, @@ -160,6 +165,7 @@ impl Cache { stripped_mod: false, access_levels, crate_version: krate.version.take(), + document_private, orphan_impl_items: Vec::new(), orphan_trait_impls: Vec::new(), traits: krate.external_traits.replace(Default::default()), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4961dc2d4bcea..de6fa3dbd4a89 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -34,7 +34,6 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_mir; extern crate rustc_parse; -extern crate rustc_privacy; extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span as rustc_span; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a19d3afc2e3b1..e4fe8996a233f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -204,7 +204,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return Ok((res, Some(path_str.to_owned()))); } other => { - debug!("failed to resolve {} in namespace {:?} (got {:?})", path_str, ns, other); + debug!( + "failed to resolve {} in namespace {:?} (got {:?})", + path_str, ns, other + ); debug!("extra_fragment is {:?}", extra_fragment); return Ok((res, extra_fragment.clone())); } @@ -564,10 +567,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let mut path_str; let (res, fragment) = { let mut kind = None; - path_str = if let Some(prefix) = - ["struct@", "enum@", "type@", "trait@", "union@"] - .iter() - .find(|p| link.starts_with(**p)) + path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"] + .iter() + .find(|p| link.starts_with(**p)) { kind = Some(TypeNS); link.trim_start_matches(prefix) @@ -766,22 +768,30 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { item.attrs.links.push((ori_link, None, fragment)); } else { - // ~~WRONG: TODO: I think this happens too late and we need to instead put this in `self.resolve`~~ - debug!("item {:?} resolved to {:?}", item, res); + debug!("linked item {} resolved to {:?}", path_str, res); if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) { + use rustc_hir::def_id::LOCAL_CRATE; + let hir_id = self.cx.tcx.hir().as_local_hir_id(local); - if !self.cx.tcx.privacy_access_levels(rustc_hir::def_id::LOCAL_CRATE).is_exported(hir_id) { + if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id) + && !self.cx.render_options.document_private + { let item_name = item.name.as_deref().unwrap_or(""); + let err_msg = format!( + "public documentation for `{}` links to a private item", + item_name + ); build_diagnostic( cx, &item, path_str, &dox, link_range, - &format!("public documentation for `{}` links to a private item", item_name), + &err_msg, "this item is private", None, ); + continue; } } let id = register_res(cx, res); diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr new file mode 100644 index 0000000000000..0a8dafdaf9466 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -0,0 +1,10 @@ +warning: `[DontDocMe]` public documentation for `DocMe` links to a private item + --> $DIR/intra-links-private.rs:6:11 + | +LL | /// docs [DontDocMe] + | ^^^^^^^^^ this item is private + | + = note: `#[warn(intra_doc_link_resolution_failure)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-links-private.rs new file mode 100644 index 0000000000000..b7906aba5b1a9 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-private.rs @@ -0,0 +1,10 @@ +// check-pass +// revisions: public private +// [private]compile-flags: --document-private-items +#![cfg_attr(private, deny(intra_doc_resolution_failure))] + +/// docs [DontDocMe] +//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item +// FIXME: for [private] we should also make sure the link was actually generated +pub struct DocMe; +struct DontDocMe; diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.rs b/src/test/rustdoc-ui/reference-link-has-one-warning.rs new file mode 100644 index 0000000000000..21cb7eb9040bd --- /dev/null +++ b/src/test/rustdoc-ui/reference-link-has-one-warning.rs @@ -0,0 +1,6 @@ +// ignore-test +// check-pass + +/// docs [label][with#anchor#error] +//~^ WARNING has an issue with the link anchor +pub struct S; diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.stderr b/src/test/rustdoc-ui/reference-link-has-one-warning.stderr new file mode 100644 index 0000000000000..5bbc62b76dd04 --- /dev/null +++ b/src/test/rustdoc-ui/reference-link-has-one-warning.stderr @@ -0,0 +1,10 @@ +warning: `[with#anchor#error]` has an issue with the link anchor. + --> $DIR/reference-link-has-one-warning.rs:3:18 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link + | + = note: `#[warn(intra_doc_link_resolution_failure)]` on by default + +warning: 1 warning emitted + From 67423821aa0dd705720c9e183d04d4b7a55b723f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 26 Jun 2020 08:24:45 -0400 Subject: [PATCH 12/13] Fix debug messages --- src/librustdoc/passes/collect_intra_doc_links.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index e4fe8996a233f..8da74f375d9ce 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let result = cx.enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) }); - debug!("{} resolved to {:?} in namespace {:?}", path_str, ns, result); + debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); let result = match result { Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), _ => result.map_err(|_| ErrorKind::ResolutionFailure), @@ -208,7 +208,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { "failed to resolve {} in namespace {:?} (got {:?})", path_str, ns, other ); - debug!("extra_fragment is {:?}", extra_fragment); return Ok((res, extra_fragment.clone())); } }; @@ -768,7 +767,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { item.attrs.links.push((ori_link, None, fragment)); } else { - debug!("linked item {} resolved to {:?}", path_str, res); + debug!("intra-doc link to {} resolved to {:?}", path_str, res); if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) { use rustc_hir::def_id::LOCAL_CRATE; From cb152eae2f63cc07e23142452d7e80b24392c284 Mon Sep 17 00:00:00 2001 From: "KRAAI, MATTHEW [VISUS]" Date: Fri, 26 Jun 2020 06:22:35 -0700 Subject: [PATCH 13/13] Remove blank line --- src/liballoc/raw_vec/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs index 6418c4a9823f2..5408faa079c15 100644 --- a/src/liballoc/raw_vec/tests.rs +++ b/src/liballoc/raw_vec/tests.rs @@ -12,7 +12,6 @@ fn allocator_param() { // // Instead, this just checks that the `RawVec` methods do at // least go through the Allocator API when it reserves - // storage. // A dumb allocator that consumes a fixed amount of fuel