diff options
Diffstat (limited to 'src/doc/rustc-dev-guide')
38 files changed, 748 insertions, 402 deletions
diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml index 51dc8ecb0..c86ec5638 100644 --- a/src/doc/rustc-dev-guide/book.toml +++ b/src/doc/rustc-dev-guide/book.toml @@ -15,7 +15,7 @@ command = "mdbook-mermaid" [output.html] git-repository-url = "https://github.com/rust-lang/rustc-dev-guide" -edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/tree/master/{path}?mode=edit" +edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/edit/master/{path}" additional-js = ["mermaid.min.js", "mermaid-init.js"] [output.html.fold] diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index bbea2bf38..70fce8b1c 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -3,9 +3,11 @@ use std::{ convert::TryInto as _, env, fmt, fs, path::{Path, PathBuf}, + process, + str::FromStr, }; -use chrono::{Datelike as _, TimeZone as _, Utc}; +use chrono::{Datelike as _, Month, TimeZone as _, Utc}; use glob::glob; use regex::Regex; @@ -38,12 +40,18 @@ impl fmt::Display for Date { fn make_date_regex() -> Regex { Regex::new( r"(?x) # insignificant whitespace mode - <!--\s* - [dD]ate:\s* - (?P<y>\d{4}) # year - - - (?P<m>\d{2}) # month - \s*-->", + (<!--\s* + date-check:\s* + (?P<m1>[[:alpha:]]+)\s+ + (?P<y1>\d{4})\s*--> + ) + | + (<!--\s* + date-check\s*-->\s+ + (?P<m2>[[:alpha:]]+)\s+ + (?P<y2>\d{4})\b + ) + ", ) .unwrap() } @@ -52,15 +60,22 @@ fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)> let mut line = 1; let mut end_of_last_cap = 0; date_regex - .captures_iter(&text) - .map(|cap| { - ( - cap.get(0).unwrap().range(), - Date { - year: cap["y"].parse().unwrap(), - month: cap["m"].parse().unwrap(), - }, - ) + .captures_iter(text) + .filter_map(|cap| { + if let (Some(month), Some(year), None, None) | (None, None, Some(month), Some(year)) = ( + cap.name("m1"), + cap.name("y1"), + cap.name("m2"), + cap.name("y2"), + ) { + let year = year.as_str().parse().expect("year"); + let month = Month::from_str(month.as_str()) + .expect("month") + .number_from_month(); + Some((cap.get(0).expect("all").range(), Date { year, month })) + } else { + None + } }) .map(|(byte_range, date)| { line += text[end_of_last_cap..byte_range.end] @@ -110,9 +125,12 @@ fn filter_dates( } fn main() { - let root_dir = env::args() - .nth(1) - .expect("expect root Markdown directory as CLI argument"); + let mut args = env::args(); + if args.len() == 1 { + eprintln!("error: expected root Markdown directory as CLI argument"); + process::exit(1); + } + let root_dir = args.nth(1).unwrap(); let root_dir_path = Path::new(&root_dir); let glob_pat = format!("{}/**/*.md", root_dir); let today_chrono = Utc::today(); @@ -136,7 +154,7 @@ fn main() { up-to-date. Each date should be updated (in the Markdown file where it appears) to \ use the current month ({current_month}), or removed if the docs it annotates are not \ expected to fall out of date quickly.", - current_month = current_month + current_month = today_chrono.format("%B %Y"), ); println!(); println!( @@ -153,7 +171,7 @@ fn main() { for (path, dates) in dates_by_file { println!( "- [ ] {}", - path.strip_prefix(&root_dir_path).unwrap().display() + path.strip_prefix(&root_dir_path).unwrap_or(&path).display(), ); for (line, date) in dates { println!(" - [ ] line {}: {}", line, date); @@ -182,61 +200,153 @@ mod tests { #[test] fn test_date_regex() { - let regex = make_date_regex(); - assert!(regex.is_match("foo <!-- date: 2021-01 --> bar")); + let regex = &make_date_regex(); + assert!(regex.is_match("<!-- date-check: jan 2021 -->")); + assert!(regex.is_match("<!-- date-check: january 2021 -->")); + assert!(regex.is_match("<!-- date-check: Jan 2021 -->")); + assert!(regex.is_match("<!-- date-check: January 2021 -->")); + assert!(regex.is_match("<!-- date-check --> jan 2021")); + assert!(regex.is_match("<!-- date-check --> january 2021")); + assert!(regex.is_match("<!-- date-check --> Jan 2021")); + assert!(regex.is_match("<!-- date-check --> January 2021")); + + assert!(regex.is_match("<!-- date-check --> jan 2021 ")); + assert!(regex.is_match("<!-- date-check --> jan 2021.")); } #[test] - fn test_date_regex_capitalized() { - let regex = make_date_regex(); - assert!(regex.is_match("foo <!-- Date: 2021-08 --> bar")); + fn test_date_regex_fail() { + let regexes = &make_date_regex(); + assert!(!regexes.is_match("<!-- date-check: jan 221 -->")); + assert!(!regexes.is_match("<!-- date-check: jan 20221 -->")); + assert!(!regexes.is_match("<!-- date-check: 01 2021 -->")); + assert!(!regexes.is_match("<!-- date-check --> jan 221")); + assert!(!regexes.is_match("<!-- date-check --> jan 20222")); + assert!(!regexes.is_match("<!-- date-check --> 01 2021")); } #[test] fn test_collect_dates_from_file() { - let text = "Test1\n<!-- date: 2021-01 -->\nTest2\nFoo<!-- date: 2021-02 \ - -->\nTest3\nTest4\nFoo<!-- date: 2021-03 -->Bar\n<!-- date: 2021-04 \ - -->\nTest5\nTest6\nTest7\n<!-- date: \n\n2021-05 -->\nTest8 + let text = r" +Test1 +<!-- date-check: jan 2021 --> +Test2 +Foo<!-- date-check: february 2021 +--> +Test3 +Test4 +Foo<!-- date-check: Mar 2021 -->Bar +<!-- date-check:April 2021 +--> +Test5 +Test6 +Test7 +<!-- date-check: + +may 2021 --> +Test8 +Test1 +<!-- date-check --> jan 2021 +Test2 +Foo<!-- date-check +--> february 2021 +Test3 +Test4 +Foo<!-- date-check --> mar 2021 Bar +<!-- date-check +--> apr 2021 +Test5 +Test6 +Test7 +<!-- date-check + + --> may 2021 +Test8 + <!-- + date-check + --> june 2021. "; assert_eq!( collect_dates_from_file(&make_date_regex(), text), vec![ ( - 2, + 3, + Date { + year: 2021, + month: 1, + } + ), + ( + 6, + Date { + year: 2021, + month: 2, + } + ), + ( + 9, + Date { + year: 2021, + month: 3, + } + ), + ( + 11, + Date { + year: 2021, + month: 4, + } + ), + ( + 17, + Date { + year: 2021, + month: 5, + } + ), + ( + 20, Date { year: 2021, month: 1, } ), ( - 4, + 23, Date { year: 2021, month: 2, } ), ( - 7, + 26, Date { year: 2021, month: 3, } ), ( - 8, + 28, Date { year: 2021, month: 4, } ), ( - 14, + 34, Date { year: 2021, month: 5, } ), - ] + ( + 38, + Date { + year: 2021, + month: 6, + } + ), + ], ); } } diff --git a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md index 271e6a16f..ea50cd754 100644 --- a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md +++ b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md @@ -2,15 +2,12 @@ <!-- toc --> -As of <!-- date: 2021-10 --> October 2021, `rustc_codegen_ssa` provides an +As of <!-- date-check --> Aug 2022, `rustc_codegen_ssa` provides an abstract interface for all backends to implement, to allow other codegen backends (e.g. [Cranelift]). [Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/HEAD/cranelift -> The following is a copy/paste of a README from the rust-lang/rust repo. -> Please submit a PR if it needs updating. - # Refactoring of `rustc_codegen_llvm` by Denis Merigoux, October 23rd 2018 diff --git a/src/doc/rustc-dev-guide/src/backend/codegen.md b/src/doc/rustc-dev-guide/src/backend/codegen.md index 1a6c2fa76..5feea5202 100644 --- a/src/doc/rustc-dev-guide/src/backend/codegen.md +++ b/src/doc/rustc-dev-guide/src/backend/codegen.md @@ -1,13 +1,16 @@ # Code generation -Code generation or "codegen" is the part of the compiler that actually -generates an executable binary. Usually, rustc uses LLVM for code generation; -there is also support for [Cranelift]. The key is that rustc doesn't implement -codegen itself. It's worth noting, though, that in the Rust source code, many -parts of the backend have `codegen` in their names (there are no hard -boundaries). - -[Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/HEAD/cranelift +Code generation (or "codegen") is the part of the compiler +that actually generates an executable binary. +Usually, rustc uses LLVM for code generation, +bu there is also support for [Cranelift] and [GCC]. +The key is that rustc doesn't implement codegen itself. +It's worth noting, though, that in the Rust source code, +many parts of the backend have `codegen` in their names +(there are no hard boundaries). + +[Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/main/cranelift +[GCC]: https://github.com/rust-lang/rustc_codegen_gcc > NOTE: If you are looking for hints on how to debug code generation bugs, > please see [this section of the debugging chapter][debugging]. diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 0de0767b6..81ebbbb40 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -43,7 +43,7 @@ the branch we're already using. The steps for this are: 1. Make sure the bugfix is in upstream LLVM. 2. Identify the branch that rustc is currently using. The `src/llvm-project` submodule is always pinned to a branch of the - [rust-lang/llvm-project](https://github.com/rust-lang/llvm-project) repository. + [rust-lang/llvm-project repository]. 3. Fork the rust-lang/llvm-project repository 4. Check out the appropriate branch (typically named `rustc/a.b-yyyy-mm-dd`) 5. Cherry-pick the upstream commit onto the branch @@ -66,8 +66,8 @@ Example PRs look like: ## Feature updates -> Note that this information is as of the time of this writing <!-- date: -2021-10 --> (October 2021). The process for updating LLVM changes with +> Note that this information is as of the time of this writing, <!-- +date-check --> October 2021. The process for updating LLVM changes with practically all LLVM updates, so this may be out of date! Unlike bugfixes, updating to pick up a new feature of LLVM typically requires a @@ -146,9 +146,6 @@ easiest to land [`llvm-wrapper`] compatibility as a PR before actually updating interested in trying out the new LLVM can benefit from work you've done to update the C++ bindings. -[rust-lang/llvm-project repository]: https://github.com/rust-lang/llvm-project -[`llvm-wrapper`]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_llvm/llvm-wrapper - ### Caveats and gotchas Ideally the above instructions are pretty smooth, but here's some caveats to @@ -161,8 +158,6 @@ keep in mind while going through them: * Creating branches is a privileged operation on GitHub, so you'll need someone with write access to create the branches for you most likely. -[wg-llvm]: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm - ## New LLVM Release Updates Updating to a new release of LLVM is very similar to the "feature updates" @@ -172,7 +167,7 @@ section above is generally around branch naming. The sequence of events typically looks like: 1. LLVM announces that its latest release version has branched. This will show - up as a branch in https://github.com/llvm/llvm-project typically named + up as a branch in the [llvm/llvm-project repository] typically named `release/$N.x` where `$N` is the version of LLVM that's being released. 2. We then follow the "feature updates" section above to create a new branch of @@ -192,3 +187,8 @@ typically looks like: to create a new branch in the rust-lang/llvm-project repository, this time with a new date. The commit history should look much cleaner as just a few Rust-specific commits stacked on top of stock LLVM's release branch. + +[rust-lang/llvm-project repository]: https://github.com/rust-lang/llvm-project +[llvm/llvm-project repository]: https://github.com/llvm/llvm-project +[`llvm-wrapper`]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_llvm/llvm-wrapper +[wg-llvm]: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md index c7c107e1e..e236e0124 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md @@ -94,7 +94,7 @@ member constraints come in. ## Choices are always lifetime parameters At present, the "choice" regions from a member constraint are always lifetime -parameters from the current function. As of <!-- date: 2021-10 --> October 2021, +parameters from the current function. As of <!-- date-check --> October 2021, this falls out from the placement of impl Trait, though in the future it may not be the case. We take some advantage of this fact, as it simplifies the current code. In particular, we don't have to consider a case like `'0 member of ['1, diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping.md b/src/doc/rustc-dev-guide/src/building/bootstrapping.md index fd54de20c..939c47f1b 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping.md @@ -18,7 +18,34 @@ rustc, then uses it to compile the new compiler. ## Stages of bootstrapping -Compiling `rustc` is done in stages. +Compiling `rustc` is done in stages. Here's a diagram, adapted from Joshua Nelson's +[talk on bootstrapping][rustconf22-talk] at RustConf 2022, with detailed explanations below. + +The `A`, `B`, `C`, and `D` show the ordering of the stages of bootstrapping. +<span style="background-color: lightblue; color: black">Blue</span> nodes are downloaded, +<span style="background-color: yellow; color: black">yellow</span> nodes are built with the +stage0 compiler, and +<span style="background-color: lightgreen; color: black">green</span> nodes are built with the +stage1 compiler. + +[rustconf22-talk]: https://rustconf.com/schedule#bootstrapping-the-once-and-future-compiler + +```mermaid +graph TD + s0c["stage0 compiler (1.63)"]:::downloaded -->|A| s0l("stage0 std (1.64)"):::with-s0c; + s0c & s0l --- stepb[ ]:::empty; + stepb -->|B| s0ca["stage0 compiler artifacts (1.64)"]:::with-s0c; + s0ca -->|copy| s1c["stage1 compiler (1.64)"]:::with-s0c; + s1c -->|C| s1l("stage1 std (1.64)"):::with-s1c; + s1c & s1l --- stepd[ ]:::empty; + stepd -->|D| s1ca["stage1 compiler artifacts (1.64)"]:::with-s1c; + s1ca -->|copy| s2c["stage2 compiler"]:::with-s1c; + + classDef empty width:0px,height:0px; + classDef downloaded fill: lightblue; + classDef with-s0c fill: yellow; + classDef with-s1c fill: lightgreen; +``` ### Stage 0 diff --git a/src/doc/rustc-dev-guide/src/building/prerequisites.md b/src/doc/rustc-dev-guide/src/building/prerequisites.md index a5ab23d91..0783e82ee 100644 --- a/src/doc/rustc-dev-guide/src/building/prerequisites.md +++ b/src/doc/rustc-dev-guide/src/building/prerequisites.md @@ -12,7 +12,8 @@ Before building the compiler, you need the following things installed: If building LLVM from source (the default), you'll need additional tools: -* `g++` 5.1 or later, `clang++` 3.5 or later, or MSVC 2017 or later. +* `g++`, `clang++`, or MSVC with versions listed on <!-- date-check: Aug 2022 --> + [LLVM's documentation](https://releases.llvm.org/13.0.0/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library) * `ninja`, or GNU `make` 3.81 or later (ninja is recommended, especially on Windows) * `cmake` 3.13.4 or later diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 1c2229335..3e077977d 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -22,7 +22,7 @@ You can also install the hook as a step of running `./x.py setup`! a file. By default, `rust-analyzer` runs the `cargo check` and `rustfmt` commands, but you can override these commands to use more adapted versions of these tools when hacking on `rustc`. For example, for Visual Studio Code, -you can write: <!-- date: 2022-04 --><!-- the date comment is for the edition below --> +you can write: <!-- date-check: apr 2022 --><!-- the date comment is for the edition below --> ```JSON { diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 8f46e896e..35458b55c 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -16,9 +16,36 @@ set `debug = true` in your config.toml. Setting `debug = true` turns on many different debug options (e.g., `debug-assertions`, `debug-logging`, etc.) which can be individually tweaked if you want to, but many people -simply set `debug = true`. Check out the comments in config.toml.example for more info. +simply set `debug = true`. -You will need to rebuild the compiler once you've changed any configuration options. +If you want to use GDB to debug rustc, please set `config.toml` with options: + +```toml +[rust] +debug = true +debuginfo-level = 2 +``` + +> NOTE: +> This will use a lot of disk space +> (upwards of <!-- date-check Aug 2022 --> 35GB), +> and will take a lot more compile time. +> With `debuginfo-level = 1` (the default when `debug = true`), +> you will be able to track the execution path, +> but will lose the symbol information for debugging. + +The default configuration will enable `symbol-mangling-version` v0. +This requires at least GDB v10.2, +otherwise you need to disable new symbol-mangling-version in `config.toml`. + +```toml +[rust] +new-symbol-mangling = false +``` + +> See the comments in `config.toml.example` for more info. + +You will need to rebuild the compiler after changing any configuration option. ## `-Z` flags diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 45f8c9033..e59bb0a77 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -437,17 +437,35 @@ Just a few things to keep in mind: the project. - The date the comment was added, e.g. instead of writing _"Currently, ..."_ - or _"As of now, ..."_, consider writing - _"As of January 2021, ..."_. - Try to format the date as `<MONTH> <YEAR>` to ease search. + or _"As of now, ..."_, + consider adding the date, in one of the following formats: + - Jan 2021 + - January 2021 + - jan 2021 + - january 2021 - - Additionally, include a machine-readable comment of the form `<!-- date: - 2022-04 -->` (if the current month is April 2022). We have an automated - tool that uses these (in `ci/date-check`). + There is a CI action (in `~/.github/workflows/date-check.yml`) + that generates a monthly issue with any of these that are over 6 months old. - So, for the month of April 2022, the comment would look like: `As of <!-- - date: 2022-04 --> April 2022`. Make sure to put the comment *between* `as of` - and `April 2022`; see [PR #1066][rdg#1066] for the rationale. + For the action to pick the date, + add a special annotation before specifying the date: + + ```md + <!-- date-check --> Jul 2022 + ``` + + Example: + + ```md + As of <!-- date-check --> Jul 2022, the foo did the bar. + ``` + + For cases where the date should not be part of the visible rendered output, + use the following instead: + + ```md + <!-- date-check: Jul 2022 --> + ``` - A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide further explanation for the change process or a way to verify that the information is not @@ -459,7 +477,6 @@ Just a few things to keep in mind: [rdg]: https://rustc-dev-guide.rust-lang.org/ [rdgrepo]: https://github.com/rust-lang/rustc-dev-guide -[rdg#1066]: https://github.com/rust-lang/rustc-dev-guide/pull/1066 ## Issue Triage diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 15d125377..0d5f17b99 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -14,14 +14,14 @@ special config, so this may result in different style from normal [`rustfmt`]. Therefore, formatting this repository using `cargo fmt` is not recommended. Instead, formatting should be done using `./x.py fmt`. It's a good habit to run -`./x.py fmt` before every commit, as this reduces conflicts later. +`./x.py fmt` before every commit, as this reduces conflicts later. Formatting is checked by the `tidy` script. It runs automatically when you do `./x.py test` and can be run in isolation with `./x.py fmt --check`. If you want to use format-on-save in your editor, the pinned version of `rustfmt` is built under `build/<target>/stage0/bin/rustfmt`. You'll have to -pass the <!-- date: 2022-04 --> `--edition=2021` argument yourself when calling +pass the <!-- date-check: April 2022 --> `--edition=2021` argument yourself when calling `rustfmt` directly. [fmt]: https://github.com/rust-dev-tools/fmt-rfcs diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md index 8c8fd0c38..f012c5bb5 100644 --- a/src/doc/rustc-dev-guide/src/crates-io.md +++ b/src/doc/rustc-dev-guide/src/crates-io.md @@ -1,20 +1,20 @@ # crates.io Dependencies The Rust compiler supports building with some dependencies from `crates.io`. -For example, `log` and `env_logger` come from `crates.io`. +Examples are `log` and `env_logger`. -In general, you should avoid adding dependencies to the compiler for several -reasons: +In general, +you should avoid adding dependencies to the compiler for several reasons: -- The dependency may not be high quality or well-maintained, whereas we want - the compiler to be high-quality. +- The dependency may not be of high quality or well-maintained. - The dependency may not be using a compatible license. - The dependency may have transitive dependencies that have one of the above problems. -As of <!-- date: 2022-02 --> February 2022, there is no official policy for vetting -new dependencies to the compiler. Generally, new dependencies are not added -to the compiler unless there is a good reason to do so. +As of <!-- date-check --> Aug 2022, +there is no official policy for vetting new dependencies to the compiler. +Decisions are made on a case-by-case basis, +during code review. ## Permitted dependencies diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md index b6b6e0fa9..dcaba533e 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-items.md @@ -1,4 +1,5 @@ # Diagnostic Items + While writing lints it's common to check for specific types, traits and functions. This raises the question on how to check for these. Types can be checked by their complete type path. However, this requires hard coding paths @@ -7,7 +8,8 @@ rustc has introduced diagnostic items that are used to identify types via [`Symbol`]s. ## Finding diagnostic items -Diagnostic items are added to items inside `rustc`/`std`/`core` with the + +Diagnostic items are added to items inside `rustc`/`std`/`core`/`alloc` with the `rustc_diagnostic_item` attribute. The item for a specific type can be found by opening the source code in the documentation and looking for this attribute. Note that it's often added with the `cfg_attr` attribute to avoid compilation @@ -19,12 +21,15 @@ errors during tests. A definition often looks like this: struct Penguin; ``` -Diagnostic items are usually only added to traits, types and standalone -functions. If the goal is to check for an associated type or method, please use -the diagnostic item of the item and reference [*How To Use Diagnostic -Items*](#how-to-use-diagnostic-items). +Diagnostic items are usually only added to traits, +types, +and standalone functions. +If the goal is to check for an associated type or method, +please use the diagnostic item of the item and reference +[*Using Diagnostic Items*](#using-diagnostic-items). ## Adding diagnostic items + A new diagnostic item can be added with these two steps: 1. Find the target item inside the Rust repo. Now add the diagnostic item as a @@ -43,45 +48,55 @@ A new diagnostic item can be added with these two steps: For the naming conventions of diagnostic items, please refer to [*Naming Conventions*](#naming-conventions). -2. As of <!-- date: 2022-02 --> February 2022, diagnostic items in code are - accessed via symbols in [`rustc_span::symbol::sym`]. To add your newly - created diagnostic item simply open the module file and add the name (In - this case `Cat`) at the correct point in the list. +2. <!-- date-check: Aug 2022 --> + Diagnostic items in code are accessed via symbols in + [`rustc_span::symbol::sym`]. + To add your newly-created diagnostic item, + simply open the module file, + and add the name (In this case `Cat`) at the correct point in the list. -Now you can create a pull request with your changes. :tada: (Note that when -using diagnostic items in other projects like Clippy, it might take some time -until the repos get synchronized.) +Now you can create a pull request with your changes. :tada: + +> NOTE: +> When using diagnostic items in other projects like Clippy, +> it might take some time until the repos get synchronized. ## Naming conventions -Diagnostic items don't have a set in stone naming convention yet. These are -some guidelines that should be used for the future, but might differ from -existing names: - -* Types, traits and enums are named using UpperCamelCase (Examples: `Iterator`, -* `HashMap`, ...) -* For type names that are used multiple times like `Writer` it's good to choose - a more precise name, maybe by adding the module to it. (Example: `IoWriter`) -* Associated items should not get their own diagnostic items, but instead be - accessed indirectly by the diagnostic item of the type they're originating - from. + +Diagnostic items don't have a naming convention yet. +Following are some guidelines that should be used in future, +but might differ from existing names: + +* Types, traits, and enums are named using UpperCamelCase + (Examples: `Iterator` and `HashMap`) +* For type names that are used multiple times, + like `Writer`, + it's good to choose a more precise name, + maybe by adding the module to it + (Example: `IoWriter`) +* Associated items should not get their own diagnostic items, + but instead be accessed indirectly by the diagnostic item + of the type they're originating from. * Freestanding functions like `std::mem::swap()` should be named using - `snake_case` with one important (export) module as a prefix (Example: - `mem_swap`, `cmp_max`) + `snake_case` with one important (export) module as a prefix + (Examples: `mem_swap` and `cmp_max`) * Modules should usually not have a diagnostic item attached to them. - Diagnostic items were added to avoid the usage of paths, using them on - modules would therefore most likely to be counterproductive. + Diagnostic items were added to avoid the usage of paths, + and using them on modules would therefore most likely be counterproductive. ## Using diagnostic items + In rustc, diagnostic items are looked up via [`Symbol`]s from inside the [`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s using [`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`] using [`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to a [`DefId`], the method will return a `Option<DefId>`. This can be `None` if either the symbol isn't a diagnostic item or the type is not registered, for -instance when compiling with `#[no_std]`. All following examples are based on -[`DefId`]s and their usage. +instance when compiling with `#[no_std]`. +All the following examples are based on [`DefId`]s and their usage. ### Example: Checking for a type + ```rust use rustc_span::symbol::sym; @@ -96,6 +111,7 @@ fn example_1(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { ``` ### Example: Checking for a trait implementation + ```rust /// This example checks if a given [`DefId`] from a method is part of a trait /// implementation defined by a diagnostic item. @@ -112,6 +128,7 @@ fn is_diag_trait_item( ``` ### Associated Types + Associated types of diagnostic items can be accessed indirectly by first getting the [`DefId`] of the trait and then calling [`TyCtxt::associated_items()`]. This returns an [`AssocItems`] object which can @@ -119,13 +136,15 @@ be used for further checks. Checkout [`clippy_utils::ty::get_iterator_item_ty()`] for an example usage of this. ### Usage in Clippy + Clippy tries to use diagnostic items where possible and has developed some wrapper and utility functions. Please also refer to its documentation when using diagnostic items in Clippy. (See [*Common tools for writing lints*][clippy-Common-tools-for-writing-lints].) ## Related issues -This lists some related issues. These are probably only interesting to people + +These are probably only interesting to people who really want to take a deep dive into the topic :) * [rust#60966]: The Rust PR that introduced diagnostic items diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index f28350e03..f456474c7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -17,45 +17,43 @@ shown below: ```rust,ignore #[derive(SessionDiagnostic)] -#[error(typeck::field_already_declared, code = "E0124")] +#[diag(typeck::field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] #[label] pub span: Span, - #[label = "previous-decl-label"] + #[label(typeck::previous_decl_label)] pub prev_span: Span, } ``` `SessionDiagnostic` can only be applied to structs. Every `SessionDiagnostic` -has to have one attribute applied to the struct itself: either `#[error(..)]` -for defining errors, or `#[warning(..)]` for defining warnings. +has to have one attribute, `#[diag(...)]`, applied to the struct itself. If an error has an error code (e.g. "E0624"), then that can be specified using the `code` sub-attribute. Specifying a `code` isn't mandatory, but if you are porting a diagnostic that uses `DiagnosticBuilder` to use `SessionDiagnostic` then you should keep the code if there was one. -Both `#[error(..)]` and `#[warning(..)]` must provide a slug as the first -positional argument (a path to an item in `rustc_errors::fluent::*`). A slug -uniquely identifies the diagnostic and is also how the compiler knows what -error message to emit (in the default locale of the compiler, or in the locale -requested by the user). See [translation documentation](./translation.md) to -learn more about how translatable error messages are written and how slug -items are generated. +`#[diag(..)]` must provide a slug as the first positional argument (a path to an +item in `rustc_errors::fluent::*`). A slug uniquely identifies the diagnostic +and is also how the compiler knows what error message to emit (in the default +locale of the compiler, or in the locale requested by the user). See +[translation documentation](./translation.md) to learn more about how +translatable error messages are written and how slug items are generated. In our example, the Fluent message for the "field already declared" diagnostic looks like this: ```fluent -typeck-field-already-declared = +typeck_field_already_declared = field `{$field_name}` is already declared .label = field already declared - .previous-decl-label = `{$field_name}` first declared here + .previous_decl_label = `{$field_name}` first declared here ``` -`typeck-field-already-declared` is the slug from our example and is followed +`typeck_field_already_declared` is the slug from our example and is followed by the diagnostic message. Every field of the `SessionDiagnostic` which does not have an annotation is @@ -75,10 +73,10 @@ type `Span`. Applying any of these attributes will create the corresponding subdiagnostic with that `Span`. These attributes will look for their diagnostic message in a Fluent attribute attached to the primary Fluent message. In our example, `#[label]` will look for -`typeck-field-already-declared.label` (which has the message "field already +`typeck_field_already_declared.label` (which has the message "field already declared"). If there is more than one subdiagnostic of the same type, then these attributes can also take a value that is the attribute name to look for -(e.g. `previous-decl-label` in our example). +(e.g. `previous_decl_label` in our example). Other types have special behavior when used in a `SessionDiagnostic` derive: @@ -95,38 +93,35 @@ represent optional `#[note]`/`#[help]` subdiagnostics. Suggestions can be emitted using one of four field attributes: -- `#[suggestion(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_hidden(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_short(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_verbose(message = "...", code = "...", applicability = "...")]` +- `#[suggestion(slug, code = "...", applicability = "...")]` +- `#[suggestion_hidden(slug, code = "...", applicability = "...")]` +- `#[suggestion_short(slug, code = "...", applicability = "...")]` +- `#[suggestion_verbose(slug, code = "...", applicability = "...")]` Suggestions must be applied on either a `Span` field or a `(Span, -MachineApplicability)` field. Similarly to other field attributes, `message` -specifies the Fluent attribute with the message and defaults to `.suggestion`. -`code` specifies the code that should be suggested as a replacement and is a -format string (e.g. `{field_name}` would be replaced by the value of the -`field_name` field of the struct), not a Fluent identifier. `applicability` can -be used to specify the applicability in the attribute, it cannot be used when -the field's type contains an `Applicability`. +MachineApplicability)` field. Similarly to other field attributes, the slug +specifies the Fluent attribute with the message and defaults to the equivalent +of `.suggestion`. `code` specifies the code that should be suggested as a +replacement and is a format string (e.g. `{field_name}` would be replaced by +the value of the `field_name` field of the struct), not a Fluent identifier. +`applicability` can be used to specify the applicability in the attribute, it +cannot be used when the field's type contains an `Applicability`. In the end, the `SessionDiagnostic` derive will generate an implementation of `SessionDiagnostic` that looks like the following: ```rust,ignore -impl SessionDiagnostic for FieldAlreadyDeclared { +impl SessionDiagnostic<'_> for FieldAlreadyDeclared { fn into_diagnostic(self, sess: &'_ rustc_session::Session) -> DiagnosticBuilder<'_> { - let mut diag = sess.struct_err_with_code( - rustc_errors::DiagnosticMessage::fluent("typeck-field-already-declared"), - rustc_errors::DiagnosticId::Error("E0124") - ); + let mut diag = sess.struct_err(rustc_errors::fluent::typeck::field_already_declared); diag.set_span(self.span); diag.span_label( self.span, - rustc_errors::DiagnosticMessage::fluent_attr("typeck-field-already-declared", "label") + rustc_errors::fluent::typeck::label ); diag.span_label( self.prev_span, - rustc_errors::DiagnosticMessage::fluent_attr("typeck-field-already-declared", "previous-decl-label") + rustc_errors::fluent::typeck::previous_decl_label ); diag } @@ -146,12 +141,13 @@ tcx.sess.emit_err(FieldAlreadyDeclared { ``` ### Reference -`#[derive(SessionDiagnostic)]` supports the following attributes: +`#[derive(SessionDiagnostic)]` and `#[derive(LintDiagnostic)]` support the +following attributes: -- `#[error(slug, code = "...")]` or `#[warning(slug, code = "...")]` +- `#[diag(slug, code = "...")]` - _Applied to struct._ - _Mandatory_ - - Defines the struct to be representing an error or a warning. + - Defines the text and error code to be associated with the diagnostic. - Slug (_Mandatory_) - Uniquely identifies the diagnostic and corresponds to its Fluent message, mandatory. @@ -164,34 +160,48 @@ tcx.sess.emit_err(FieldAlreadyDeclared { - See [translation documentation](./translation.md). - `code = "..."` (_Optional_) - Specifies the error code. -- `#[note]` or `#[note = "..."]` (_Optional_) +- `#[note]` or `#[note(slug)]` (_Optional_) - _Applied to struct or `Span`/`()` fields._ - Adds a note subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the note's message - - Defaults to `note`. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.note`. - If applied to a `Span` field, creates a spanned note. -- `#[help]` or `#[help = "..."]` (_Optional_) +- `#[help]` or `#[help(slug)]` (_Optional_) - _Applied to struct or `Span`/`()` fields._ - Adds a help subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the help's message. - - Defaults to `help`. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.help`. - If applied to a `Span` field, creates a spanned help. -- `#[label]` or `#[label = "..."]` (_Optional_) +- `#[label]` or `#[label(slug)]` (_Optional_) - _Applied to `Span` fields._ - Adds a label subdiagnostic. - - Value is the Fluent attribute (relative to the Fluent message specified by - `slug`) for the label's message. - - Defaults to `label`. -- `#[suggestion{,_hidden,_short,_verbose}(message = "...", code = "...", applicability = "...")]` + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.label`. +- `#[warn_]` or `#[warn_(slug)]` (_Optional_) + - _Applied to `Span` fields._ + - Adds a warning subdiagnostic. + - Value is a path to an item in `rustc_errors::fluent` for the note's + message. + - Defaults to equivalent of `.warn`. +- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` (_Optional_) - _Applied to `(Span, MachineApplicability)` or `Span` fields._ - Adds a suggestion subdiagnostic. - - `message = "..."` (_Mandatory_) - - Value is the Fluent attribute (relative to the Fluent message specified - by `slug`) for the suggestion's message. - - Defaults to `suggestion`. + - Slug (_Mandatory_) + - A path to an item in `rustc_errors::fluent`. Always in a module starting + with a Fluent resource name (which is typically the name of the crate + that the diagnostic is from), e.g. + `rustc_errors::fluent::typeck::field_already_declared` + (`rustc_errors::fluent` is implicit in the attribute, so just + `typeck::field_already_declared`). Fluent attributes for all messages + exist as top-level items in that module (so `typeck_message.attr` is just + `typeck::attr`). + - See [translation documentation](./translation.md). + - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or + - `.suggestion` in Fluent). - `code = "..."` (_Mandatory_) - Value is a format string indicating the code to be suggested as a replacement. @@ -203,7 +213,7 @@ tcx.sess.emit_err(FieldAlreadyDeclared { `#[derive(SessionSubdiagnostic)]`)._ - Adds the subdiagnostic represented by the subdiagnostic struct. - `#[primary_span]` (_Optional_) - - _Applied to `Span` fields._ + - _Applied to `Span` fields on `SessionSubdiagnostic`s. Not used for `LintDiagnostic`s._ - Indicates the primary span of the diagnostic. - `#[skip_arg]` (_Optional_) - _Applied to any field._ @@ -258,9 +268,9 @@ In our example, the Fluent message for the "expected return type" label looks like this: ```fluent -typeck-expected-default-return-type = expected `()` because of default return type +typeck_expected_default_return_type = expected `()` because of default return type -typeck-expected-return-type = expected `{$expected}` because of return type +typeck_expected_return_type = expected `{$expected}` because of return type ``` Using the `#[primary_span]` attribute on a field (with type `Span`) will denote @@ -276,16 +286,17 @@ Like `SessionDiagnostic`, `SessionSubdiagnostic` supports `Option<T>` and Suggestions can be emitted using one of four attributes on the type/variant: -- `#[suggestion(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_hidden(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_short(message = "...", code = "...", applicability = "...")]` -- `#[suggestion_verbose(message = "...", code = "...", applicability = "...")]` +- `#[suggestion(..., code = "...", applicability = "...")]` +- `#[suggestion_hidden(..., code = "...", applicability = "...")]` +- `#[suggestion_short(..., code = "...", applicability = "...")]` +- `#[suggestion_verbose(..., code = "...", applicability = "...")]` Suggestions require `#[primary_span]` be set on a field and can have the following sub-attributes: -- `message` specifies the Fluent attribute with the message and defaults to - `.suggestion`. +- The first positional argument specifies the path to a item in + `rustc_errors::fluent` corresponding to the Fluent attribute with the message + and defaults to the equivalent of `.suggestion`. - `code` specifies the code that should be suggested as a replacement and is a format string (e.g. `{field_name}` would be replaced by the value of the `field_name` field of the struct), not a Fluent identifier. @@ -304,11 +315,11 @@ impl<'tcx> AddToDiagnostic for ExpectedReturnTypeLabel<'tcx> { use rustc_errors::{Applicability, IntoDiagnosticArg}; match self { ExpectedReturnTypeLabel::Unit { span } => { - diag.span_label(span, DiagnosticMessage::fluent("typeck-expected-default-return-type")) + diag.span_label(span, rustc_errors::fluent::typeck::expected_default_return_type) } ExpectedReturnTypeLabel::Other { span, expected } => { diag.set_arg("expected", expected); - diag.span_label(span, DiagnosticMessage::fluent("typeck-expected-return-type")) + diag.span_label(span, rustc_errors::fluent::typeck::expected_return_type) } } @@ -338,14 +349,22 @@ diagnostic struct. (`rustc_errors::fluent` is implicit in the attribute, so just `typeck::field_already_declared`). - See [translation documentation](./translation.md). -- `#[suggestion{,_hidden,_short,_verbose}(message = "...", code = "...", applicability = "...")]` +- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]` - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._ - _Mandatory_ - Defines the type to be representing a suggestion. - - `message = "..."` (_Mandatory_) - - Value is the Fluent attribute (relative to the Fluent message specified - by `slug`) for the suggestion's message. - - Defaults to `suggestion`. + - Slug (_Mandatory_) + - A path to an item in `rustc_errors::fluent`. Always in a module starting + with a Fluent resource name (which is typically the name of the crate + that the diagnostic is from), e.g. + `rustc_errors::fluent::typeck::field_already_declared` + (`rustc_errors::fluent` is implicit in the attribute, so just + `typeck::field_already_declared`). Fluent attributes for all messages + exist as top-level items in that module (so `typeck_message.attr` is just + `typeck::attr`). + - See [translation documentation](./translation.md). + - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or + - `.suggestion` in Fluent). - `code = "..."` (_Mandatory_) - Value is a format string indicating the code to be suggested as a replacement. diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md index 39007f8d1..33d9646f6 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md @@ -1,4 +1,5 @@ # Lints + This page documents some of the machinery around lint registration and how we run lints in the compiler. @@ -8,6 +9,7 @@ everything rotates. It's not available during the early parts of compilation lints, which can only happen after plugin registration. ## Lints vs. lint passes + There are two parts to the linting mechanism within the compiler: lints and lint passes. Unfortunately, a lot of the documentation we have refers to both of these as just "lints." @@ -15,11 +17,18 @@ of these as just "lints." First, we have the lint declarations themselves: this is where the name and default lint level and other metadata come from. These are normally defined by way of the [`declare_lint!`] macro, which boils down to a static with type -`&rustc_session::lint::Lint`. +[`&rustc_lint_defs::Lint`]. + +First, we have the lint declarations themselves, +and this is where the name and default lint level and other metadata come from. +These are normally defined by way of the [`declare_lint!`] macro, +which boils down to a static with type [`&rustc_lint_defs::Lint`] +(although this may change in the future, +as the macro is somewhat unwieldy to add new fields to, +like all macros). -As of <!-- date: 2022-02 --> February 2022, we lint against direct declarations -without the use of the macro today (although this may change in the future, as -the macro is somewhat unwieldy to add new fields to, like all macros). +As of <!-- date-check --> Aug 2022, +we lint against direct declarations without the use of the macro. Lint declarations don't carry any "state" - they are merely global identifiers and descriptions of lints. We assert at runtime that they are not registered @@ -34,8 +43,10 @@ lints are emitted as part of other work (e.g., type checking, etc.). ## Registration ### High-level overview -In [`rustc_interface::register_plugins`] the [`LintStore`] is created and all -lints are registered. + +In [`rustc_interface::register_plugins`], +the [`LintStore`] is created, +and all lints are registered. There are four 'sources' of lints: @@ -61,6 +72,7 @@ then invoke the lint pass methods. The lint pass methods take `&mut self` so they can keep track of state internally. #### Internal lints + These are lints used just by the compiler or plugins like `clippy`. They can be found in `rustc_lint::internal`. @@ -73,16 +85,20 @@ function which is called when constructing a new lint store inside [`rustc_lint::new_lint_store`]. ### Builtin Lints -These are primarily described in two places: `rustc_session::lint::builtin` and -`rustc_lint::builtin`. Often the first provides the definitions for the lints -themselves, and the latter provides the lint pass definitions (and -implementations), but this is not always true. -The builtin lint registration happens in the [`rustc_lint::register_builtins`] -function. Just like with internal lints, this happens inside of -[`rustc_lint::new_lint_store`]. +These are primarily described in two places, +`rustc_lint_defs::builtin` and `rustc_lint::builtin`. +Often the first provides the definitions for the lints themselves, +and the latter provides the lint pass definitions (and implementations), +but this is not always true. + +The builtin lint registration happens in +the [`rustc_lint::register_builtins`] function. +Just like with internal lints, +this happens inside of [`rustc_lint::new_lint_store`]. #### Plugin lints + This is one of the primary use cases remaining for plugins/drivers. Plugins are given access to the mutable `LintStore` during registration (which happens inside of [`rustc_interface::register_plugins`]) and they can call any @@ -94,6 +110,7 @@ diagnostics and help text; otherwise plugin lints are mostly just as first class as rustc builtin lints. #### Driver lints + These are the lints provided by drivers via the `rustc_interface::Config` [`register_lints`] field, which is a callback. Drivers should, if finding it already set, call the function currently set within the callback they add. The @@ -102,6 +119,7 @@ best way for drivers to get access to this is by overriding the structure. ## Compiler lint passes are combined into one pass + Within the compiler, for performance reasons, we usually do not register dozens of lint passes. Instead, we have a single lint pass of each variety (e.g., `BuiltinCombinedModuleLateLintPass`) which will internally call all of the @@ -121,3 +139,4 @@ approach, it is beneficial to do so for performance reasons. [`declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint.html [`declare_tool_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_tool_lint.html [`register_lints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html#structfield.register_lints +[`&rustc_lint_defs::Lint`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/struct.Lint.html diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index 5c078ffb3..5bb37fbc2 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -32,23 +32,23 @@ Diagnostic messages are defined in Fluent resources. A combined set of Fluent resources for a given locale (e.g. `en-US`) is known as Fluent bundle. ```fluent -typeck-address-of-temporary-taken = cannot take address of a temporary +typeck_address_of_temporary_taken = cannot take address of a temporary ``` -In the above example, `typeck-address-of-temporary-taken` is the identifier for +In the above example, `typeck_address_of_temporary_taken` is the identifier for a Fluent message and corresponds to the diagnostic message in English. Other Fluent resources can be written which would correspond to a message in another language. Each diagnostic therefore has at least one Fluent message. ```fluent -typeck-address-of-temporary-taken = cannot take address of a temporary +typeck_address_of_temporary_taken = cannot take address of a temporary .label = temporary value ``` By convention, diagnostic messages for subdiagnostics are specified as "attributes" on Fluent messages (additional related messages, denoted by the `.<attribute-name>` syntax). In the above example, `label` is an attribute of -`typeck-address-of-temporary-taken` which corresponds to the message for the +`typeck_address_of_temporary_taken` which corresponds to the message for the label added to this diagnostic. Diagnostic messages often interpolate additional context into the message shown @@ -56,7 +56,7 @@ to the user, such as the name of a type or of a variable. Additional context to Fluent messages is provided as an "argument" to the diagnostic. ```fluent -typeck-struct-expr-non-exhaustive = +typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression ``` @@ -67,6 +67,13 @@ discussed in detail later). You can consult the [Fluent] documentation for other usage examples of Fluent and its syntax. +### Guideline for message naming +Usually, fluent uses `-` for separating words inside a message name. However, +`_` is accepted by fluent as well. As `_` fits Rust's use cases better, due to +the identifiers on the Rust side using `_` as well, inside rustc, `-` is not +allowed for separating words, and instead `_` is recommended. The only exception +is for leading `-`s, for message names like `-passes_see_issue`. + ### Guidelines for writing translatable messages For a message to be translatable into different languages, all of the information required by any language must be provided to the diagnostic as an @@ -106,10 +113,10 @@ fluent_messages! { For example, given the following Fluent... ```fluent -typeck-field-multiply-specified-in-initializer = +typeck_field_multiply_specified_in_initializer = field `{$ident}` specified more than once .label = used more than once - .label-previous-use = first use of `{$ident}` + .label_previous_use = first use of `{$ident}` ``` ...then the `fluent_messages` macro will generate: @@ -122,11 +129,11 @@ pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[ mod fluent_generated { mod typeck { pub const field_multiply_specified_in_initializer: DiagnosticMessage = - DiagnosticMessage::new("typeck-field-multiply-specified-in-initializer"); + DiagnosticMessage::new("typeck_field_multiply_specified_in_initializer"); pub const label: SubdiagnosticMessage = SubdiagnosticMessage::attr("label"); pub const label_previous_use: SubdiagnosticMessage = - SubdiagnosticMessage::attr("previous-use-label"); + SubdiagnosticMessage::attr("previous_use_label"); } } ``` @@ -217,7 +224,7 @@ returned by `Emitter::fluent_bundle`. This bundle is used preferentially when translating messages, the fallback bundle is only used if the primary bundle is missing a message or not provided. -As of <!-- date: 2022-06 --> June 2022, there are no locale bundles +As of <!-- date-check --> June 2022, there are no locale bundles distributed with the compiler, but mechanisms are implemented for loading bundles. diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index f16c22d93..5899753ba 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -157,9 +157,12 @@ no changes added to commit (use "git add" and/or "git commit -a") These changes are not changes to files: they are changes to submodules (more on this [later](#git-submodules)). To get rid of those, run `git submodule update` (or run any `x.py` command, which will automatically update the submodules). -Note that there is (as of <!-- date: 2022-02 --> February 2022) a [bug][#77620] if you use -worktrees, submodules, and `x.py` in a commit hook. If you run into an error -like: +Note that, +as of <!-- date-check --> Aug 2022, +there is a [bug][#77620] if you use worktrees, +submodules, and `x.py` in a commit hook. +If you run into an error like the following, +it's not anything you did wrong: ``` error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Cargo.toml` @@ -167,7 +170,8 @@ error: failed to read `/home/joshua/rustc-worktree/src/tools/miri/cargo-miri/Car Caused by: No such file or directory (os error 2) ``` -it's not anything you did wrong. There is a workaround in [the issue][#77620-workaround]. + +There is a workaround in [the issue][#77620-workaround]. [#77620]: https://github.com/rust-lang/rust/issues/77620 [#77620-workaround]: https://github.com/rust-lang/rust/issues/77620#issuecomment-705228229 diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index ea4bdfca6..b186f4820 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -222,9 +222,10 @@ properly-configured variables in LLVM IR, according to very specific details of the [_LLVM Coverage Mapping Format_][coverage-mapping-format] (Version 6).[^llvm-and-covmap-versions] -[^llvm-and-covmap-versions]: The Rust compiler (as of <!-- date: 2021-12 --> -December 2021) supports _LLVM Coverage Mapping Format_ Version 5 or 6. Version 5 -was introduced in _LLVM 12_, which is (as of this writing) the minimum LLVM +[^llvm-and-covmap-versions]: The Rust compiler (as of <!-- date-check --> December 2021) +supports _LLVM Coverage Mapping Format_ Version 5 or 6. Version 5 +was introduced in _LLVM 12_, +which is (as of <!-- date-check: December 2021--> this writing) the minimum LLVM version supported by the current version of Rust. Version 6 was introduced in _LLVM 13_, which is currently the default LLVM version for Rust. The Rust compiler will automatically use the most up-to-date coverage mapping format diff --git a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md index 2be072dd2..956f56828 100644 --- a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md +++ b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md @@ -14,9 +14,9 @@ This declares an opaque type named `Foo`, of which the only information is that it implements `Bar`. Therefore, any of `Bar`'s interface can be used on a `Foo`, but nothing else (regardless of whether it implements any other traits). -Since there needs to be a concrete background type, you can (as of <!-- date: -2021-01 --> January 2021) express that type by using the opaque type in a -"defining use site". +Since there needs to be a concrete background type, +you can (as of <!-- date-check --> January 2021) express that type +by using the opaque type in a "defining use site". ```rust,ignore struct Struct; diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index de6c88e7e..c7da92542 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -292,7 +292,7 @@ Moreover, the compiler wasn't originally built to use a query system; the query system has been retrofitted into the compiler, so parts of it are not query-fied yet. Also, LLVM isn't our code, so that isn't querified either. The plan is to eventually query-fy all of the steps listed in the previous section, -but as of <!-- date: 2021-11 --> November 2021, only the steps between HIR and +but as of <!-- date-check --> November 2021, only the steps between HIR and LLVM IR are query-fied. That is, lexing, parsing, name resolution, and macro expansion are done all at once for the whole program. diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md index 4aa13d781..e93f51dbb 100644 --- a/src/doc/rustc-dev-guide/src/parallel-rustc.md +++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md @@ -1,34 +1,116 @@ # Parallel Compilation -As of <!-- date: 2022-05 --> May 2022, The only stage of the compiler -that is already parallel is codegen. The nightly compiler implements query evaluation, -but there is still a lot of work to be done. The lack of parallelism at other stages -also represents an opportunity for improving compiler performance. One can try out the current -parallel compiler work by enabling it in the `config.toml`. +As of <!-- date-check --> August 2022, the only stage of the compiler that +is already parallel is codegen. Some parts of the compiler already have +parallel implementations, such as query evaluation, type check and +monomorphization, but the general version of the compiler does not include +these parallelization functions. **To try out the current parallel compiler**, +one can install rustc from source code with `parallel-compiler = true` in +the `config.toml`. + +The lack of parallelism at other stages (for example, macro expansion) also +represents an opportunity for improving compiler performance. These next few sections describe where and how parallelism is currently used, and the current status of making parallel compilation the default in `rustc`. -The underlying thread-safe data-structures used in the parallel compiler -can be found in the `rustc_data_structures::sync` module. Some of these data structures -use the `parking_lot` crate as well. - ## Codegen -There are two underlying thread safe data structures used in code generation: - -- `Lrc` - - Which is an [`Arc`][Arc] if `parallel_compiler` is true, and a [`Rc`][Rc] - if it is not. -- `MetadataRef` -> [`OwningRef<Box<dyn Erased + Send + Sync>, [u8]>`][OwningRef] - - This data structure is specific to `rustc`. - During [monomorphization][monomorphization] the compiler splits up all the code to be generated into smaller chunks called _codegen units_. These are then generated by independent instances of LLVM running in parallel. At the end, the linker is run to combine all the codegen units together into one binary. This process occurs in the `rustc_codegen_ssa::base` module. +## Data Structures + +The underlying thread-safe data-structures used in the parallel compiler +can be found in the `rustc_data_structures::sync` module. These data structures +are implemented diferently depending on whether `parallel-compiler` is true. + +| data structure | parallel | non-parallel | +| -------------------------------- | --------------------------------------------------- | ------------ | +| Lrc | std::sync::Arc | std::rc::Rc | +| Weak | std::sync::Weak | std::rc::Weak | +| Atomic{Bool}/{Usize}/{U32}/{U64} | std::sync::atomic::Atomic{Bool}/{Usize}/{U32}/{U64} | (std::cell::Cell<bool/usize/u32/u64>) | +| OnceCell | std::sync::OnceLock | std::cell::OnceCell | +| Lock\<T> | (parking_lot::Mutex\<T>) | (std::cell::RefCell) | +| RwLock\<T> | (parking_lot::RwLock\<T>) | (std::cell::RefCell) | +| MTRef<'a, T> | &'a T | &'a mut T | +| MTLock\<T> | (Lock\<T>) | (T) | +| ReadGuard | parking_lot::RwLockReadGuard | std::cell::Ref | +| MappedReadGuard | parking_lot::MappedRwLockReadGuard | std::cell::Ref | +| WriteGuard | parking_lot::RwLockWriteGuard | std::cell::RefMut | +| MappedWriteGuard | parking_lot::MappedRwLockWriteGuard | std::cell::RefMut | +| LockGuard | parking_lot::MutexGuard | std::cell::RefMut | +| MappedLockGuard | parking_lot::MappedMutexGuard | std::cell::RefMut | +| MetadataRef | [`OwningRef<Box<dyn Erased + Send + Sync>, [u8]>`][OwningRef] | [`OwningRef<Box<dyn Erased>, [u8]>`][OwningRef] | + +- These thread-safe data structures interspersed during compilation can + cause a lot of lock contention, which actually degrades performance as the + number of threads increases beyond 4. This inspires us to audit the use + of these data structures, leading to either refactoring to reduce use of + shared state, or persistent documentation covering invariants, atomicity, + and lock orderings. + +- On the other hand, we still need to figure out what other invariants + during compilation might not hold in parallel compilation. + +### WorkLocal + +`WorkLocal` is a special data structure implemented for parallel compiler. +It holds worker-locals values for each thread in a thread pool. You can only +access the worker local value through the Deref impl on the thread pool it +was constructed on. It will panic otherwise. + +`WorkLocal` is used to implement the `Arena` allocator in the parallel +environment, which is critical in parallel queries. Its implementation +is located in the `rustc-rayon-core::worker_local` module. However, in the +non-parallel compiler, it is implemented as `(OneThread<T>)`, whose `T` +can be accessed directly through `Deref::deref`. + +## Parallel Iterator + +The parallel iterators provided by the [`rayon`] crate are easy ways +to implement parallelism. In the current implementation of the parallel +compiler we use a custom [fork][rustc-rayon] of [`rayon`] to run tasks in parallel. + +Some iterator functions are implemented to run loops in parallel +when `parallel-compiler` is true. + +| Function(Omit `Send` and `Sync`) | Introduction | Owning Module | +| ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------- | +| **par_iter**<T: IntoParallelIterator>(t: T) -> T::Iter | generate a parallel iterator | rustc_data_structure::sync | +| **par_for_each_in**<T: IntoParallelIterator>(t: T, for_each: impl Fn(T::Item)) | generate a parallel iterator and run `for_each` on each element | rustc_data_structure::sync | +| **Map::par_body_owners**(self, f: impl Fn(LocalDefId)) | run `f` on all hir owners in the crate | rustc_middle::hir::map | +| **Map::par_for_each_module**(self, f: impl Fn(LocalDefId)) | run `f` on all modules and sub modules in the crate | rustc_middle::hir::map | +| **ModuleItems::par_items**(&self, f: impl Fn(ItemId)) | run `f` on all items in the module | rustc_middle::hir | +| **ModuleItems::par_trait_items**(&self, f: impl Fn(TraitItemId)) | run `f` on all trait items in the module | rustc_middle::hir | +| **ModuleItems::par_impl_items**(&self, f: impl Fn(ImplItemId)) | run `f` on all impl items in the module | rustc_middle::hir | +| **ModuleItems::par_foreign_items**(&self, f: impl Fn(ForeignItemId)) | run `f` on all foreign items in the module | rustc_middle::hir | + +There are a lot of loops in the compiler which can possibly be +parallelized using these functions. As of <!-- date-check--> August +2022, scenarios where the parallel iterator function has been used +are as follows: + +| caller | scenario | callee | +| ------------------------------------------------------- | ------------------------------------------------------------ | ------------------------ | +| rustc_metadata::rmeta::encoder::prefetch_mir | Prefetch queries which will be needed later by metadata encoding | par_iter | +| rustc_monomorphize::collector::collect_crate_mono_items | Collect monomorphized items reachable from non-generic items | par_for_each_in | +| rustc_interface::passes::analysis | Check the validity of the match statements | Map::par_body_owners | +| rustc_interface::passes::analysis | MIR borrow check | Map::par_body_owners | +| rustc_typeck::check::typeck_item_bodies | Type check | Map::par_body_owners | +| rustc_interface::passes::hir_id_validator::check_crate | Check the validity of hir | Map::par_for_each_module | +| rustc_interface::passes::analysis | Check the validity of loops body, attributes, naked functions, unstable abi, const bodys | Map::par_for_each_module | +| rustc_interface::passes::analysis | Liveness and intrinsic checking of MIR | Map::par_for_each_module | +| rustc_interface::passes::analysis | Deathness checking | Map::par_for_each_module | +| rustc_interface::passes::analysis | Privacy checking | Map::par_for_each_module | +| rustc_lint::late::check_crate | Run per-module lints | Map::par_for_each_module | +| rustc_typeck::check_crate | Well-formedness checking | Map::par_for_each_module | + +There are still many loops that have the potential to use parallel iterators. + ## Query System The query model has some properties that make it actually feasible to evaluate @@ -48,44 +130,22 @@ When a query `foo` is evaluated, the cache table for `foo` is locked. start evaluating. - If there *is* another query invocation for the same key in progress, we release the lock, and just block the thread until the other invocation has - computed the result we are waiting for. This cannot deadlock because, as - mentioned before, query invocations form a DAG. Some threads will always make - progress. + computed the result we are waiting for. **Cycle error detection** in the parallel + compiler requires more complex logic than in single-threaded mode. When + worker threads in parallel queries stop making progress due to interdependence, + the compiler uses an extra thread *(named deadlock handler)* to detect, remove and + report the cycle error. + +Parallel query still has a lot of work to do, most of which is related to +the previous `Data Structures` and `Parallel Iterators`. See [this tracking issue][tracking]. ## Rustdoc -As of <!-- date: 2022-05--> May 2022, there are still a number of steps +As of <!-- date-check--> May 2022, there are still a number of steps to complete before rustdoc rendering can be made parallel. More details on this issue can be found [here][parallel-rustdoc]. -## Current Status - -As of <!-- date: 2022-05 --> May 2022, work on explicitly parallelizing the -compiler has stalled. There is a lot of design and correctness work that needs -to be done. - -These are the basic ideas in the effort to make `rustc` parallel: - -- There are a lot of loops in the compiler that just iterate over all items in - a crate. These can possibly be parallelized. -- We can use (a custom fork of) [`rayon`] to run tasks in parallel. The custom - fork allows the execution of DAGs of tasks, not just trees. -- There are currently a lot of global data structures that need to be made - thread-safe. A key strategy here has been converting interior-mutable - data-structures (e.g. `Cell`) into their thread-safe siblings (e.g. `Mutex`). - -[`rayon`]: https://crates.io/crates/rayon - -As of <!-- date: 2022-05 --> May 2022, much of this effort is on hold due -to lack of manpower. We have a working prototype with promising performance -gains in many cases. However, there are two blockers: - -- It's not clear what invariants need to be upheld that might not hold in the - face of concurrency. An auditing effort was underway, but seems to have - stalled at some point. - -- There is a lot of lock contention, which actually degrades performance as the - number of threads increases beyond 4. +## Resources Here are some resources that can be used to learn more (note that some of them are a bit out of date): @@ -93,8 +153,9 @@ are a bit out of date): - [This IRLO thread by Zoxc, one of the pioneers of the effort][irlo0] - [This list of interior mutability in the compiler by nikomatsakis][imlist] - [This IRLO thread by alexchricton about performance][irlo1] -- [This tracking issue][tracking] +[`rayon`]: https://crates.io/crates/rayon +[rustc-rayon]: https://github.com/rust-lang/rustc-rayon [irlo0]: https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606 [imlist]: https://github.com/nikomatsakis/rustc-parallelization/blob/master/interior-mutability-list.md [irlo1]: https://internals.rust-lang.org/t/help-test-parallel-rustc/11503 diff --git a/src/doc/rustc-dev-guide/src/part-5-intro.md b/src/doc/rustc-dev-guide/src/part-5-intro.md index 4b7c25797..faa12f484 100644 --- a/src/doc/rustc-dev-guide/src/part-5-intro.md +++ b/src/doc/rustc-dev-guide/src/part-5-intro.md @@ -1,54 +1,57 @@ # From MIR to Binaries -All of the preceding chapters of this guide have one thing in common: we never -generated any executable machine code at all! With this chapter, all of that -changes. +All of the preceding chapters of this guide have one thing in common: +we never generated any executable machine code at all! +With this chapter, all of that changes. -So far, we've shown how the compiler can take raw source code in text format -and transform it into [MIR]. We have also shown how the compiler does various -analyses on the code to detect things like type or lifetime errors. Now, we -will finally take the MIR and produce some executable machine code. +So far, +we've shown how the compiler can take raw source code in text format +and transform it into [MIR]. +We have also shown how the compiler does various +analyses on the code to detect things like type or lifetime errors. +Now, we will finally take the MIR and produce some executable machine code. [MIR]: ./mir/index.md -> NOTE: This part of a compiler is often called the _backend_. The term is a bit -> overloaded because in the compiler source, it usually refers to the "codegen -> backend" (i.e. LLVM or Cranelift). Usually, when you see the word "backend" -> in this part, we are referring to the "codegen backend". +> NOTE: This part of a compiler is often called the _backend_. +> The term is a bit overloaded because in the compiler source, +> it usually refers to the "codegen backend" (i.e. LLVM, Cranelift, or GCC). +> Usually, when you see the word "backend" in this part, +> we are referring to the "codegen backend". So what do we need to do? -0. First, we need to collect the set of things to generate code for. In - particular, we need to find out which concrete types to substitute for - generic ones, since we need to generate code for the concrete types. - Generating code for the concrete types (i.e. emitting a copy of the code for - each concrete type) is called _monomorphization_, so the process of - collecting all the concrete types is called _monomorphization collection_. +0. First, we need to collect the set of things to generate code for. + In particular, + we need to find out which concrete types to substitute for generic ones, + since we need to generate code for the concrete types. + Generating code for the concrete types + (i.e. emitting a copy of the code for each concrete type) is called _monomorphization_, + so the process of collecting all the concrete types is called _monomorphization collection_. 1. Next, we need to actually lower the MIR to a codegen IR (usually LLVM IR) for each concrete type we collected. -2. Finally, we need to invoke LLVM or Cranelift, which runs a bunch of - optimization passes, generates executable code, and links together an - executable binary. +2. Finally, we need to invoke the codegen backend, + which runs a bunch of optimization passes, + generates executable code, + and links together an executable binary. [codegen1]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/fn.codegen_crate.html The code for codegen is actually a bit complex due to a few factors: -- Support for multiple codegen backends (LLVM and Cranelift). We try to share as much - backend code between them as possible, so a lot of it is generic over the - codegen implementation. This means that there are often a lot of layers of - abstraction. +- Support for multiple codegen backends (LLVM, Cranelift, and GCC). + We try to share as much backend code between them as possible, + so a lot of it is generic over the codegen implementation. + This means that there are often a lot of layers of abstraction. - Codegen happens asynchronously in another thread for performance. -- The actual codegen is done by a third-party library (either LLVM or Cranelift). +- The actual codegen is done by a third-party library (either of the 3 backends). -Generally, the [`rustc_codegen_ssa`][ssa] crate contains backend-agnostic code -(i.e. independent of LLVM or Cranelift), while the [`rustc_codegen_llvm`][llvm] -crate contains code specific to LLVM codegen. +Generally, the [`rustc_codegen_ssa`][ssa] crate contains backend-agnostic code, +while the [`rustc_codegen_llvm`][llvm] crate contains code specific to LLVM codegen. [ssa]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html [llvm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/index.html At a very high level, the entry point is -[`rustc_codegen_ssa::base::codegen_crate`][codegen1]. This function starts the -process discussed in the rest of this chapter. - +[`rustc_codegen_ssa::base::codegen_crate`][codegen1]. +This function starts the process discussed in the rest of this chapter. diff --git a/src/doc/rustc-dev-guide/src/profiling.md b/src/doc/rustc-dev-guide/src/profiling.md index ada497d88..e1666e237 100644 --- a/src/doc/rustc-dev-guide/src/profiling.md +++ b/src/doc/rustc-dev-guide/src/profiling.md @@ -108,6 +108,6 @@ The llvm-lines output is affected by several options. MIR optimizations have little impact. Compared to the default `RUSTFLAGS="-Z mir-opt-level=1"`, level 0 adds 0.3GB and level 2 removes 0.2GB. -As of <!-- date: 2022-07 --> July 2022, +As of <!-- date-check --> July 2022, inlining happens in LLVM and GCC codegen backends, missing only in the Cranelift one. diff --git a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md index b84a5dac4..8a08f1e04 100644 --- a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md @@ -76,7 +76,7 @@ executed, no results are cached. But the context already provides access to "input" data, i.e. pieces of immutable data that were computed before the context was created and that queries can access to do their computations. -As of <!-- date: 2021-01 --> January 2021, this input data consists mainly of +As of <!-- date-check --> January 2021, this input data consists mainly of the HIR map, upstream crate metadata, and the command-line options the compiler was invoked with; but in the future inputs will just consist of command-line options and a list of source files -- the HIR map will itself be provided by a diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 95e570dfc..3d60059bd 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -3,7 +3,7 @@ <!-- toc --> As described in [the high-level overview of the compiler][hl], the Rust compiler -is still (as of <!-- date: 2021-07 --> July 2021) transitioning from a +is still (as of <!-- date-check --> July 2021) transitioning from a traditional "pass-based" setup to a "demand-driven" system. The compiler query system is the key to rustc's demand-driven organization. The idea is pretty simple. Instead of entirely independent passes diff --git a/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md b/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md index 327415e5a..5ce93c3df 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver-getting-diagnostics.md @@ -7,7 +7,7 @@ To get diagnostics from the compiler, configure `rustc_interface::Config` to output diagnostic to a buffer, and run `TyCtxt.analysis`. The following was tested -with <!-- date: 2022-06 --> `nightly-2022-06-05` (See [here][example] +with <!-- date-check: June 2022 --> `nightly-2022-06-05` (See [here][example] for the complete example): [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-getting-diagnostics.rs diff --git a/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md b/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md index d70264fe4..ce53f3861 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver-interacting-with-the-ast.md @@ -5,7 +5,7 @@ ## Getting the type of an expression To get the type of an expression, use the `global_ctxt` to get a `TyCtxt`. -The following was tested with <!-- date: 2022-06 --> `nightly-2022-06-05` +The following was tested with <!-- date-check: June 2022 --> `nightly-2022-06-05` (see [here][example] for the complete example): [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-interacting-with-the-ast.rs diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md index 91bb0c358..f21c8725c 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md @@ -66,7 +66,7 @@ these passes, please let us know!) [44136]: https://github.com/rust-lang/rust/issues/44136 -Here is the list of passes as of <!-- date: 2022-05 --> May 2022: +Here is the list of passes as of <!-- date-check --> May 2022: - `calculate-doc-coverage` calculates information used for the `--show-coverage` flag. diff --git a/src/doc/rustc-dev-guide/src/salsa.md b/src/doc/rustc-dev-guide/src/salsa.md index afa01eda2..872308e78 100644 --- a/src/doc/rustc-dev-guide/src/salsa.md +++ b/src/doc/rustc-dev-guide/src/salsa.md @@ -9,7 +9,7 @@ want to watch [Salsa In More Depth](https://www.youtube.com/watch?v=i_IhACacPRY), also by Niko Matsakis. -> As of <!-- date: 2022-04 --> April 2022, although Salsa is inspired by +> As of <!-- date-check --> April 2022, although Salsa is inspired by > (among other things) rustc's query system, it is not used directly in rustc. > It _is_ used in chalk and extensively in `rust-analyzer`, but there are no > medium or long-term concrete plans to integrate it into the compiler. diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md index 454cd0f27..0ac19293b 100644 --- a/src/doc/rustc-dev-guide/src/stabilization_guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md @@ -99,24 +99,6 @@ require steps beyond what this guide talks about. Note: Before we stabilize any feature, it's the rule that it should appear in the documentation. -### Determining the stabilization version - -The version in which the feature will be stabilized *must* match -the value of [the `src/version` file in `master`][src-version] when the PR is merged. - -It's worth checking [the version schedule on the Forge][forge-versions] to see whether -changes are coming soon. You'll usually use the version labelled "Nightly". -"Nightly" is two versions higher than the current stable release, -since what's currently in beta will be the next stable release, -and any changes you're making now will be in the one after that. - -No PR is merged instantly, so you'll want to be careful around release time. -The version bump happens [the Friday before][forge-release-process] the stable release, -not the same time as the release. So if you're opening a PR shortly before then, -be prepared to update the version, or consider just opening it for one version -higher than the current nightly, with a note saying not to merge until -after the upcoming version bump. - ### Updating the feature-gate listing There is a central listing of feature-gates in @@ -127,7 +109,7 @@ to stabilize, something like (this example is taken from ```rust,ignore // pub(restricted) visibilities (RFC 1422) -(active, pub_restricted, "1.9.0", Some(32409)), +(active, pub_restricted, "CURRENT_RUSTC_VERSION", Some(32409)), ``` The above line should be moved down to the area for "accepted" @@ -136,11 +118,13 @@ When it is done, it should look like: ```rust,ignore // pub(restricted) visibilities (RFC 1422) -(accepted, pub_restricted, "1.31.0", Some(32409)), +(accepted, pub_restricted, "CURRENT_RUSTC_VERSION", Some(32409)), // note that we changed this ``` -(The version here is the one discussed in the previous section.) +(Even though you will encounter version numbers in the file of past changes, +you should not put the rustc version you expect your stabilization to happen in, +but instead `CURRENT_RUSTC_VERSION`) ### Removing existing uses of the feature-gate diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md index 09a66cdc9..1b8247005 100644 --- a/src/doc/rustc-dev-guide/src/test-implementation.md +++ b/src/doc/rustc-dev-guide/src/test-implementation.md @@ -155,5 +155,4 @@ $ rustc my_mod.rs -Z unpretty=hir [TestDesc]: https://doc.rust-lang.org/test/struct.TestDesc.html [Symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html [Ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html -[eRFC]: https://github.com/rust-lang/rfcs/blob/master/text/2318-custom-test-frameworks.md [rustc_ast]: https://github.com/rust-lang/rust/tree/master/compiler/rustc_ast diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 5c3dcf54b..70cef2ad3 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -452,7 +452,7 @@ fn main() { ## Revisions -Certain classes of tests support "revisions" (as of <!-- date: 2022-07 --> July 2022, +Certain classes of tests support "revisions" (as of <!-- date-check --> July 2022, this includes UI, assembly, codegen, debuginfo, incremental, and rustdoc UI tests, though incremental tests are somewhat different). Revisions allow a single test file to be used for multiple tests. diff --git a/src/doc/rustc-dev-guide/src/the-parser.md b/src/doc/rustc-dev-guide/src/the-parser.md index ff43220c1..0d37704e8 100644 --- a/src/doc/rustc-dev-guide/src/the-parser.md +++ b/src/doc/rustc-dev-guide/src/the-parser.md @@ -1,6 +1,6 @@ # Lexing and Parsing -As of <!-- date: 2021-01 --> January 2021, the lexer and parser are undergoing +As of <!-- date-check --> January 2021, the lexer and parser are undergoing refactoring to allow extracting them into libraries. The very first thing the compiler does is take the program (in Unicode @@ -35,9 +35,10 @@ The main entrypoint to the parser is via the various `parse_*` functions and oth the token stream, and then execute the parser to get a `Crate` (the root AST node). -To minimise the amount of copying that is done, both the `StringReader` and -`Parser` have lifetimes which bind them to the parent `ParseSess`. This contains -all the information needed while parsing, as well as the `SourceMap` itself. +To minimize the amount of copying that is done, +both [`StringReader`] and [`Parser`] have lifetimes which bind them to the parent `ParseSess`. +This contains all the information needed while parsing, +as well as the [`SourceMap`] itself. Note that while parsing, we may encounter macro definitions or invocations. We set these aside to be expanded (see [this chapter](./macro-expansion.md)). @@ -52,9 +53,9 @@ Code for lexical analysis is split between two crates: constituting tokens. Although it is popular to implement lexers as generated finite state machines, the lexer in `rustc_lexer` is hand-written. -- [`StringReader`] from [`rustc_ast`][rustc_ast] integrates `rustc_lexer` with `rustc` - specific data structures. Specifically, it adds `Span` information to tokens - returned by `rustc_lexer` and interns identifiers. +- [`StringReader`] integrates `rustc_lexer` with data structures specific to `rustc`. + Specifically, + it adds `Span` information to tokens returned by `rustc_lexer` and interns identifiers. [rustc_ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/index.html [rustc_errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html @@ -64,7 +65,7 @@ Code for lexical analysis is split between two crates: [rustc_parse]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [parser_lib]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html [parser]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/index.html -[`Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/parse/parser/struct.Parser.html +[`Parser`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/parser/struct.Parser.html [`StringReader`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.StringReader.html [visit module]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/index.html [sourcefile]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.SourceFile.html diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 4f8e6512c..2a811be3d 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -4,7 +4,7 @@ The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for "High-Level Abstract IR", is another IR used by rustc that is generated after -[type checking]. It is (as of <!-- date: 2022-04 --> April 2022) only used for +[type checking]. It is (as of <!-- date-check --> April 2022) only used for [MIR construction] and [exhaustiveness checking]. There is also [an experimental unsafety checker][thir-unsafeck] that operates on the THIR as a replacement for the current MIR unsafety checker, and can be used instead of the MIR unsafety checker by passing @@ -47,9 +47,19 @@ which is useful to keep peak memory in check. Having a THIR representation of all bodies of a crate in memory at the same time would be very heavy. You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag -to `rustc`. Here is how a function with just the statement `let x = 1 + 2;` gets represented in -THIR: +to `rustc`. + +To demonstrate, let's use the following example: + ```rust +fn main() { + let x = 1 + 2; +} +``` + +Here is how that gets represented in THIR (as of <!-- date-check --> Aug 2022): + +```rust,no_run Thir { // no match arms arms: [], @@ -57,57 +67,73 @@ Thir { // expression 0, a literal with a value of 1 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:14 (#0), kind: Literal { - literal: Const { - ty: i32, - val: Value(Scalar(0x00000001)), + lit: Spanned { + node: Int( + 1, + Unsuffixed, + ), + span: oneplustwo.rs:2:13: 2:14 (#0), }, - user_ty: None, - const_id: None, + neg: false, }, }, // expression 1, scope surronding literal 1 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:14 (#0), kind: Scope { - region_scope: Node(1), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 1, - }), // reference to expression 0 above + region_scope: Node(3), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 3, + }, + ), value: e0, }, }, // expression 2, literal 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:17: 2:18 (#0), kind: Literal { - literal: Const { - ty: i32, - val: Value(Scalar(0x00000002)), + lit: Spanned { + node: Int( + 2, + Unsuffixed, + ), + span: oneplustwo.rs:2:17: 2:18 (#0), }, - user_ty: None, - const_id: None, + neg: false, }, }, // expression 3, scope surrounding literal 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:17: 2:18 (#0), kind: Scope { - region_scope: Node(2), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 2, - }), + region_scope: Node(4), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 4, + }, + ), // reference to expression 2 above value: e2, }, @@ -115,7 +141,9 @@ Thir { // expression 4, represents 1 + 2 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:18 (#0), kind: Binary { op: Add, @@ -127,30 +155,38 @@ Thir { // expression 5, scope surronding expression 4 Expr { ty: i32, - temp_lifetime: Some(Node(6)), + temp_lifetime: Some( + Node(1), + ), span: oneplustwo.rs:2:13: 2:18 (#0), kind: Scope { - region_scope: Node(3), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 3, - }), + region_scope: Node(5), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 5, + }, + ), value: e4, }, }, // expression 6, block around statement Expr { ty: (), - temp_lifetime: Some(Node(8)), + temp_lifetime: Some( + Node(9), + ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Block { body: Block { targeted_by_break: false, - region_scope: Node(7), + region_scope: Node(8), opt_destruction_scope: None, span: oneplustwo.rs:1:11: 3:2 (#0), // reference to statement 0 below - stmts: [ s0 ], + stmts: [ + s0, + ], expr: None, safety_mode: Safe, }, @@ -160,25 +196,29 @@ Thir { Expr { ty: (), temp_lifetime: Some( - Node(8), + Node(9), ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Node(8), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 8, - }), + region_scope: Node(9), + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 9, + }, + ), value: e6, }, }, // destruction scope around expression 7 Expr { ty: (), - temp_lifetime: Some(Node(8)), + temp_lifetime: Some( + Node(9), + ), span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Destruction(8), + region_scope: Destruction(9), lint_level: Inherited, value: e7, }, @@ -188,8 +228,8 @@ Thir { // let statement Stmt { kind: Let { - remainder_scope: Remainder { block: 7, first_statement_index: 0}, - init_scope: Node(6), + remainder_scope: Remainder { block: 8, first_statement_index: 0}, + init_scope: Node(1), pattern: Pat { ty: i32, span: oneplustwo.rs:2:9: 2:10 (#0), @@ -197,22 +237,31 @@ Thir { mutability: Not, name: "x", mode: ByValue, - var: HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 5, - }, + var: LocalVarId( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 7, + }, + ), ty: i32, subpattern: None, is_primary: true, }, }, - initializer: Some(e5), - lint_level: Explicit(HirId { - owner: DefId(0:3 ~ oneplustwo[6ccc]::main), - local_id: 4, - }), + initializer: Some( + e5, + ), + else_block: None, + lint_level: Explicit( + HirId { + owner: DefId(0:3 ~ oneplustwo[6932]::main), + local_id: 6, + }, + ), }, - opt_destruction_scope: Some(Destruction(6)), + opt_destruction_scope: Some( + Destruction(1), + ), }, ], } diff --git a/src/doc/rustc-dev-guide/src/traits/chalk.md b/src/doc/rustc-dev-guide/src/traits/chalk.md index d4045c460..78deb3675 100644 --- a/src/doc/rustc-dev-guide/src/traits/chalk.md +++ b/src/doc/rustc-dev-guide/src/traits/chalk.md @@ -1,7 +1,7 @@ # Chalk-based trait solving -[Chalk][chalk] is an experimental trait solver for Rust that is (as of <!-- -date: 2022-05 --> May 2022) under development by the [Types team]. +[Chalk][chalk] is an experimental trait solver for Rust that is +(as of <!-- date-check --> May 2022) under development by the [Types team]. Its goal is to enable a lot of trait system features and bug fixes that are hard to implement (e.g. GATs or specialization). If you would like to help in hacking on the new solver, drop by on the rust-lang Zulip in the [`#t-types`] diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md index c22ee6de6..195fe6050 100644 --- a/src/doc/rustc-dev-guide/src/traits/resolution.md +++ b/src/doc/rustc-dev-guide/src/traits/resolution.md @@ -120,7 +120,7 @@ the obligation contains unbound inference variables. The subroutines that decide whether a particular impl/where-clause/etc applies to a particular obligation are collectively referred to as the process of -_matching_. As of <!-- date: 2022-05 --> May 2022, this amounts to unifying +_matching_. As of <!-- date-check --> May 2022, this amounts to unifying the `Self` types, but in the future we may also recursively consider some of the nested obligations, in the case of an impl. diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index 4be9211ee..10f1dd5ef 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -45,11 +45,9 @@ tcx.infer_ctxt().enter(|infcx| { }) ``` -Within the closure, `infcx` has the type `InferCtxt<'cx, 'tcx>` for some -fresh `'cx`, while `'tcx` is the same as outside the inference context. -(Again, see the [`ty` chapter][ty-ch] for more details on this setup.) - -[ty-ch]: ty.html +Within the closure, +`infcx` has the type `InferCtxt<'a, 'tcx>` for some fresh `'a`, +while `'tcx` is the same as outside the inference context. The `tcx.infer_ctxt` method actually returns a builder, which means there are some kinds of configuration you can do before the `infcx` is @@ -72,7 +70,7 @@ inference works, or perhaps this blog post on [Unification in the Chalk project]: http://smallcultfollowing.com/babysteps/blog/2017/03/25/unification-in-chalk-part-1/ All told, the inference context stores five kinds of inference variables -(as of <!-- date: 2021-06 --> June 2021): +(as of <!-- date-check --> June 2021): - Type variables, which come in three varieties: - General type variables (the most common). These can be unified with any |