diff --git a/config.toml.example b/config.toml.example index c0be7dded17bc..2fa613755d64c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -378,7 +378,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 @@ -521,12 +521,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/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) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0208dc8ba5eb6..8e755756865b2 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -190,7 +190,7 @@ fn copy_self_contained_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( builder, @@ -279,8 +279,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 5728b9d24de99..b611af54565ac 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -888,6 +888,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!( 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/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 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, diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 1bd7ae3a34ebb..46e6ea7cd1866 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -358,12 +358,13 @@ 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 an extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [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 /// @@ -492,12 +493,13 @@ 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 an extern type tail. /// - otherwise, it is conservatively not allowed to call this function. /// /// [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 /// 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); 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/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f5b2f1bb5b178..8da74f375d9ce 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, result, ns); let result = match result { Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), _ => result.map_err(|_| ErrorKind::ResolutionFailure), @@ -202,7 +203,13 @@ 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 + ); + return Ok((res, extra_fragment.clone())); + } }; if value != (ns == ValueNS) { @@ -555,12 +562,13 @@ 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) = - ["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) @@ -614,7 +622,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 +767,32 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { item.attrs.links.push((ori_link, None, fragment)); } else { + 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; + + let hir_id = self.cx.tcx.hir().as_local_hir_id(local); + 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, + &err_msg, + "this item is private", + None, + ); + continue; + } + } let id = register_res(cx, res); item.attrs.links.push((ori_link, Some(id), fragment)); } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index f987eb67ea5f2..d972cf6db18cf 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1217,11 +1217,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")] @@ -1345,10 +1400,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")] 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 +