From 7f2810f92cd1696eec9ae71ec657f6cb080dc61e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Aug 2024 11:43:19 -0700 Subject: [PATCH 1/7] Rewrite std_links This rewrites std_links for two major changes: - Uses pulldown_cmark to parse the markdown instead of using regular expressions. The RegEx approach was just too unreliable. - Call rustdoc only once, instead of once per chapter. The overhead of calling rustdoc is significant, and calling it for each chapter was extremely slow. Unfortunately the error messages are a little worse now, since it doesn't show which chapter a bad link came from. I'm uncertain how to make that better. --- mdbook-spec/Cargo.lock | 1 + mdbook-spec/Cargo.toml | 2 + mdbook-spec/src/lib.rs | 5 +- mdbook-spec/src/std_links.rs | 358 +++++++++++++++++++++++------------ 4 files changed, 246 insertions(+), 120 deletions(-) diff --git a/mdbook-spec/Cargo.lock b/mdbook-spec/Cargo.lock index 1fc0efaf5..ff835b409 100644 --- a/mdbook-spec/Cargo.lock +++ b/mdbook-spec/Cargo.lock @@ -407,6 +407,7 @@ dependencies = [ "mdbook", "once_cell", "pathdiff", + "pulldown-cmark", "regex", "semver", "serde_json", diff --git a/mdbook-spec/Cargo.toml b/mdbook-spec/Cargo.toml index a81915d82..703322cb0 100644 --- a/mdbook-spec/Cargo.toml +++ b/mdbook-spec/Cargo.toml @@ -13,6 +13,8 @@ anyhow = "1.0.79" mdbook = { version = "0.4.36", default-features = false } once_cell = "1.19.0" pathdiff = "0.2.1" +# Try to keep in sync with mdbook. +pulldown-cmark = { version = "0.10.3", default-features = false } regex = "1.9.4" semver = "1.0.21" serde_json = "1.0.113" diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 6591e4161..ef1d56501 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -154,7 +154,6 @@ impl Preprocessor for Spec { } ch.content = self.rule_definitions(&ch, &mut found_rules); ch.content = self.admonitions(&ch); - ch.content = std_links::std_links(&ch); }); // This is a separate pass because it relies on the modifications of // the previous passes. @@ -167,6 +166,10 @@ impl Preprocessor for Spec { } ch.content = self.auto_link_references(&ch, &found_rules); }); + // Final pass will resolve everything as a std link (or error if the + // link is unknown). + std_links::std_links(&mut book); + Ok(book) } } diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 0c7860b57..789518c4e 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -1,145 +1,199 @@ +//! Support for translating links to the standard library. + +use mdbook::book::Book; use mdbook::book::Chapter; +use mdbook::BookItem; use once_cell::sync::Lazy; -use regex::{Captures, Regex}; -use std::collections::HashSet; +use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; +use regex::Regex; +use std::collections::HashMap; use std::fmt::Write as _; use std::fs; use std::io::{self, Write as _}; +use std::ops::Range; +use std::path::PathBuf; use std::process::{self, Command}; use tempfile::TempDir; -/// A markdown link (without the brackets) that might possibly be a link to -/// the standard library using rustdoc's intra-doc notation. -const STD_LINK: &str = r"(?: [a-z]+@ )? - (?: std|core|alloc|proc_macro|test ) - (?: ::[A-Za-z0-9_!,:<>{}()\[\]]+ )?"; - -/// The Regex for a markdown link that might be a link to the standard library. -static STD_LINK_RE: Lazy = Lazy::new(|| { - Regex::new(&format!( - r"(?x) - (?: - ( \[`[^`]+`\] ) \( ({STD_LINK}) \) - ) - | (?: - ( \[`{STD_LINK}`\] ) - ) - " - )) - .unwrap() -}); - /// The Regex used to extract the std links from the HTML generated by rustdoc. static STD_LINK_EXTRACT_RE: Lazy = - Lazy::new(|| Regex::new(r#"
  • ]*href="(https://doc.rust-lang.org/[^"]+)""#).unwrap()); - -/// The Regex for a markdown link definition. -static LINK_DEF_RE: Lazy = Lazy::new(|| { - // This is a pretty lousy regex for a link definition. It doesn't - // handle things like blockquotes, code blocks, etc. Using a - // markdown parser isn't really feasible here, it would be nice to - // improve this. - Regex::new(r#"(?m)^(?
  • LINK: (.*)
  • "#).unwrap()); + +/// The Regex used to extract the URL from an HTML link. +static ANCHOR_URL: Lazy = Lazy::new(|| Regex::new(" = Lazy::new(|| Regex::new(r"(?s)(\[.+\])(\(.+\))").unwrap()); +/// Regex for a markdown reference link, like `[foo][bar]`. +static MD_LINK_REFERENCE: Lazy = Lazy::new(|| Regex::new(r"(?s)(\[.+\])(\[.*\])").unwrap()); +/// Regex for a markdown shortcut link, like `[foo]`. +static MD_LINK_SHORTCUT: Lazy = Lazy::new(|| Regex::new(r"(?s)(\[.+\])").unwrap()); /// Converts links to the standard library to the online documentation in a /// fashion similar to rustdoc intra-doc links. -pub fn std_links(chapter: &Chapter) -> String { - let links = collect_markdown_links(chapter); - if links.is_empty() { - return chapter.content.clone(); +pub fn std_links(book: &mut Book) { + // Collect all links in all chapters. + let mut chapter_links = HashMap::new(); + for item in book.iter() { + let BookItem::Chapter(ch) = item else { + continue; + }; + if ch.is_draft_chapter() { + continue; + } + let key = ch.source_path.as_ref().unwrap(); + chapter_links.insert(key, collect_markdown_links(&ch)); } - // Write a Rust source file to use with rustdoc to generate intra-doc links. let tmp = TempDir::with_prefix("mdbook-spec-").unwrap(); - run_rustdoc(&tmp, &links, &chapter); + run_rustdoc(&tmp, &chapter_links); // Extract the links from the generated html. let generated = fs::read_to_string(tmp.path().join("doc/a/index.html")).expect("index.html generated"); - let urls: Vec<_> = STD_LINK_EXTRACT_RE + let mut urls: Vec<_> = STD_LINK_EXTRACT_RE .captures_iter(&generated) .map(|cap| cap.get(1).unwrap().as_str()) .collect(); - if urls.len() != links.len() { + let expected_len: usize = chapter_links.values().map(|l| l.len()).sum(); + if urls.len() != expected_len { eprintln!( - "error: expected rustdoc to generate {} links, but found {} in chapter {} ({:?})", - links.len(), + "error: expected rustdoc to generate {} links, but found {}", + expected_len, urls.len(), - chapter.name, - chapter.source_path.as_ref().unwrap() ); process::exit(1); } + // Unflatten the urls list so that it is split back by chapter. + let mut ch_urls: HashMap<&PathBuf, Vec<_>> = HashMap::new(); + for (ch_path, links) in &chapter_links { + let rest = urls.split_off(links.len()); + ch_urls.insert(ch_path, urls); + urls = rest; + } - // Replace any disambiguated links with just the disambiguation. - let mut output = STD_LINK_RE - .replace_all(&chapter.content, |caps: &Captures<'_>| { - if let Some(dest) = caps.get(2) { - // Replace destination parenthesis with a link definition (square brackets). - format!("{}[{}]", &caps[1], dest.as_str()) - } else { - caps[0].to_string() - } - }) - .to_string(); - - // Append the link definitions to the bottom of the chapter. - write!(output, "\n").unwrap(); - for ((link, dest), url) in links.iter().zip(urls) { - // Convert links to be relative so that links work offline and - // with the linkchecker. - let url = relative_url(url, chapter); - if let Some(dest) = dest { - write!(output, "[{dest}]: {url}\n").unwrap(); - } else { - write!(output, "{link}: {url}\n").unwrap(); + // Do this in two passes to deal with lifetimes. + let mut ch_contents = HashMap::new(); + for item in book.iter() { + let BookItem::Chapter(ch) = item else { + continue; + }; + if ch.is_draft_chapter() { + continue; } + let key = ch.source_path.as_ref().unwrap(); + // Create a list of replacements to make in the raw markdown to point to the new url. + let replacements = compute_replacements(&ch.content, &chapter_links[key], &ch_urls[key]); + + let mut new_contents = ch.content.to_string(); + for (md_link, url, range) in replacements { + // Convert links to be relative so that links work offline and + // with the linkchecker. + let url = relative_url(url, ch); + // Note that this may orphan reference link definitions. This should + // probably remove them, but pulldown_cmark doesn't give the span for + // the reference definition. + new_contents.replace_range(range, &format!("{md_link}({url})")); + } + ch_contents.insert(key.clone(), new_contents); } - output + // Replace the content with the new content. + book.for_each_mut(|item| { + let BookItem::Chapter(ch) = item else { + return; + }; + if ch.is_draft_chapter() { + return; + } + let key = ch.source_path.as_ref().unwrap(); + let content = ch_contents.remove(key).unwrap(); + ch.content = content; + }); } -/// Collects all markdown links, excluding those that already have link definitions. -/// -/// Returns a `Vec` of `(link, Option)` where markdown text like -/// ``[`std::fmt`]`` would return that as a link. The dest is optional, for -/// example ``[`Option`](std::option::Option)`` would have the part in -/// parentheses as the dest. -fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> { - let mut links: Vec<_> = STD_LINK_RE - .captures_iter(&chapter.content) - .map(|cap| { - if let Some(no_dest) = cap.get(3) { - (no_dest.as_str(), None) - } else { - ( - cap.get(1).unwrap().as_str(), - Some(cap.get(2).unwrap().as_str()), - ) - } - }) - .collect(); - if links.is_empty() { - return vec![]; - } - links.sort(); - links.dedup(); - // Remove any links that already have a link definition. We don't want - // to override what the author explicitly specified. - let existing_labels: HashSet<_> = LINK_DEF_RE - .captures_iter(&chapter.content) - .map(|cap| cap.get(1).unwrap().as_str()) - .collect(); - links.retain(|(link, dest)| { - let mut tmp = None; - let label: &str = dest.map_or(link, |d| { - tmp = Some(format!("[`{d}`]")); - tmp.as_deref().unwrap() +#[derive(Debug)] +struct Link<'a> { + link_type: LinkType, + /// Where the link is going to, for example `std::ffi::OsString`. + dest_url: CowStr<'a>, + /// The span in the original markdown where the link is located. + /// + /// Note that during translation, all links will be converted to inline + /// links. That means that for reference-style links, the link reference + /// definition will end up being ignored in the final markdown. For + /// example, a link like ``[`OsString`]`` with a definition + /// ``[`OsString`]: std::ffi::OsString`` will convert the link to + /// ``[`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html)`. + range: Range, +} + +/// Collects all markdown links that look like they might be standard library links. +fn collect_markdown_links<'a>(chapter: &'a Chapter) -> Vec> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + opts.insert(Options::ENABLE_HEADING_ATTRIBUTES); + opts.insert(Options::ENABLE_SMART_PUNCTUATION); + + let mut broken_links = Vec::new(); + let mut links = Vec::new(); + + // Broken links are collected so that you can write something like + // `[std::option::Option]` which in pulldown_cmark's eyes is a broken + // link. However, that is the normal syntax for rustdoc. + let broken_link = |broken_link: BrokenLink| { + broken_links.push(Link { + link_type: broken_link.link_type, + // Necessary due to lifetime issues. + dest_url: CowStr::Boxed(broken_link.reference.into_string().into()), + range: broken_link.span.clone(), }); - !existing_labels.contains(label) - }); + None + }; + let parser = Parser::new_with_broken_link_callback(&chapter.content, opts, Some(broken_link)) + .into_offset_iter(); + for (event, range) in parser { + match event { + Event::Start(Tag::Link { + link_type, + dest_url, + title, + id: _, + }) => { + // Only collect links that are for the standard library. + if matches!(link_type, LinkType::Autolink | LinkType::Email) { + continue; + } + if dest_url.starts_with("http") + || dest_url.contains(".md") + || dest_url.contains(".html") + || dest_url.starts_with('#') + { + continue; + } + if !title.is_empty() { + eprintln!( + "error: titles in links are not supported\n\ + Link {dest_url} has title `{title}` found in chapter {} ({:?})", + chapter.name, + chapter.source_path.as_ref().unwrap() + ); + process::exit(1); + } + links.push(Link { + link_type, + dest_url, + range: range.clone(), + }); + } + _ => {} + } + } + links.extend(broken_links); links } @@ -150,7 +204,7 @@ fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> { /// generate intra-doc links on them. /// /// The output will be in the given `tmp` directory. -fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) { +fn run_rustdoc(tmp: &TempDir, chapter_links: &HashMap<&PathBuf, Vec>) { let src_path = tmp.path().join("a.rs"); // Allow redundant since there could some in-scope things that are // technically not necessary, but we don't care about (like @@ -159,13 +213,29 @@ fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) "#![deny(rustdoc::broken_intra_doc_links)]\n\ #![allow(rustdoc::redundant_explicit_links)]\n" ); - for (link, dest) in links { - write!(src, "//! - {link}").unwrap(); - if let Some(dest) = dest { - write!(src, "({})", dest).unwrap(); + // This uses a list to make easy to pull the links out of the generated HTML. + for (_ch_path, links) in chapter_links { + for link in links { + match link.link_type { + LinkType::Inline + | LinkType::Reference + | LinkType::Collapsed + | LinkType::Shortcut => { + writeln!(src, "//! - LINK: [{}]", link.dest_url).unwrap(); + } + LinkType::ReferenceUnknown + | LinkType::CollapsedUnknown + | LinkType::ShortcutUnknown => { + // These should only happen due to broken link replacements. + panic!("unexpected link type unknown {link:?}"); + } + LinkType::Autolink | LinkType::Email => { + panic!("link type should have been filtered {link:?}"); + } + } } - src.push('\n'); } + // Put some common things into scope so that links to them work. writeln!( src, "extern crate alloc;\n\ @@ -182,12 +252,7 @@ fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) .output() .expect("rustdoc installed"); if !output.status.success() { - eprintln!( - "error: failed to extract std links ({:?}) in chapter {} ({:?})\n", - output.status, - chapter.name, - chapter.source_path.as_ref().unwrap() - ); + eprintln!("error: failed to extract std links ({:?})\n", output.status,); io::stderr().write_all(&output.stderr).unwrap(); process::exit(1); } @@ -202,7 +267,7 @@ fn relative_url(url: &str, chapter: &Chapter) -> String { // Set SPEC_RELATIVE=0 to disable this, which can be useful for working locally. if std::env::var("SPEC_RELATIVE").as_deref() != Ok("0") { let Some(url_start) = DOC_URL.shortest_match(url) else { - eprintln!("expected rustdoc URL to start with {DOC_URL:?}, got {url}"); + eprintln!("error: expected rustdoc URL to start with {DOC_URL:?}, got {url}"); std::process::exit(1); }; let url_path = &url[url_start..]; @@ -213,3 +278,58 @@ fn relative_url(url: &str, chapter: &Chapter) -> String { url.to_string() } } + +/// Computes the replacements to make in the markdown content. +/// +/// Returns a `Vec` of `(md_link, url, range)` where: +/// +/// - `md_link` is the markdown link string to show to the user (like `[foo]`). +/// - `url` is the URL to the standard library. +/// - `range` is the range in the original markdown to replace with the new link. +fn compute_replacements<'a>( + contents: &'a str, + links: &[Link<'_>], + urls: &[&'a str], +) -> Vec<(&'a str, &'a str, Range)> { + let mut replacements = Vec::new(); + + for (url, link) in urls.into_iter().zip(links) { + let Some(cap) = ANCHOR_URL.captures(url) else { + eprintln!("error: could not find anchor in:\n{url}\nlink={link:#?}"); + process::exit(1); + }; + let url = cap.get(1).unwrap().as_str(); + let md_link = &contents[link.range.clone()]; + + let range = link.range.clone(); + let add_link = |re: &Regex| { + let Some(cap) = re.captures(md_link) else { + eprintln!( + "error: expected link `{md_link}` of type {:?} to match regex {re}", + link.link_type + ); + process::exit(1); + }; + let md_link = cap.get(1).unwrap().as_str(); + replacements.push((md_link, url, range)); + }; + + match link.link_type { + LinkType::Inline => { + add_link(&MD_LINK_INLINE); + } + LinkType::Reference | LinkType::Collapsed => { + add_link(&MD_LINK_REFERENCE); + } + LinkType::Shortcut => { + add_link(&MD_LINK_SHORTCUT); + } + _ => { + panic!("unexpected link type: {link:#?}"); + } + } + } + // Sort and reverse (so that it can replace bottom-up so ranges don't shift). + replacements.sort_by(|a, b| b.2.clone().partial_cmp(a.2.clone()).unwrap()); + replacements +} From c53965bd68c2737697016892f0aa36be6b2f9cf6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Aug 2024 11:43:51 -0700 Subject: [PATCH 2/7] Switch mdbook-spec to build with release This should speed things up a little, particularly when working locally. --- book.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book.toml b/book.toml index 77b8b88a0..404b8cca8 100644 --- a/book.toml +++ b/book.toml @@ -18,7 +18,7 @@ smart-punctuation = true edition = "2021" [preprocessor.spec] -command = "cargo run --manifest-path mdbook-spec/Cargo.toml" +command = "cargo run --release --manifest-path mdbook-spec/Cargo.toml" [build] extra-watch-dirs = ["mdbook-spec/src"] From 52e0ff3c11260fb86f19e564684c86560eab4ff9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Aug 2024 11:46:37 -0700 Subject: [PATCH 3/7] Switch to automatic standard library links This removes the explicit links to the standard library. In particular, this makes it nicer to view locally since you can set SPEC_RELATIVE=0 to make the links work. There are a bunch of changes to the actual URL because rustdoc resolves re-exports to link to the original definition instead of the re-export site. From what I can tell, everything should otherwise be the same. Not all links were able to be converted due to some limitations in rustdoc, such as: - Links to rexports from std_arch don't work due to https://github.com/rust-lang/rust/issues/96506. - Links to keywords aren't supported. - Links to trait impls where the trait is not in the prelude doesn't work (they must be in scope). --- src/attributes/codegen.md | 4 +--- src/attributes/derive.md | 2 -- src/attributes/diagnostics.md | 1 - src/attributes/testing.md | 6 +++--- src/behavior-considered-undefined.md | 10 ++++----- src/conditional-compilation.md | 3 --- src/crates-and-source-files.md | 8 +++---- src/destructors.md | 7 +------ src/expressions.md | 1 - src/expressions/array-expr.md | 4 ++-- src/expressions/await-expr.md | 16 +++++++------- src/expressions/block-expr.md | 2 -- src/expressions/call-expr.md | 7 ++----- src/expressions/literal-expr.md | 9 +------- src/expressions/method-call-expr.md | 2 +- src/expressions/operator-expr.md | 4 ++-- src/inline-assembly.md | 6 +++--- src/input-format.md | 3 --- src/interior-mutability.md | 5 ----- src/introduction.md | 2 +- src/items/enumerations.md | 3 +-- src/items/functions.md | 2 +- src/items/unions.md | 6 ++---- src/names/preludes.md | 15 +------------- src/procedural-macros.md | 13 ++++++------ src/runtime.md | 6 +++--- src/special-types-and-traits.md | 31 +++++++++------------------- src/tokens.md | 2 +- src/type-coercions.md | 4 ++-- src/type-layout.md | 14 ++++++------- src/types/array.md | 1 - src/types/boolean.md | 3 +-- src/types/closure.md | 3 --- src/types/function-item.md | 3 --- src/types/pointer.md | 2 -- src/types/union.md | 1 - src/unsafe-keyword.md | 2 +- 37 files changed, 69 insertions(+), 144 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 0ccc01361..f30c296bc 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -427,9 +427,7 @@ trait object whose methods are attributed. [undefined behavior]: ../behavior-considered-undefined.md [unsafe function]: ../unsafe-keyword.md [rust-abi]: ../items/external-blocks.md#abi -[`core::intrinsics::caller_location`]: ../../core/intrinsics/fn.caller_location.html -[`core::panic::Location::caller`]: ../../core/panic/struct.Location.html#method.caller -[`Location`]: ../../core/panic/struct.Location.html +[`Location`]: core::panic::Location ## The `instruction_set` attribute diff --git a/src/attributes/derive.md b/src/attributes/derive.md index bb5631f7a..44ce8c7b3 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -37,8 +37,6 @@ has no direct effect, but it may be used by tools and diagnostic lints to detect these automatically generated implementations. [_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax -[`Clone`]: ../../std/clone/trait.Clone.html -[`PartialEq`]: ../../std/cmp/trait.PartialEq.html [`impl` item]: ../items/implementations.md [items]: ../items.md [derive macros]: ../procedural-macros.md#derive-macros diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 4f1af4db6..34dab5913 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -491,7 +491,6 @@ error[E0277]: My Message for `ImportantTrait` implemented for `String` = note: Note 2 ``` -[`std::fmt`]: ../../std/fmt/index.html [Clippy]: https://github.com/rust-lang/rust-clippy [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 2c3b29286..a2db083a7 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -82,8 +82,8 @@ fn mytest() { [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: ../attributes.md#meta-item-attribute-syntax -[`Termination`]: ../../std/process/trait.Termination.html -[`report`]: ../../std/process/trait.Termination.html#tymethod.report +[`Termination`]: std::process::Termination +[`report`]: std::process::Termination::report [`test` conditional compilation option]: ../conditional-compilation.md#test [attributes]: ../attributes.md -[`ExitCode`]: ../../std/process/struct.ExitCode.html +[`ExitCode`]: std::process::ExitCode diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 69c44bc4c..14d8edeff 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -30,7 +30,7 @@ Please read the [Rustonomicon] before writing unsafe code. * Accessing (loading from or storing to) a place that is [dangling] or [based on a misaligned pointer]. * Performing a place projection that violates the requirements of [in-bounds - pointer arithmetic][offset]. A place projection is a [field + pointer arithmetic](pointer#method.offset). A place projection is a [field expression][project-field], a [tuple index expression][project-tuple], or an [array/slice index expression][project-slice]. * Breaking the [pointer aliasing rules]. `Box`, `&mut T` and `&T` follow @@ -176,16 +176,14 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" [pointer aliasing rules]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules [undef]: http://llvm.org/docs/LangRef.html#undefined-values [`target_feature`]: attributes/codegen.md#the-target_feature-attribute -[`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html +[`UnsafeCell`]: std::cell::UnsafeCell [Rustonomicon]: ../nomicon/index.html -[`NonNull`]: ../core/ptr/struct.NonNull.html -[`NonZero`]: ../core/num/struct.NonZero.html -[`Box`]: ../alloc/boxed/struct.Box.html +[`NonNull`]: core::ptr::NonNull +[`NonZero`]: core::num::NonZero [place expression context]: expressions.md#place-expressions-and-value-expressions [rules]: inline-assembly.md#rules-for-inline-assembly [points to]: #pointed-to-bytes [pointed to]: #pointed-to-bytes -[offset]: ../std/primitive.pointer.html#method.offset [project-field]: expressions/field-expr.md [project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions [project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f98b3230e..e445475dc 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -201,8 +201,6 @@ atomic loads, stores, and compare-and-swap operations. When this cfg is present, all of the stable [`core::sync::atomic`] APIs are available for the relevant atomic width. -[`core::sync::atomic`]: ../core/sync/atomic/index.html - Possible values: * `"8"` @@ -374,7 +372,6 @@ println!("I'm running on a {} machine!", machine_kind); [`cfg`]: #the-cfg-attribute [`cfg` macro]: #the-cfg-macro [`cfg_attr`]: #the-cfg_attr-attribute -[`debug_assert!`]: ../std/macro.debug_assert.html [`target_feature` attribute]: attributes/codegen.md#the-target_feature-attribute [attribute]: attributes.md [attributes]: attributes.md diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index b0e607bb9..426ee26f1 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -129,14 +129,14 @@ or `_` (U+005F) characters. ECMA-335 CLI model, a *library* in the SML/NJ Compilation Manager, a *unit* in the Owens and Flatt module system, or a *configuration* in Mesa. -[Unicode alphanumeric]: ../std/primitive.char.html#method.is_alphanumeric +[Unicode alphanumeric]: char::is_alphanumeric [`!`]: types/never.md [_InnerAttribute_]: attributes.md [_Item_]: items.md [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax -[`ExitCode`]: ../std/process/struct.ExitCode.html -[`Infallible`]: ../std/convert/enum.Infallible.html -[`Termination`]: ../std/process/trait.Termination.html +[`ExitCode`]: std::process::ExitCode +[`Infallible`]: std::convert::Infallible +[`Termination`]: std::process::Termination [attribute]: attributes.md [attributes]: attributes.md [function]: items/functions.md diff --git a/src/destructors.md b/src/destructors.md index 9c426426c..680a9623f 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -8,7 +8,7 @@ dropped. The destructor of a type `T` consists of: -1. If `T: Drop`, calling [`::drop`] +1. If `T: Drop`, calling [`::drop`](std::ops::Drop::drop) 2. Recursively running the destructor of all of its fields. * The fields of a [struct] are dropped in declaration order. * The fields of the active [enum variant] are dropped in declaration order. @@ -400,8 +400,3 @@ variable or field from being dropped automatically. [`match`]: expressions/match-expr.md [`while let`]: expressions/loop-expr.md#predicate-pattern-loops [`while`]: expressions/loop-expr.md#predicate-loops - -[`::drop`]: ../std/ops/trait.Drop.html#tymethod.drop -[`std::ptr::drop_in_place`]: ../std/ptr/fn.drop_in_place.html -[`std::mem::forget`]: ../std/mem/fn.forget.html -[`std::mem::ManuallyDrop`]: ../std/mem/struct.ManuallyDrop.html diff --git a/src/expressions.md b/src/expressions.md index 9e10dcea3..208ac9506 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -284,7 +284,6 @@ They are never allowed before: [destructors]: destructors.md [drop scope]: destructors.md#drop-scopes -[`Box`]: ../std/boxed/struct.Box.html [`Copy`]: special-types-and-traits.md#copy [`Drop`]: special-types-and-traits.md#drop [`Sized`]: special-types-and-traits.md#sized diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index fd7e2d378..52d31940d 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -76,8 +76,8 @@ arr[10]; // warning: index out of bounds The array index expression can be implemented for types other than arrays and slices by implementing the [Index] and [IndexMut] traits. [`Copy`]: ../special-types-and-traits.md#copy -[IndexMut]: ../../std/ops/trait.IndexMut.html -[Index]: ../../std/ops/trait.Index.html +[IndexMut]: std::ops::IndexMut +[Index]: std::ops::Index [_Expression_]: ../expressions.md [array]: ../types/array.md [constant expression]: ../const_eval.md#constant-expressions diff --git a/src/expressions/await-expr.md b/src/expressions/await-expr.md index feea1a368..ae129890f 100644 --- a/src/expressions/await-expr.md +++ b/src/expressions/await-expr.md @@ -49,12 +49,12 @@ The variable `current_context` refers to the context taken from the async enviro [_Expression_]: ../expressions.md [`async fn`]: ../items/functions.md#async-functions [`async` block]: block-expr.md#async-blocks -[`context`]: ../../std/task/struct.Context.html -[`future::poll`]: ../../std/future/trait.Future.html#tymethod.poll -[`pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked -[`poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending -[`poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready +[`Context`]: std::task::Context +[`future::poll`]: std::future::Future::poll +[`pin::new_unchecked`]: std::pin::Pin::new_unchecked +[`poll::Pending`]: std::task::Poll::Pending +[`poll::Ready`]: std::task::Poll::Ready [async context]: ../expressions/block-expr.md#async-context -[future]: ../../std/future/trait.Future.html -[`IntoFuture`]: ../../std/future/trait.IntoFuture.html -[`IntoFuture::into_future`]: ../../std/future/trait.IntoFuture.html#tymethod.into_future +[future]: std::future::Future +[`IntoFuture`]: std::future::IntoFuture +[`IntoFuture::into_future`]: std::future::IntoFuture::into_future diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 08baec39d..55936e38b 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -231,8 +231,6 @@ fn is_unix_platform() -> bool { [`cfg`]: ../conditional-compilation.md [`for`]: loop-expr.md#iterator-loops [`loop`]: loop-expr.md#infinite-loops -[`std::ops::Fn`]: ../../std/ops/trait.Fn.html -[`std::future::Future`]: ../../std/future/trait.Future.html [`unsafe` blocks]: ../unsafe-keyword.md#unsafe-blocks-unsafe- [`while let`]: loop-expr.md#predicate-pattern-loops [`while`]: loop-expr.md#predicate-loops diff --git a/src/expressions/call-expr.md b/src/expressions/call-expr.md index 7a01e92e1..64df58ce4 100644 --- a/src/expressions/call-expr.md +++ b/src/expressions/call-expr.md @@ -87,11 +87,8 @@ Refer to [RFC 132] for further details and motivations. [RFC 132]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md [_Expression_]: ../expressions.md -[`default()`]: ../../std/default/trait.Default.html#tymethod.default -[`size_of()`]: ../../std/mem/fn.size_of.html -[`std::ops::FnMut`]: ../../std/ops/trait.FnMut.html -[`std::ops::FnOnce`]: ../../std/ops/trait.FnOnce.html -[`std::ops::Fn`]: ../../std/ops/trait.Fn.html +[`default()`]: std::default::Default::default +[`size_of()`]: std::mem::size_of [automatically dereferenced]: field-expr.md#automatic-dereferencing [fully-qualified syntax]: ../paths.md#qualified-paths [non-function types]: ../types/function-item.md diff --git a/src/expressions/literal-expr.md b/src/expressions/literal-expr.md index 2d8d5f9b7..221690787 100644 --- a/src/expressions/literal-expr.md +++ b/src/expressions/literal-expr.md @@ -419,7 +419,7 @@ The expression's type is the primitive [boolean type], and its value is: [String continuation escapes]: #string-continuation-escapes [boolean type]: ../types/boolean.md [constant expression]: ../const_eval.md#constant-expressions -[CStr]: ../../core/ffi/struct.CStr.html +[CStr]: core::ffi::CStr [floating-point types]: ../types/numeric.md#floating-point-types [lint check]: ../attributes/diagnostics.md#lint-check-attributes [literal tokens]: ../tokens.md#literals @@ -432,14 +432,7 @@ The expression's type is the primitive [boolean type], and its value is: [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value [Unicode scalar values]: http://www.unicode.org/glossary/#unicode_scalar_value [`f32::from_str`]: ../../core/primitive.f32.md#method.from_str -[`f32::INFINITY`]: ../../core/primitive.f32.md#associatedconstant.INFINITY -[`f32::NAN`]: ../../core/primitive.f32.md#associatedconstant.NAN [`f64::from_str`]: ../../core/primitive.f64.md#method.from_str -[`f64::INFINITY`]: ../../core/primitive.f64.md#associatedconstant.INFINITY -[`f64::NAN`]: ../../core/primitive.f64.md#associatedconstant.NAN -[`u8::from_str_radix`]: ../../core/primitive.u8.md#method.from_str_radix -[`u32::from_str_radix`]: ../../core/primitive.u32.md#method.from_str_radix -[`u128::from_str_radix`]: ../../core/primitive.u128.md#method.from_str_radix [CHAR_LITERAL]: ../tokens.md#character-literals [STRING_LITERAL]: ../tokens.md#string-literals [RAW_STRING_LITERAL]: ../tokens.md#raw-string-literals diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 8a2f68cc3..7f21c497b 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -93,4 +93,4 @@ Just don't define inherent methods on trait objects with the same name as a trai [dereference]: operator-expr.md#the-dereference-operator [methods]: ../items/associated-items.md#methods [unsized coercion]: ../type-coercions.md#unsized-coercions -[`IntoIterator`]: ../../std/iter/trait.IntoIterator.html +[`IntoIterator`]: std::iter::IntoIterator diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index cd9e5e197..0601a8622 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -674,8 +674,8 @@ See [this test] for an example of using this dependency. [Function pointer]: ../types/function-pointer.md [Function item]: ../types/function-item.md [undefined behavior]: ../behavior-considered-undefined.md -[addr_of]: ../../std/ptr/macro.addr_of.html -[addr_of_mut]: ../../std/ptr/macro.addr_of_mut.html +[addr_of]: std::ptr::addr_of +[addr_of_mut]: std::ptr::addr_of_mut [_BorrowExpression_]: #borrow-operators [_DereferenceExpression_]: #the-dereference-operator diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 960fff11b..9dd02e2fc 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -6,8 +6,8 @@ r[asm.intro] Support for inline assembly is provided via the [`asm!`] and [`global_asm!`] macros. It can be used to embed handwritten assembly in the assembly output generated by the compiler. -[`asm!`]: ../core/arch/macro.asm.html -[`global_asm!`]: ../core/arch/macro.global_asm.html +[`asm!`]: core::arch::asm +[`global_asm!`]: core::arch::global_asm r[asm.stable-targets] Support for inline assembly is stable on the following architectures: @@ -119,7 +119,7 @@ These targets impose an additional restriction on the assembly code: any assembl Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. Further constraints on the directives used by inline assembly are indicated by [Directives Support](#directives-support). -[format-syntax]: ../std/fmt/index.html#syntax +[format-syntax]: std::fmt#syntax [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795 ## Operand type diff --git a/src/input-format.md b/src/input-format.md index 8d921bf8c..aad45ac9e 100644 --- a/src/input-format.md +++ b/src/input-format.md @@ -44,9 +44,6 @@ This prevents an [inner attribute] at the start of a source file being removed. The resulting sequence of characters is then converted into tokens as described in the remainder of this chapter. -[`include!`]: ../std/macro.include.md -[`include_bytes!`]: ../std/macro.include_bytes.md -[`include_str!`]: ../std/macro.include_str.md [inner attribute]: attributes.md [BYTE ORDER MARK]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 [comments]: comments.md diff --git a/src/interior-mutability.md b/src/interior-mutability.md index 914600776..dc79aac38 100644 --- a/src/interior-mutability.md +++ b/src/interior-mutability.md @@ -22,8 +22,3 @@ across threads. [shared reference]: types/pointer.md#shared-references- [ub]: behavior-considered-undefined.md -[`std::cell::UnsafeCell`]: ../std/cell/struct.UnsafeCell.html -[`std::cell::RefCell`]: ../std/cell/struct.RefCell.html -[`std::sync::atomic`]: ../std/sync/atomic/index.html - - diff --git a/src/introduction.md b/src/introduction.md index 9038efd8d..7f01096c6 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -131,7 +131,7 @@ We also want the reference to be as normative as possible, so if you see anythin [book]: ../book/index.html [github issues]: https://github.com/rust-lang/reference/issues -[standard library]: ../std/index.html +[standard library]: std [the Rust Reference repository]: https://github.com/rust-lang/reference/ [Unstable Book]: https://doc.rust-lang.org/nightly/unstable-book/ [_Expression_]: expressions.md diff --git a/src/items/enumerations.md b/src/items/enumerations.md index 5f008461a..63a3e76ba 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -197,7 +197,7 @@ enum OverflowingDiscriminantError2 { #### Via `mem::discriminant` -[`mem::discriminant`] returns an opaque reference to the discriminant of +[`std::mem::discriminant`] returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant. @@ -331,7 +331,6 @@ enum E { [_Visibility_]: ../visibility-and-privacy.md [_WhereClause_]: generics.md#where-clauses [`C` representation]: ../type-layout.md#the-c-representation -[`mem::discriminant`]: ../../std/mem/fn.discriminant.html [call expression]: ../expressions/call-expr.md [constant expression]: ../const_eval.md#constant-expressions [default representation]: ../type-layout.md#the-default-representation diff --git a/src/items/functions.md b/src/items/functions.md index 54988df31..2a12708ac 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -418,7 +418,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [`export_name`]: ../abi.md#the-export_name-attribute [`link_section`]: ../abi.md#the-link_section-attribute [`no_mangle`]: ../abi.md#the-no_mangle-attribute -[built-in attributes]: ../attributes.html#built-in-attributes-index +[built-in attributes]: ../attributes.md#built-in-attributes-index [trait item]: traits.md [method]: associated-items.md#methods [associated function]: associated-items.md#associated-functions-and-methods diff --git a/src/items/unions.md b/src/items/unions.md index ed3ba5ae9..d6a03ed39 100644 --- a/src/items/unions.md +++ b/src/items/unions.md @@ -175,10 +175,8 @@ checking, etc etc etc). [_GenericParams_]: generics.md [_WhereClause_]: generics.md#where-clauses [_StructFields_]: structs.md -[`transmute`]: ../../std/mem/fn.transmute.html -[`Copy`]: ../../std/marker/trait.Copy.html +[`transmute`]: std::mem::transmute [boolean type]: ../types/boolean.md -[ManuallyDrop]: ../../std/mem/struct.ManuallyDrop.html [the C representation]: ../type-layout.md#reprc-unions [type namespace]: ../names/namespaces.md -[undefined behavior]: ../behavior-considered-undefined.html +[undefined behavior]: ../behavior-considered-undefined.md diff --git a/src/names/preludes.md b/src/names/preludes.md index f557699e7..745b290df 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -52,7 +52,7 @@ added as long as the [`no_std` attribute] is not specified in the crate root. > the extern prelude, so it is considered unidiomatic to use `extern crate`. > **Note**: Additional crates that ship with `rustc`, such as [`alloc`], and -> [`test`], are not automatically included with the `--extern` flag when using +> [`test`](mod@test), are not automatically included with the `--extern` flag when using > Cargo. They must be brought into scope with an `extern crate` declaration, > even in the 2018 edition. > @@ -137,24 +137,11 @@ This attribute does not affect the [language prelude]. > from the standard library are still included in the `macro_use` prelude. > Starting in the 2018 edition, it will remove the `macro_use` prelude. -[`alloc`]: ../../alloc/index.html -[`Box`]: ../../std/boxed/struct.Box.html -[`core::prelude::v1`]: ../../core/prelude/v1/index.html -[`core::prelude::rust_2015`]: ../../core/prelude/rust_2015/index.html -[`core::prelude::rust_2018`]: ../../core/prelude/rust_2018/index.html -[`core::prelude::rust_2021`]: ../../core/prelude/rust_2021/index.html -[`core`]: ../../core/index.html [`extern crate`]: ../items/extern-crates.md [`macro_use` attribute]: ../macros-by-example.md#the-macro_use-attribute [`macro_use` prelude]: #macro_use-prelude [`no_std` attribute]: #the-no_std-attribute [`no_std` attribute]: #the-no_std-attribute -[`std::prelude::v1`]: ../../std/prelude/v1/index.html -[`std::prelude::rust_2015`]: ../../std/prelude/rust_2015/index.html -[`std::prelude::rust_2018`]: ../../std/prelude/rust_2018/index.html -[`std::prelude::rust_2021`]: ../../std/prelude/rust_2021/index.html -[`std`]: ../../std/index.html -[`test`]: ../../test/index.html [attribute]: ../attributes.md [Boolean type]: ../types/boolean.md [Built-in attributes]: ../attributes.md#built-in-attributes-index diff --git a/src/procedural-macros.md b/src/procedural-macros.md index c5af448b7..a97755f7f 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -338,16 +338,15 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros. [Cargo's build scripts]: ../cargo/reference/build-scripts.html [Derive macros]: #derive-macros [Function-like macros]: #function-like-procedural-macros -[`Delimiter::None`]: ../proc_macro/enum.Delimiter.html#variant.None -[`Group`]: ../proc_macro/struct.Group.html -[`TokenStream`]: ../proc_macro/struct.TokenStream.html -[`TokenStream`s]: ../proc_macro/struct.TokenStream.html -[`TokenTree`s]: ../proc_macro/enum.TokenTree.html -[`compile_error`]: ../std/macro.compile_error.html +[`Delimiter::None`]: proc_macro::Delimiter::None +[`Group`]: proc_macro::Group +[`TokenStream`]: proc_macro::TokenStream +[`TokenStream`s]: proc_macro::TokenStream +[`TokenTree`s]: proc_macro::TokenTree [`derive` attribute]: attributes/derive.md [`extern` blocks]: items/external-blocks.md [`macro_rules`]: macros-by-example.md -[`proc_macro` crate]: ../proc_macro/index.html +[`proc_macro` crate]: proc_macro [attribute]: attributes.md [attributes]: attributes.md [block]: expressions/block-expr.md diff --git a/src/runtime.md b/src/runtime.md index a281d50fb..a673834f8 100644 --- a/src/runtime.md +++ b/src/runtime.md @@ -75,11 +75,11 @@ display a console window on startup. It will run detached from any existing cons ``` [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax -[`GlobalAlloc`]: ../alloc/alloc/trait.GlobalAlloc.html -[`PanicInfo`]: ../core/panic/struct.PanicInfo.html +[`GlobalAlloc`]: alloc::alloc::GlobalAlloc +[`PanicInfo`]: core::panic::PanicInfo [abort]: ../book/ch09-01-unrecoverable-errors-with-panic.html [attribute]: attributes.md [crate types]: linkage.md -[set_hook]: ../std/panic/fn.set_hook.html +[set_hook]: std::panic::set_hook [static item]: items/static-items.md [subsystem]: https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 21cab3dc8..f7e98323d 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -140,26 +140,15 @@ The [`Sized`] trait indicates that the size of this type is known at compile-tim `Sized` is always implemented automatically by the compiler, not by [implementation items]. These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound. -[`Arc`]: ../std/sync/struct.Arc.html -[`Box`]: ../std/boxed/struct.Box.html -[`Clone`]: ../std/clone/trait.Clone.html -[`Copy`]: ../std/marker/trait.Copy.html -[`Deref`]: ../std/ops/trait.Deref.html -[`DerefMut`]: ../std/ops/trait.DerefMut.html -[`Drop`]: ../std/ops/trait.Drop.html -[`Pin

    `]: ../std/pin/struct.Pin.html -[`Rc`]: ../std/rc/struct.Rc.html -[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html -[`Send`]: ../std/marker/trait.Send.html -[`Sized`]: ../std/marker/trait.Sized.html -[`std::cell::UnsafeCell`]: ../std/cell/struct.UnsafeCell.html -[`std::cmp`]: ../std/cmp/index.html -[`std::marker::PhantomData`]: ../std/marker/struct.PhantomData.html -[`std::ops`]: ../std/ops/index.html -[`Termination`]: ../std/process/trait.Termination.html -[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html -[`Sync`]: ../std/marker/trait.Sync.html -[`Unpin`]: ../std/marker/trait.Unpin.html +[`Arc`]: std::sync::Arc +[`Deref`]: std::ops::Deref +[`DerefMut`]: std::ops::DerefMut +[`Pin

    `]: std::pin::Pin +[`Rc`]: std::rc::Rc +[`RefUnwindSafe`]: std::panic::RefUnwindSafe +[`Termination`]: std::process::Termination +[`UnwindSafe`]: std::panic::UnwindSafe +[`Unpin`]: std::marker::Unpin [Arrays]: types/array.md [associated types]: items/associated-items.md#associated-types @@ -181,7 +170,7 @@ These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound [orphan rules]: items/implementations.md#trait-implementation-coherence [`static` items]: items/static-items.md [test functions]: attributes/testing.md#the-test-attribute -[the standard library]: ../std/index.html +[the standard library]: std [trait object]: types/trait-object.md [Tuples]: types/tuple.md [Type parameters]: types/parameters.md diff --git a/src/tokens.md b/src/tokens.md index 1c50ed11f..aeafe4b6d 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -336,7 +336,7 @@ followed by the character `U+0022`. If the character `U+0022` is present within the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character. Alternatively, a C string literal can be a _raw C string literal_, defined below. -[CStr]: ../core/ffi/struct.CStr.html +[CStr]: core::ffi::CStr C strings are implicitly terminated by byte `0x00`, so the C string literal `c""` is equivalent to manually constructing a `&CStr` from the byte string diff --git a/src/type-coercions.md b/src/type-coercions.md index f1016b19b..7d254f4e7 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -271,6 +271,6 @@ precisely. [subtype]: subtyping.md [object safe]: items/traits.md#object-safety [type cast operator]: expressions/operator-expr.md#type-cast-expressions -[`Unsize`]: ../std/marker/trait.Unsize.html -[`CoerceUnsized`]: ../std/ops/trait.CoerceUnsized.html +[`Unsize`]: std::marker::Unsize +[`CoerceUnsized`]: std::ops::CoerceUnsized [method-call expressions]: expressions/method-call-expr.md diff --git a/src/type-layout.md b/src/type-layout.md index c53e9d097..8b1a689d8 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -600,12 +600,12 @@ primitive field will have the ABI of the primitive field. Because this representation delegates type layout to another type, it cannot be used with any other representation. -[`align_of_val`]: ../std/mem/fn.align_of_val.html -[`size_of_val`]: ../std/mem/fn.size_of_val.html -[`align_of`]: ../std/mem/fn.align_of.html -[`size_of`]: ../std/mem/fn.size_of.html -[`Sized`]: ../std/marker/trait.Sized.html -[`Copy`]: ../std/marker/trait.Copy.html +[`align_of_val`]: std::mem::align_of_val +[`size_of_val`]: std::mem::size_of_val +[`align_of`]: std::mem::align_of +[`size_of`]: std::mem::size_of +[`Sized`]: std::marker::Sized +[`Copy`]: std::marker::Copy [dynamically sized types]: dynamically-sized-types.md [field-less enums]: items/enumerations.md#field-less-enum [enumerations]: items/enumerations.md @@ -618,4 +618,4 @@ used with any other representation. [primitive representations]: #primitive-representations [structs]: items/structs.md [`transparent`]: #the-transparent-representation -[`Layout`]: ../std/alloc/struct.Layout.html +[`Layout`]: std::alloc::Layout diff --git a/src/types/array.md b/src/types/array.md index 88ea8634c..167954bfe 100644 --- a/src/types/array.md +++ b/src/types/array.md @@ -26,6 +26,5 @@ always bounds-checked in safe methods and operators. [_Expression_]: ../expressions.md [_Type_]: ../types.md#type-expressions -[`Vec`]: ../../std/vec/struct.Vec.html [`usize`]: numeric.md#machine-dependent-integer-types [constant expression]: ../const_eval.md#constant-expressions diff --git a/src/types/boolean.md b/src/types/boolean.md index 7ea99d185..a0c07101f 100644 --- a/src/types/boolean.md +++ b/src/types/boolean.md @@ -30,7 +30,7 @@ Like all primitives, the boolean type [implements][p-impl] the [traits][p-traits] [`Clone`][p-clone], [`Copy`][p-copy], [`Sized`][p-sized], [`Send`][p-send], and [`Sync`][p-sync]. -> **Note**: See the [standard library docs][std] for library operations. +> **Note**: See the [standard library docs](bool) for library operations. ## Operations on boolean values @@ -119,6 +119,5 @@ are invalid `bool`s, the inverse is not always sound). [p-sync]: ../special-types-and-traits.md#sync [p-traits]: ../items/traits.md [size and alignment]: ../type-layout.md#size-and-alignment -[std]: ../../std/primitive.bool.html [undefined behavior]: ../behavior-considered-undefined.md [while expressions]: ../expressions/loop-expr.md#predicate-loops diff --git a/src/types/closure.md b/src/types/closure.md index eecdb038f..f93537819 100644 --- a/src/types/closure.md +++ b/src/types/closure.md @@ -170,9 +170,6 @@ Because captures are often by reference, the following general rules arise: [`Clone`]: ../special-types-and-traits.md#clone [`Copy`]: ../special-types-and-traits.md#copy -[`FnMut`]: ../../std/ops/trait.FnMut.html -[`FnOnce`]: ../../std/ops/trait.FnOnce.html -[`Fn`]: ../../std/ops/trait.Fn.html [`Send`]: ../special-types-and-traits.md#send [`Sized`]: ../special-types-and-traits.md#sized [`Sync`]: ../special-types-and-traits.md#sync diff --git a/src/types/function-item.md b/src/types/function-item.md index c8088e48c..3221f3e2b 100644 --- a/src/types/function-item.md +++ b/src/types/function-item.md @@ -48,9 +48,6 @@ All function items implement [`Fn`], [`FnMut`], [`FnOnce`], [`Copy`], [`Clone`]: ../special-types-and-traits.md#clone [`Copy`]: ../special-types-and-traits.md#copy -[`FnMut`]: ../../std/ops/trait.FnMut.html -[`FnOnce`]: ../../std/ops/trait.FnOnce.html -[`Fn`]: ../../std/ops/trait.Fn.html [`Send`]: ../special-types-and-traits.md#send [`Sync`]: ../special-types-and-traits.md#sync [coercion]: ../type-coercions.md diff --git a/src/types/pointer.md b/src/types/pointer.md index cbbf356e8..a1ec509c3 100644 --- a/src/types/pointer.md +++ b/src/types/pointer.md @@ -60,8 +60,6 @@ For thin raw pointers (i.e., for `P = *const T` or `P = *mut T` for `T: Sized`), the inverse direction (transmuting from an integer or array of integers to `P`) is always valid. However, the pointer produced via such a transmutation may not be dereferenced (not even if `T` has size zero). -[`core::ptr::addr_of!`]: ../../core/ptr/macro.addr_of.html -[`core::ptr::addr_of_mut!`]: ../../core/ptr/macro.addr_of_mut.html [Interior mutability]: ../interior-mutability.md [_Lifetime_]: ../trait-bounds.md [_TypeNoBounds_]: ../types.md#type-expressions diff --git a/src/types/union.md b/src/types/union.md index 326e720c6..7a2f037e8 100644 --- a/src/types/union.md +++ b/src/types/union.md @@ -15,5 +15,4 @@ The memory layout of a `union` is undefined by default (in particular, fields do fix a layout. [`Copy`]: ../special-types-and-traits.md#copy -[`ManuallyDrop`]: ../../std/mem/struct.ManuallyDrop.html [item]: ../items/unions.md diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index df68a74cc..175a5e83d 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -54,7 +54,7 @@ By writing `unsafe impl`, the programmer states that they have taken care of sat Unsafe trait implementations are the logical dual to unsafe traits: where unsafe traits define a proof obligation that implementations must uphold, unsafe implementations state that all relevant proof obligations have been discharged. [keyword]: ../std/keyword.unsafe.html -[`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked +[`get_unchecked`]: slice::get_unchecked [`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn ## Unsafe external blocks (`unsafe extern`) From 1a52c1f70b8f49bc59abe75c103eb7a5159fb34a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Aug 2024 11:56:26 -0700 Subject: [PATCH 4/7] Note some limitations of automatic std links --- docs/authoring.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/authoring.md b/docs/authoring.md index 256cb3082..a01c8a54d 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -109,6 +109,15 @@ Explicit namespace disambiguation is also supported: [`std::vec`](mod@std::vec) ``` +Beware there are some limitations, for example: + +- Links to rexports from `std_arch` don't work due to . +- Links to keywords aren't supported. +- Links to trait impls where the trait is not in the prelude doesn't work. Traits must be in scope, and there currently isn't a way to add those. +- If there are multiple generic implementations, it will link to one randomly (see ). + +When running into a rustdoc limitation, consider manually linking to the correct page using a relative link. For example, `../std/arch/macro.is_x86_feature_detected.html`. + [intra]: https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html ### Admonitions From 4711485e55bd818c77a6e63015c7d30643c26c35 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Aug 2024 11:56:54 -0700 Subject: [PATCH 5/7] Document the SPEC_RELATIVE option --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 009a3d80d..a296a3b38 100644 --- a/README.md +++ b/README.md @@ -61,13 +61,15 @@ To build the Reference locally (in `build/`) and open it in a web browser, run: ```sh -mdbook build --open +SPEC_RELATIVE=0 mdbook build --open ``` This will open a browser with a websocket live-link to automatically reload whenever the source is updated. -You can also open any current build of the reference by running: +The `SPEC_RELATIVE=0` environment variable makes links to the standard library go to instead of being relative, which is useful when viewing locally since you normally don't have a copy of the standard library. + +You can also use mdbook's live webserver option, which will automatically rebuild the book and reload your web browser whenever a source file is modified: ```sh -mdbook serve --open +SPEC_RELATIVE=0 mdbook serve --open ``` From b95d3795b7048e82e8ed759b0bb17a38490a5795 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 20 Aug 2024 05:09:24 +0000 Subject: [PATCH 6/7] Optimize a bit It's better to allocate for the smaller prefix that we're extracting than to allocate repeatedly for the tail items, especially as `split_off` doesn't shrink the capacity of what we go on to insert. --- mdbook-spec/src/std_links.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 789518c4e..8f9da6bee 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -55,6 +55,7 @@ pub fn std_links(book: &mut Book) { .captures_iter(&generated) .map(|cap| cap.get(1).unwrap().as_str()) .collect(); + let mut urls = &mut urls[..]; let expected_len: usize = chapter_links.values().map(|l| l.len()).sum(); if urls.len() != expected_len { eprintln!( @@ -67,9 +68,9 @@ pub fn std_links(book: &mut Book) { // Unflatten the urls list so that it is split back by chapter. let mut ch_urls: HashMap<&PathBuf, Vec<_>> = HashMap::new(); for (ch_path, links) in &chapter_links { - let rest = urls.split_off(links.len()); - ch_urls.insert(ch_path, urls); - urls = rest; + let xs; + (xs, urls) = urls.split_at_mut(links.len()); + ch_urls.insert(ch_path, xs.into()); } // Do this in two passes to deal with lifetimes. From b30807032c7e65de6d4e95a73c6081223867983f Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 20 Aug 2024 05:14:09 +0000 Subject: [PATCH 7/7] Make some idiomatic tweaks --- mdbook-spec/src/std_links.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 8f9da6bee..d0b017999 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -86,7 +86,7 @@ pub fn std_links(book: &mut Book) { // Create a list of replacements to make in the raw markdown to point to the new url. let replacements = compute_replacements(&ch.content, &chapter_links[key], &ch_urls[key]); - let mut new_contents = ch.content.to_string(); + let mut new_contents = ch.content.clone(); for (md_link, url, range) in replacements { // Convert links to be relative so that links work offline and // with the linkchecker. @@ -130,7 +130,7 @@ struct Link<'a> { } /// Collects all markdown links that look like they might be standard library links. -fn collect_markdown_links<'a>(chapter: &'a Chapter) -> Vec> { +fn collect_markdown_links(chapter: &Chapter) -> Vec> { let mut opts = Options::empty(); opts.insert(Options::ENABLE_TABLES); opts.insert(Options::ENABLE_FOOTNOTES); @@ -294,7 +294,7 @@ fn compute_replacements<'a>( ) -> Vec<(&'a str, &'a str, Range)> { let mut replacements = Vec::new(); - for (url, link) in urls.into_iter().zip(links) { + for (url, link) in urls.iter().zip(links) { let Some(cap) = ANCHOR_URL.captures(url) else { eprintln!("error: could not find anchor in:\n{url}\nlink={link:#?}"); process::exit(1);