From 9b588a6b69aae9b62291c3c11d423ba5b2145e74 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 23 Dec 2021 01:25:11 +0000 Subject: [PATCH 01/21] Add release notes for 1.58 --- RELEASES.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 4b9b20f4cba60..a29059c01445c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,169 @@ +Version 1.58.0 (2022-01-13) +========================== + +Language +-------- + +- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] +- [`*const T` pointers can now be dereferenced in const contexts.][89551] +- [The rules for when a generic struct implements `Unsize` have been relaxed.][90417] + +Compiler +-------- + +- [Add LLVM CFI support to the Rust compiler][89652] +- [Stabilize -Z strip as -C strip][90058] +- [Add support for LLVM coverage mapping format versions 5 and 6][91207] +- [Emit LLVM optimization remarks when enabled with `-Cremark`][90833] +- [Update the minimum external LLVM to 12][90175] +- [Add `x86_64-unknown-none` at Tier 3*][89062] +- [Build musl dist artifacts with debuginfo enabled][90733] +- [Fix CVE-2021-42574][90462] +- [Don't abort compilation after giving a lint error][87337] +- [Error messages point at the source of trait bound obligations in more places][89580] +- [Link with default MACOSX_DEPLOYMENT_TARGET if not otherwise specified.][90499] + +\* Refer to Rust's [platform support page][platform-support-doc] for more + information on Rust's tiered platform support. + +Libraries +--------- + +- [Add #[must_use] to Rc::downgrade][89833] +- [Add #[must_use] to expensive computations][89835] +- [Add #[must_use] to mem/ptr functions][89839] +- [Add #[must_use] to remaining core functions][89897] +- [Add #[must_use] to remaining alloc functions][89899] +- [Add #[must_use] to len and is_empty][89786] +- [Add #[must_use] to thread::Builder][89789] +- [Add #[must_use] to alloc functions that would leak memory][90427] +- [Add #[must_use] to remaining std functions (A-N)][90430] +- [Add #[must_use] to remaining std functions (O-Z)][90431] +- [Windows: Resolve `process::Command` program without using the current directory][87704] +- [Paths are automatically canonicalized on Windows for operations that support it][89174] +- [Re-enable `copy[_nonoverlapping]()` debug-checks][90041] +- [Implement `RefUnwindSafe` for `Rc`][87467] +- [Make RSplit: Clone not require T: Clone][90117] +- [unix: Make `std::thread::available_concurrency` support process-limited number of CPUs][89310] +- [Implement `Termination` for `Result`][88601] + +Stabilized APIs +--------------- + +- [`Metadata::is_symlink`][89677] +- [`Path::is_symlink`][89677] +- [`{integer}::saturating_div`][88624] +- [`Option::unwrap_unchecked`][89951] +- [`NonZero::is_power_of_two`][91301] +- [`unix::process::ExitStatusExt::core_dumped`][88300] +- [`unix::process::ExitStatusExt::stopped_signal`][88300] +- [`unix::process::ExitStatusExt::continued`][88300] +- [`unix::process::ExitStatusExt::into_raw`][88300] + +These APIs are now usable in const contexts: + +- [Partially stabilize `duration_consts_2`][89542] +- [`Duration::new`][89542] +- [`Duration::checked_add`][89542] +- [`Duration::saturating_add`][89542] +- [`Duration::checked_sub`][89542] +- [`Duration::saturating_sub`][89542] +- [`Duration::checked_mul`][89542] +- [`Duration::saturating_mul`][89542] +- [`Duration::checked_div`][89542] +- [`Duration::as_secs_f64`][89542] +- [`Duration::as_secs_f32`][89542] +- [`Duration::from_secs_f64`][89542] +- [`Duration::from_secs_f32`][89542] +- [`Duration::mul_f64`][89542] +- [`Duration::mul_f32`][89542] +- [`Duration::div_f64`][89542] +- [`Duration::div_f32`][89542] +- [`Duration::div_duration_f64`][89542] +- [`Duration::div_duration_f32`][89542] +- [`MaybeUninit::as_ptr`][90896] +- [`MaybeUninit::as_mut_ptr`][90896] +- [`MaybeUninit::assume_init`][90896] +- [`MaybeUninit::assume_init_ref`][90896] + +Cargo +----- + +- [Add --message-format for install command][cargo/10107] +- [Warn when alias shadows external subcommand][cargo/10082] + +Misc +---- + +- [Show all Deref implementations recursively in rustdoc][90183] +- [Use computed visibility in rustdoc][88447] + +Compatibility Notes +------------------- + +- [All proc-macro backward-compatibility lints are now deny-by-default.][88041] +- [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297] +- [Refactor weak symbols in std::sys::unix][90846] +- `RUSTFLAGS` is no longer set for build scripts. This change was made in + 1.55, but the release notes did not highlight this change. Build scripts + should use `CARGO_ENCODED_RUSTFLAGS` instead. See the + [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) + for more details. +- [rustdoc doctest: detect `fn main` after an unexpected semicolon][91026] + +Internal Changes +---------------- + +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc +and related tools. + +- [Try all stable method candidates first before trying unstable ones][90329] +- [Implement coherence checks for negative trait impls][90104] +- [Add rustc lint, warning when iterating over hashmaps][89558] +- [Optimize live point computation][90491] +- [Enable verification for 1/32th of queries loaded from disk][90361] +- [Implement version of normalize_erasing_regions that allows for normalization failure][91255] + +[87337]: https://github.com/rust-lang/rust/pull/87337/ +[87467]: https://github.com/rust-lang/rust/pull/87467/ +[87704]: https://github.com/rust-lang/rust/pull/87704/ +[88041]: https://github.com/rust-lang/rust/pull/88041/ +[88300]: https://github.com/rust-lang/rust/pull/88300/ +[88447]: https://github.com/rust-lang/rust/pull/88447/ +[88601]: https://github.com/rust-lang/rust/pull/88601/ +[88624]: https://github.com/rust-lang/rust/pull/88624/ +[89062]: https://github.com/rust-lang/rust/pull/89062/ +[89174]: https://github.com/rust-lang/rust/pull/89174/ +[89542]: https://github.com/rust-lang/rust/pull/89542/ +[89551]: https://github.com/rust-lang/rust/pull/89551/ +[89558]: https://github.com/rust-lang/rust/pull/89558/ +[89580]: https://github.com/rust-lang/rust/pull/89580/ +[89652]: https://github.com/rust-lang/rust/pull/89652/ +[89677]: https://github.com/rust-lang/rust/pull/89677/ +[89951]: https://github.com/rust-lang/rust/pull/89951/ +[90058]: https://github.com/rust-lang/rust/pull/90058/ +[90104]: https://github.com/rust-lang/rust/pull/90104/ +[90117]: https://github.com/rust-lang/rust/pull/90117/ +[90175]: https://github.com/rust-lang/rust/pull/90175/ +[90183]: https://github.com/rust-lang/rust/pull/90183/ +[90297]: https://github.com/rust-lang/rust/pull/90297/ +[90329]: https://github.com/rust-lang/rust/pull/90329/ +[90361]: https://github.com/rust-lang/rust/pull/90361/ +[90417]: https://github.com/rust-lang/rust/pull/90417/ +[90473]: https://github.com/rust-lang/rust/pull/90473/ +[90491]: https://github.com/rust-lang/rust/pull/90491/ +[90733]: https://github.com/rust-lang/rust/pull/90733/ +[90833]: https://github.com/rust-lang/rust/pull/90833/ +[90846]: https://github.com/rust-lang/rust/pull/90846/ +[90896]: https://github.com/rust-lang/rust/pull/90896/ +[91026]: https://github.com/rust-lang/rust/pull/91026/ +[91207]: https://github.com/rust-lang/rust/pull/91207/ +[91255]: https://github.com/rust-lang/rust/pull/91255/ +[91301]: https://github.com/rust-lang/rust/pull/91301/ +[cargo/10082]: https://github.com/rust-lang/cargo/pull/10082/ +[cargo/10107]: https://github.com/rust-lang/cargo/pull/10107/ + Version 1.57.0 (2021-12-02) ========================== From 0928e5257132f76faa9d3d19c79eeba8f36b462a Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 21 Dec 2021 14:46:50 -0800 Subject: [PATCH 02/21] Apply suggestions from code review Co-authored-by: Hans Kratz Co-authored-by: Chris Denton Co-authored-by: Joshua Nelson --- RELEASES.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index a29059c01445c..db8ebbbc8bd1b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -18,10 +18,8 @@ Compiler - [Update the minimum external LLVM to 12][90175] - [Add `x86_64-unknown-none` at Tier 3*][89062] - [Build musl dist artifacts with debuginfo enabled][90733] -- [Fix CVE-2021-42574][90462] - [Don't abort compilation after giving a lint error][87337] - [Error messages point at the source of trait bound obligations in more places][89580] -- [Link with default MACOSX_DEPLOYMENT_TARGET if not otherwise specified.][90499] \* Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support. @@ -39,12 +37,10 @@ Libraries - [Add #[must_use] to alloc functions that would leak memory][90427] - [Add #[must_use] to remaining std functions (A-N)][90430] - [Add #[must_use] to remaining std functions (O-Z)][90431] -- [Windows: Resolve `process::Command` program without using the current directory][87704] - [Paths are automatically canonicalized on Windows for operations that support it][89174] - [Re-enable `copy[_nonoverlapping]()` debug-checks][90041] - [Implement `RefUnwindSafe` for `Rc`][87467] - [Make RSplit: Clone not require T: Clone][90117] -- [unix: Make `std::thread::available_concurrency` support process-limited number of CPUs][89310] - [Implement `Termination` for `Result`][88601] Stabilized APIs @@ -92,7 +88,7 @@ Cargo - [Add --message-format for install command][cargo/10107] - [Warn when alias shadows external subcommand][cargo/10082] -Misc +Rustdoc ---- - [Show all Deref implementations recursively in rustdoc][90183] @@ -101,15 +97,16 @@ Misc Compatibility Notes ------------------- +- Windows: [`std::process::Command` will no longer search the current directory for executables.][87704] - [All proc-macro backward-compatibility lints are now deny-by-default.][88041] - [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297] - [Refactor weak symbols in std::sys::unix][90846] +- [rustdoc now rejects some unexpected semicolons in doctests][91026] - `RUSTFLAGS` is no longer set for build scripts. This change was made in 1.55, but the release notes did not highlight this change. Build scripts should use `CARGO_ENCODED_RUSTFLAGS` instead. See the [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) for more details. -- [rustdoc doctest: detect `fn main` after an unexpected semicolon][91026] Internal Changes ---------------- From 8fd6e8bb544736be1f35f9d799695692c139f40f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 23 Dec 2021 01:27:19 +0000 Subject: [PATCH 03/21] Move RUSTFLAGS compat note to 1.55 --- RELEASES.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index db8ebbbc8bd1b..1bc08295e48e9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -102,11 +102,6 @@ Compatibility Notes - [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297] - [Refactor weak symbols in std::sys::unix][90846] - [rustdoc now rejects some unexpected semicolons in doctests][91026] -- `RUSTFLAGS` is no longer set for build scripts. This change was made in - 1.55, but the release notes did not highlight this change. Build scripts - should use `CARGO_ENCODED_RUSTFLAGS` instead. See the - [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) - for more details. Internal Changes ---------------- @@ -551,6 +546,10 @@ Compatibility Notes `Command` would cause them to be ASCII-uppercased. - [Rustdoc will now warn on using rustdoc lints that aren't prefixed with `rustdoc::`][86849] +- `RUSTFLAGS` is no longer set for build scripts. Build scripts + should use `CARGO_ENCODED_RUSTFLAGS` instead. See the + [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) + for more details. [86849]: https://github.com/rust-lang/rust/pull/86849 [86513]: https://github.com/rust-lang/rust/pull/86513 From e2c659bed8f1cf50fbc9312b703753b3245e2d42 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 23 Dec 2021 01:41:45 +0000 Subject: [PATCH 04/21] Add links to stabilized APIs --- RELEASES.md | 92 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 1bc08295e48e9..7152338387c55 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -46,41 +46,36 @@ Libraries Stabilized APIs --------------- -- [`Metadata::is_symlink`][89677] -- [`Path::is_symlink`][89677] -- [`{integer}::saturating_div`][88624] -- [`Option::unwrap_unchecked`][89951] -- [`NonZero::is_power_of_two`][91301] -- [`unix::process::ExitStatusExt::core_dumped`][88300] -- [`unix::process::ExitStatusExt::stopped_signal`][88300] -- [`unix::process::ExitStatusExt::continued`][88300] -- [`unix::process::ExitStatusExt::into_raw`][88300] +- [`Metadata::is_symlink`] +- [`Path::is_symlink`] +- [`{integer}::saturating_div`] +- [`Option::unwrap_unchecked`] +- [`NonZero{unsigned}::is_power_of_two`] These APIs are now usable in const contexts: -- [Partially stabilize `duration_consts_2`][89542] -- [`Duration::new`][89542] -- [`Duration::checked_add`][89542] -- [`Duration::saturating_add`][89542] -- [`Duration::checked_sub`][89542] -- [`Duration::saturating_sub`][89542] -- [`Duration::checked_mul`][89542] -- [`Duration::saturating_mul`][89542] -- [`Duration::checked_div`][89542] -- [`Duration::as_secs_f64`][89542] -- [`Duration::as_secs_f32`][89542] -- [`Duration::from_secs_f64`][89542] -- [`Duration::from_secs_f32`][89542] -- [`Duration::mul_f64`][89542] -- [`Duration::mul_f32`][89542] -- [`Duration::div_f64`][89542] -- [`Duration::div_f32`][89542] -- [`Duration::div_duration_f64`][89542] -- [`Duration::div_duration_f32`][89542] -- [`MaybeUninit::as_ptr`][90896] -- [`MaybeUninit::as_mut_ptr`][90896] -- [`MaybeUninit::assume_init`][90896] -- [`MaybeUninit::assume_init_ref`][90896] +- [`Duration::new`] +- [`Duration::checked_add`] +- [`Duration::saturating_add`] +- [`Duration::checked_sub`] +- [`Duration::saturating_sub`] +- [`Duration::checked_mul`] +- [`Duration::saturating_mul`] +- [`Duration::checked_div`] +- [`Duration::as_secs_f64`] +- [`Duration::as_secs_f32`] +- [`Duration::from_secs_f64`] +- [`Duration::from_secs_f32`] +- [`Duration::mul_f64`] +- [`Duration::mul_f32`] +- [`Duration::div_f64`] +- [`Duration::div_f32`] +- [`Duration::div_duration_f64`] +- [`Duration::div_duration_f32`] +- [`MaybeUninit::as_ptr`] +- [`MaybeUninit::as_mut_ptr`] +- [`MaybeUninit::assume_init`] +- [`MaybeUninit::assume_init_ref`] Cargo ----- @@ -89,7 +84,7 @@ Cargo - [Warn when alias shadows external subcommand][cargo/10082] Rustdoc ----- +------- - [Show all Deref implementations recursively in rustdoc][90183] - [Use computed visibility in rustdoc][88447] @@ -155,6 +150,37 @@ and related tools. [91301]: https://github.com/rust-lang/rust/pull/91301/ [cargo/10082]: https://github.com/rust-lang/cargo/pull/10082/ [cargo/10107]: https://github.com/rust-lang/cargo/pull/10107/ +[`Metadata::is_symlink`]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html#method.is_symlink +[`Path::is_symlink`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.is_symlink +[`{integer}::saturating_div`]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.saturating_div +[`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked +[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two +[`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped +[`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal +[`unix::process::ExitStatusExt::continued`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.continued +[`unix::process::ExitStatusExt::into_raw`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.into_raw +[`Duration::new`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.new +[`Duration::checked_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_add +[`Duration::saturating_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add +[`Duration::checked_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_sub +[`Duration::saturating_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_sub +[`Duration::checked_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_mul +[`Duration::saturating_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_mul +[`Duration::checked_div`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_div +[`Duration::as_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f64 +[`Duration::as_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f32 +[`Duration::from_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f64 +[`Duration::from_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f32 +[`Duration::mul_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f64 +[`Duration::mul_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f32 +[`Duration::div_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f64 +[`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32 +[`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64 +[`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32 +[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr +[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr +[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init +[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref Version 1.57.0 (2021-12-02) ========================== From 3d2b8a29f937c7b7879b939cb3c59ae0e61dcfbb Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 4 Jan 2022 17:03:05 -0800 Subject: [PATCH 05/21] Apply suggestions from code review Co-authored-by: Josh Triplett Co-authored-by: Alexander Ronald Altman --- RELEASES.md | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 7152338387c55..96e5ab645c4c6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,7 +4,7 @@ Version 1.58.0 (2022-01-13) Language -------- -- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] +- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] This works in all macros accepting format strings. Support for this in `panic!` (`panic!("{ident}")`) requires the 2021 edition; panic invocations in previous editions that appear to be trying to use this will result in a warning lint about not having the intended effect. - [`*const T` pointers can now be dereferenced in const contexts.][89551] - [The rules for when a generic struct implements `Unsize` have been relaxed.][90417] @@ -12,12 +12,12 @@ Compiler -------- - [Add LLVM CFI support to the Rust compiler][89652] -- [Stabilize -Z strip as -C strip][90058] +- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. - [Add support for LLVM coverage mapping format versions 5 and 6][91207] - [Emit LLVM optimization remarks when enabled with `-Cremark`][90833] - [Update the minimum external LLVM to 12][90175] - [Add `x86_64-unknown-none` at Tier 3*][89062] -- [Build musl dist artifacts with debuginfo enabled][90733] +- [Build musl dist artifacts with debuginfo enabled][90733]. When building release binaries using musl, you may want to use the newly stabilized strip option to remove these debug symbols, reducing the size of your binaries. - [Don't abort compilation after giving a lint error][87337] - [Error messages point at the source of trait bound obligations in more places][89580] @@ -27,21 +27,12 @@ Compiler Libraries --------- -- [Add #[must_use] to Rc::downgrade][89833] -- [Add #[must_use] to expensive computations][89835] -- [Add #[must_use] to mem/ptr functions][89839] -- [Add #[must_use] to remaining core functions][89897] -- [Add #[must_use] to remaining alloc functions][89899] -- [Add #[must_use] to len and is_empty][89786] -- [Add #[must_use] to thread::Builder][89789] -- [Add #[must_use] to alloc functions that would leak memory][90427] -- [Add #[must_use] to remaining std functions (A-N)][90430] -- [Add #[must_use] to remaining std functions (O-Z)][90431] +- [All remaining functions in the standard library have `#[must_use]` annotations where appropriate][89692], producing a warning when ignoring their return value. This helps catch mistakes such as expecting a function to mutate a value in place rather than return a new value. - [Paths are automatically canonicalized on Windows for operations that support it][89174] -- [Re-enable `copy[_nonoverlapping]()` debug-checks][90041] +- [Re-enable debug checks for `copy` and `copy_nonoverlapping`][90041] - [Implement `RefUnwindSafe` for `Rc`][87467] - [Make RSplit: Clone not require T: Clone][90117] -- [Implement `Termination` for `Result`][88601] +- [Implement `Termination` for `Result`][88601]. This allows writing `fn main() -> Result`, for a program whose successful exits never involve returning from `main` (for instance, a program that calls `exit`, or that uses `exec` to run another program). Stabilized APIs --------------- @@ -95,7 +86,7 @@ Compatibility Notes - Windows: [`std::process::Command` will no longer search the current directory for executables.][87704] - [All proc-macro backward-compatibility lints are now deny-by-default.][88041] - [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297] -- [Refactor weak symbols in std::sys::unix][90846] +- [Refactor weak symbols in std::sys::unix][90846]. This optimizes accesses to glibc functions, by avoiding the use of dlopen. This does not increase the [minimum expected version of glibc](https://doc.rust-lang.org/nightly/rustc/platform-support.html). However, software distributions that use symbol versions to detect library dependencies, and which take weak symbols into account in that analysis, may detect rust binaries as requiring newer versions of glibc. - [rustdoc now rejects some unexpected semicolons in doctests][91026] Internal Changes @@ -105,11 +96,11 @@ These changes provide no direct user facing benefits, but represent significant improvements to the internals and overall performance of rustc and related tools. -- [Try all stable method candidates first before trying unstable ones][90329] +- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library. - [Implement coherence checks for negative trait impls][90104] - [Add rustc lint, warning when iterating over hashmaps][89558] - [Optimize live point computation][90491] -- [Enable verification for 1/32th of queries loaded from disk][90361] +- [Enable verification for 1/32nd of queries loaded from disk][90361] - [Implement version of normalize_erasing_regions that allows for normalization failure][91255] [87337]: https://github.com/rust-lang/rust/pull/87337/ From c3a99d8fd623f7b466289c2bbd6a35a0c93b03a0 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 5 Jan 2022 01:08:56 +0000 Subject: [PATCH 06/21] Move #90329 to compatibility notes --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 96e5ab645c4c6..987431a2dbfd9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -83,6 +83,7 @@ Rustdoc Compatibility Notes ------------------- +- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library. - Windows: [`std::process::Command` will no longer search the current directory for executables.][87704] - [All proc-macro backward-compatibility lints are now deny-by-default.][88041] - [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297] @@ -96,7 +97,6 @@ These changes provide no direct user facing benefits, but represent significant improvements to the internals and overall performance of rustc and related tools. -- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library. - [Implement coherence checks for negative trait impls][90104] - [Add rustc lint, warning when iterating over hashmaps][89558] - [Optimize live point computation][90491] From f3fe91278c340590b462d9c7097e7e64620225b7 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sun, 2 Jan 2022 09:46:59 -0500 Subject: [PATCH 07/21] Switch to es6 for eslint Also update Node to v16.9.0, es-check to 6.1.1, and eslint to 8.6.0. --- src/ci/docker/host-x86_64/mingw-check/Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index c27e42a266220..66333e2b99214 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -17,12 +17,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ mingw-w64 -RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ -ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" +RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ +ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}" # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. -RUN npm install es-check@5.2.3 -g -RUN npm install eslint@7.20.0 -g +RUN npm install es-check@6.1.1 -g +RUN npm install eslint@8.6.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -40,5 +40,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ # Runs checks to ensure that there are no ES5 issues in our JS code. - es-check es5 ../src/librustdoc/html/static/js/*.js && \ + es-check es6 ../src/librustdoc/html/static/js/*.js && \ eslint ../src/librustdoc/html/static/js/*.js From 8abb4bb698c9d74507adb9cd7b54a032f3c1b595 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sat, 1 Jan 2022 23:48:34 -0500 Subject: [PATCH 08/21] Move crate drop-down to search results page This reduces clutter on doc pages. --- src/librustdoc/html/static/css/rustdoc.css | 18 ++++++--- src/librustdoc/html/static/js/search.js | 39 +++++++++++--------- src/librustdoc/html/templates/page.html | 6 +-- src/test/rustdoc-gui/escape-key.goml | 2 +- src/test/rustdoc-gui/search-filter.goml | 4 +- src/test/rustdoc-gui/toggle-docs-mobile.goml | 6 +-- 6 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d82c65398b835..7c92156dec25c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -862,18 +862,24 @@ h2.small-section-header > .anchor { display: inline-flex; width: calc(100% - 63px); } +.search-results-title { + display: inline; +} +#search-settings { + font-size: 1.5rem; + font-weight: 500; + margin-bottom: 20px; +} #crate-search { min-width: 115px; margin-top: 5px; - padding: 6px; - padding-right: 19px; - flex: none; + margin-left: 0.2em; + padding-left: 0.3em; + padding-right: 23px; border: 0; - border-right: 0; - border-radius: 4px 0 0 4px; + border-radius: 4px; outline: none; cursor: pointer; - border-right: 1px solid; -moz-appearance: none; -webkit-appearance: none; /* Removes default arrow from firefox */ diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index cf320f7b4958a..e859431e1f189 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1085,7 +1085,7 @@ window.initSearch = function(rawSearchIndex) { return ""; } - function showResults(results, go_to_first) { + function showResults(results, go_to_first, filterCrates) { var search = searchState.outputElement(); if (go_to_first || (results.others.length === 1 && getSettingValue("go-to-only-result") === "true" @@ -1126,9 +1126,16 @@ window.initSearch = function(rawSearchIndex) { } } - var output = "

Results for " + escape(query.query) + + let crates = ``; + var output = `
+

Results for ${escape(query.query)} ` + (query.type ? " (type: " + escape(query.type) + ")" : "") + "

" + - "
" + + ` in ${crates} ` + + `
` + makeTabHeader(0, "In Names", ret_others[1]) + makeTabHeader(1, "In Parameters", ret_in_args[1]) + makeTabHeader(2, "In Return Types", ret_returned[1]) + @@ -1141,6 +1148,7 @@ window.initSearch = function(rawSearchIndex) { resultsElem.appendChild(ret_returned[0]); search.innerHTML = output; + document.getElementById("crate-search").addEventListener("input", updateCrate); search.appendChild(resultsElem); // Reset focused elements. searchState.focusedByTab = [null, null, null]; @@ -1316,7 +1324,8 @@ window.initSearch = function(rawSearchIndex) { } var filterCrates = getFilterCrates(); - showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]); + showResults(execSearch(query, searchWords, filterCrates), + params["go_to_first"], filterCrates); } function buildIndex(rawSearchIndex) { @@ -1552,19 +1561,6 @@ window.initSearch = function(rawSearchIndex) { } }); - - var selectCrate = document.getElementById("crate-search"); - if (selectCrate) { - selectCrate.onchange = function() { - updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value); - // In case you "cut" the entry from the search input, then change the crate filter - // before paste back the previous search, you get the old search results without - // the filter. To prevent this, we need to remove the previous results. - currentResults = null; - search(undefined, true); - }; - } - // Push and pop states are used to add search results to the browser // history. if (searchState.browserSupportsHistoryApi()) { @@ -1616,6 +1612,15 @@ window.initSearch = function(rawSearchIndex) { }; } + function updateCrate(ev) { + updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value); + // In case you "cut" the entry from the search input, then change the crate filter + // before paste back the previous search, you get the old search results without + // the filter. To prevent this, we need to remove the previous results. + currentResults = null; + search(undefined, true); + } + searchWords = buildIndex(rawSearchIndex); registerSearchEvents(); // If there's a search term in the URL, execute the search now. diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 00b46b1ba918b..5cade1b1a4c73 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -105,11 +105,7 @@
{#- -#}
{#- -#}
{#- -#} -
{%- if layout.generate_search_filter -%} - {#- -#} - {%- endif -%} +
h1" // The search element is empty before the first search +wait-for: "#search h1" // The search element is empty before the first search assert-attribute: ("#search", {"class": "content"}) assert-attribute: ("#main-content", {"class": "content hidden"}) press-key: "Escape" diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index 7a8f8ca5311ad..e5cdf3ea7a169 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -5,14 +5,12 @@ write: (".search-input", "test") wait-for: "#titles" assert-text: ("#results .externcrate", "test_docs") -goto: file://|DOC_PATH|/test_docs/index.html +wait-for: "#crate-search" // We now want to change the crate filter. click: "#crate-search" // We select "lib2" option then press enter to change the filter. press-key: "ArrowDown" press-key: "Enter" -// We now make the search again. -write: (".search-input", "test") // Waiting for the search results to appear... wait-for: "#titles" // We check that there is no more "test_docs" appearing. diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index b370dd012fae1..6e0ad8e0fa7fb 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -1,12 +1,12 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html size: (433, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 280) // This is the position of the top doc comment toggle +click: (4, 240) // This is the position of the top doc comment toggle assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 280) +click: (4, 240) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 280) +click: (3, 240) assert-attribute: (".top-doc", {"open": ""}) // Assert the position of the toggle on the top doc block. From 486585242e57ba184f26547c52c428dbf135e762 Mon Sep 17 00:00:00 2001 From: inquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com> Date: Sun, 2 Jan 2022 21:11:16 -0800 Subject: [PATCH 09/21] Do not resolve blocks in foreign functions --- compiler/rustc_resolve/src/late.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5098cef11e83b..b3ee042fd0a76 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -520,9 +520,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) { let rib_kind = match fn_kind { - // Bail if there's no body. - FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp), - FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind, + // Bail if the function is foreign, and thus cannot validly have + // a body, or if there's no body for some other reason. + FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => { + // We don't need to deal with patterns in parameters, because + // they are not possible for foreign or bodiless functions. + self.visit_fn_header(&sig.header); + visit::walk_fn_decl(self, &sig.decl); + return; + } + FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, FnKind::Closure(..) => ClosureOrAsyncRibKind, }; From 42de973099a14c0efa9059b1bf820d8a9c61f326 Mon Sep 17 00:00:00 2001 From: inquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com> Date: Sun, 2 Jan 2022 22:23:31 -0800 Subject: [PATCH 10/21] Add regression test --- .../issue-91370-foreign-fn-block-impl.rs | 12 +++++++++++ .../issue-91370-foreign-fn-block-impl.stderr | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs create mode 100644 src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs new file mode 100644 index 0000000000000..2ac3ca29355d8 --- /dev/null +++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs @@ -0,0 +1,12 @@ +// Regression test for issue #91370. + +extern { + //~^ `extern` blocks define existing foreign functions + fn f() { + //~^ incorrect function inside `extern` block + //~| cannot have a body + impl Copy for u8 {} + } +} + +fn main() {} diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr new file mode 100644 index 0000000000000..4fb2f8c659c53 --- /dev/null +++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr @@ -0,0 +1,21 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | +LL | fn f() { + | ________^___- + | | | + | | cannot have a body +LL | | +LL | | +LL | | impl Copy for u8 {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + From dc7e7711555a0021f5a3592de84bb2b650e42e19 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 5 Jan 2022 13:56:45 +0800 Subject: [PATCH 11/21] expand: Rename some `AstFragment`s to match AST structures --- compiler/rustc_expand/src/expand.rs | 36 +++++++++++------------ compiler/rustc_expand/src/placeholders.rs | 6 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7f49f80a8439b..08c30f5b396a1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -178,10 +178,10 @@ ast_fragments! { Arms(SmallVec<[ast::Arm; 1]>) { "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; } - Fields(SmallVec<[ast::ExprField; 1]>) { + ExprFields(SmallVec<[ast::ExprField; 1]>) { "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; } - FieldPats(SmallVec<[ast::PatField; 1]>) { + PatFields(SmallVec<[ast::PatField; 1]>) { "field pattern"; many fn flat_map_pat_field; fn visit_pat_field(); @@ -196,7 +196,7 @@ ast_fragments! { Params(SmallVec<[ast::Param; 1]>) { "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; } - StructFields(SmallVec<[ast::FieldDef; 1]>) { + FieldDefs(SmallVec<[ast::FieldDef; 1]>) { "field"; many fn flat_map_field_def; fn visit_field_def(); @@ -231,11 +231,11 @@ impl AstFragmentKind { | AstFragmentKind::ForeignItems | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true }, AstFragmentKind::Arms - | AstFragmentKind::Fields - | AstFragmentKind::FieldPats + | AstFragmentKind::ExprFields + | AstFragmentKind::PatFields | AstFragmentKind::GenericParams | AstFragmentKind::Params - | AstFragmentKind::StructFields + | AstFragmentKind::FieldDefs | AstFragmentKind::Variants => SupportsMacroExpansion::No, } } @@ -249,11 +249,11 @@ impl AstFragmentKind { AstFragmentKind::Arms => { AstFragment::Arms(items.map(Annotatable::expect_arm).collect()) } - AstFragmentKind::Fields => { - AstFragment::Fields(items.map(Annotatable::expect_expr_field).collect()) + AstFragmentKind::ExprFields => { + AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect()) } - AstFragmentKind::FieldPats => { - AstFragment::FieldPats(items.map(Annotatable::expect_pat_field).collect()) + AstFragmentKind::PatFields => { + AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect()) } AstFragmentKind::GenericParams => { AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect()) @@ -261,8 +261,8 @@ impl AstFragmentKind { AstFragmentKind::Params => { AstFragment::Params(items.map(Annotatable::expect_param).collect()) } - AstFragmentKind::StructFields => { - AstFragment::StructFields(items.map(Annotatable::expect_field_def).collect()) + AstFragmentKind::FieldDefs => { + AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect()) } AstFragmentKind::Variants => { AstFragment::Variants(items.map(Annotatable::expect_variant).collect()) @@ -915,11 +915,11 @@ pub fn parse_ast_fragment<'a>( )?), AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?), AstFragmentKind::Arms - | AstFragmentKind::Fields - | AstFragmentKind::FieldPats + | AstFragmentKind::ExprFields + | AstFragmentKind::PatFields | AstFragmentKind::GenericParams | AstFragmentKind::Params - | AstFragmentKind::StructFields + | AstFragmentKind::FieldDefs | AstFragmentKind::Variants => panic!("unexpected AST fragment kind"), }) } @@ -1231,7 +1231,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr(&mut field) { return self - .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields) + .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::ExprFields) .make_expr_fields(); } @@ -1243,7 +1243,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr(&mut fp) { return self - .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats) + .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::PatFields) .make_pat_fields(); } @@ -1267,7 +1267,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr(&mut sf) { return self - .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields) + .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::FieldDefs) .make_field_defs(); } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 825af9a7b2bd9..af593e92634b0 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -123,7 +123,7 @@ pub fn placeholder( span, is_placeholder: true, }]), - AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField { + AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField { attrs: Default::default(), expr: expr_placeholder(), id, @@ -132,7 +132,7 @@ pub fn placeholder( span, is_placeholder: true, }]), - AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField { + AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField { attrs: Default::default(), id, ident, @@ -159,7 +159,7 @@ pub fn placeholder( ty: ty(), is_placeholder: true, }]), - AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef { + AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef { attrs: Default::default(), id, ident: None, From 4fd23350cdd871196d2fd925e3f8d1e0df9f1c10 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 5 Jan 2022 14:10:07 +0800 Subject: [PATCH 12/21] expand: Remove some unnecessary `self` mutability --- compiler/rustc_expand/src/config.rs | 17 +++++++---------- compiler/rustc_expand/src/expand.rs | 6 +++--- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index db0dea4870876..e0bdeb30dc84b 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -238,7 +238,7 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - pub fn configure(&mut self, mut node: T) -> Option { + pub fn configure(&self, mut node: T) -> Option { self.process_cfg_attrs(&mut node); if self.in_cfg(node.attrs()) { self.try_configure_tokens(&mut node); @@ -248,7 +248,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn try_configure_tokens(&mut self, node: &mut T) { + fn try_configure_tokens(&self, node: &mut T) { if self.config_tokens { if let Some(Some(tokens)) = node.tokens_mut() { let attr_annotated_tokens = tokens.create_token_stream(); @@ -257,10 +257,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs( - &mut self, - mut attrs: Vec, - ) -> Option> { + fn configure_krate_attrs(&self, mut attrs: Vec) -> Option> { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); if self.in_cfg(&attrs) { Some(attrs) } else { None } } @@ -269,7 +266,7 @@ impl<'a> StripUnconfigured<'a> { /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method - fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { + fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool { stream.0.iter().all(|(tree, _spacing)| match tree { AttrAnnotatedTokenTree::Attributes(_) => false, @@ -325,7 +322,7 @@ impl<'a> StripUnconfigured<'a> { /// Gives compiler warnings if any `cfg_attr` does not contain any /// attributes and is in the original source code. Gives compiler errors if /// the syntax of any `cfg_attr` is incorrect. - fn process_cfg_attrs(&mut self, node: &mut T) { + fn process_cfg_attrs(&self, node: &mut T) { node.visit_attrs(|attrs| { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); }); @@ -338,7 +335,7 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { + fn process_cfg_attr(&self, attr: Attribute) -> Vec { if !attr.has_name(sym::cfg_attr) { return vec![attr]; } @@ -461,7 +458,7 @@ impl<'a> StripUnconfigured<'a> { } } - pub fn configure_expr(&mut self, expr: &mut P) { + pub fn configure_expr(&self, expr: &mut P) { for attr in expr.attrs.iter() { self.maybe_emit_expr_attr_err(attr); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 08c30f5b396a1..f8c4ddbff767d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1007,7 +1007,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { /// its position and derives following it. We have to collect the derives in order to resolve /// legacy derive helpers (helpers written before derives that introduce them). fn take_first_attr( - &mut self, + &self, item: &mut impl AstLike, ) -> Option<(ast::Attribute, usize, Vec)> { let mut attr = None; @@ -1040,7 +1040,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } fn take_stmt_bang( - &mut self, + &self, stmt: ast::Stmt, ) -> Result<(bool, MacCall, Vec), ast::Stmt> { match stmt.kind { @@ -1071,7 +1071,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } - fn configure(&mut self, node: T) -> Option { + fn configure(&self, node: T) -> Option { self.cfg.configure(node) } From 800ba8f8e862d72707200f77a51981de62f38b3a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 5 Jan 2022 14:15:44 +0800 Subject: [PATCH 13/21] expand: Refactor `InvocationCollector` visitor for better code reuse --- compiler/rustc_ast/src/ast_like.rs | 39 +- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_expand/src/expand.rs | 1181 ++++++++++++++++----------- compiler/rustc_expand/src/lib.rs | 2 + 4 files changed, 724 insertions(+), 500 deletions(-) diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs index b9c397974a163..9a24158ba35d9 100644 --- a/compiler/rustc_ast/src/ast_like.rs +++ b/compiler/rustc_ast/src/ast_like.rs @@ -6,12 +6,13 @@ use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt}; use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use super::{AttrVec, Attribute, Stmt, StmtKind}; -use std::fmt::Debug; +use std::fmt; +use std::marker::PhantomData; /// An `AstLike` represents an AST node (or some wrapper around /// and AST node) which stores some combination of attributes /// and tokens. -pub trait AstLike: Sized + Debug { +pub trait AstLike: Sized + fmt::Debug { /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not /// considered 'custom' attributes @@ -285,3 +286,37 @@ derive_has_attrs_no_tokens! { derive_has_tokens_no_attrs! { Ty, Block, AttrItem, Pat, Path, Visibility } + +/// A newtype around an `AstLike` node that implements `AstLike` itself. +pub struct AstLikeWrapper { + pub wrapped: Wrapped, + pub tag: PhantomData, +} + +impl AstLikeWrapper { + pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper { + AstLikeWrapper { wrapped, tag: Default::default() } + } +} + +impl fmt::Debug for AstLikeWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AstLikeWrapper") + .field("wrapped", &self.wrapped) + .field("tag", &self.tag) + .finish() + } +} + +impl AstLike for AstLikeWrapper { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.wrapped.attrs() + } + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + self.wrapped.visit_attrs(f) + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + self.wrapped.tokens_mut() + } +} diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index ff3b501a0bdc2..84fe9ad26720e 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -41,7 +41,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_like::AstLike; +pub use self::ast_like::{AstLike, AstLikeWrapper}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f8c4ddbff767d..4c50685d5f334 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,6 +1,5 @@ use crate::base::*; use crate::config::StripUnconfigured; -use crate::configure; use crate::hygiene::SyntaxContext; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -12,13 +11,12 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall}; +use rustc_ast::{AstLike, AstLikeWrapper, Block, Inline, ItemKind, MacArgs, MacCall}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; -use rustc_ast::{NodeId, PatKind, Path, StmtKind}; +use rustc_ast::{NodeId, Path, StmtKind}; use rustc_ast_pretty::pprust; use rustc_attr::is_builtin_attr; use rustc_data_structures::map_in_place::MapInPlace; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; @@ -34,7 +32,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::{FileName, LocalExpnId, Span}; use smallvec::SmallVec; -use std::ops::DerefMut; +use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; use std::{iter, mem}; @@ -109,6 +107,10 @@ macro_rules! ast_fragments { } })* + fn make_ast(self) -> T::OutputTy { + T::fragment_to_output(self) + } + pub fn mut_visit_with(&mut self, vis: &mut F) { match self { AstFragment::OptExpr(opt_expr) => { @@ -961,6 +963,568 @@ pub fn ensure_complete_parse<'a>( } } +/// Wraps a call to `noop_visit_*` / `noop_flat_map_*` +/// for an AST node that supports attributes +/// (see the `Annotatable` enum) +/// This method assigns a `NodeId`, and sets that `NodeId` +/// as our current 'lint node id'. If a macro call is found +/// inside this AST node, we will use this AST node's `NodeId` +/// to emit lints associated with that macro (allowing +/// `#[allow]` / `#[deny]` to be applied close to +/// the macro invocation). +/// +/// Do *not* call this for a macro AST node +/// (e.g. `ExprKind::MacCall`) - we cannot emit lints +/// at these AST nodes, since they are removed and +/// replaced with the result of macro expansion. +/// +/// All other `NodeId`s are assigned by `visit_id`. +/// * `self` is the 'self' parameter for the current method, +/// * `id` is a mutable reference to the `NodeId` field +/// of the current AST node. +/// * `closure` is a closure that executes the +/// `noop_visit_*` / `noop_flat_map_*` method +/// for the current AST node. +macro_rules! assign_id { + ($self:ident, $id:expr, $closure:expr) => {{ + let old_id = $self.cx.current_expansion.lint_node_id; + if $self.monotonic { + debug_assert_eq!(*$id, ast::DUMMY_NODE_ID); + let new_id = $self.cx.resolver.next_node_id(); + *$id = new_id; + $self.cx.current_expansion.lint_node_id = new_id; + } + let ret = ($closure)(); + $self.cx.current_expansion.lint_node_id = old_id; + ret + }}; +} + +enum AddSemicolon { + Yes, + No, +} + +/// A trait implemented for all `AstFragment` nodes and providing all pieces +/// of functionality used by `InvocationCollector`. +trait InvocationCollectorNode: AstLike { + type OutputTy = SmallVec<[Self; 1]>; + type AttrsTy: Deref = Vec; + const KIND: AstFragmentKind; + fn to_annotatable(self) -> Annotatable; + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; + fn id(&mut self) -> &mut NodeId; + fn noop_flat_map(self, _visitor: &mut V) -> Self::OutputTy { + unreachable!() + } + fn noop_visit(&mut self, _visitor: &mut V) { + unreachable!() + } + fn is_mac_call(&self) -> bool { + false + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + unreachable!() + } + fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {} + fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) { + } + fn wrap_flat_map_node_noop_flat_map( + node: Self, + collector: &mut InvocationCollector<'_, '_>, + noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, + ) -> Result { + Ok(noop_flat_map(node, collector)) + } +} + +impl InvocationCollectorNode for P { + const KIND: AstFragmentKind = AstFragmentKind::Items; + fn to_annotatable(self) -> Annotatable { + Annotatable::Item(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_items() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_item(self, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.kind, ast::ItemKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.into_inner(); + match node.kind { + ast::ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } + fn wrap_flat_map_node_noop_flat_map( + mut node: Self, + collector: &mut InvocationCollector<'_, '_>, + noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, + ) -> Result { + if !matches!(node.kind, ast::ItemKind::Mod(..)) { + return Ok(noop_flat_map(node, collector)); + } + + // Work around borrow checker not seeing through `P`'s deref. + let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs)); + let ast::ItemKind::Mod(_, mod_kind) = &mut node.kind else { + unreachable!() + }; + + let ecx = &mut collector.cx; + let (file_path, dir_path, dir_ownership) = match mod_kind { + ModKind::Loaded(_, inline, _) => { + // Inline `mod foo { ... }`, but we still need to push directories. + let (dir_path, dir_ownership) = mod_dir_path( + &ecx.sess, + ident, + &attrs, + &ecx.current_expansion.module, + ecx.current_expansion.dir_ownership, + *inline, + ); + node.attrs = attrs; + (None, dir_path, dir_ownership) + } + ModKind::Unloaded => { + // We have an outline `mod foo;` so we need to parse the file. + let old_attrs_len = attrs.len(); + let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } = + parse_external_mod( + &ecx.sess, + ident, + span, + &ecx.current_expansion.module, + ecx.current_expansion.dir_ownership, + &mut attrs, + ); + + if let Some(extern_mod_loaded) = ecx.extern_mod_loaded { + (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); + } + + *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); + node.attrs = attrs; + if node.attrs.len() > old_attrs_len { + // If we loaded an out-of-line module and added some inner attributes, + // then we need to re-configure it and re-collect attributes for + // resolution and expansion. + return Err(node); + } + (Some(file_path), dir_path, dir_ownership) + } + }; + + // Set the module info before we flat map. + let mut module = ecx.current_expansion.module.with_dir_path(dir_path); + module.mod_path.push(ident); + if let Some(file_path) = file_path { + module.file_path_stack.push(file_path); + } + + let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module)); + let orig_dir_ownership = + mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership); + + let res = Ok(noop_flat_map(node, collector)); + + collector.cx.current_expansion.dir_ownership = orig_dir_ownership; + collector.cx.current_expansion.module = orig_module; + res + } +} + +struct TraitItemTag; +impl InvocationCollectorNode for AstLikeWrapper, TraitItemTag> { + type OutputTy = SmallVec<[P; 1]>; + const KIND: AstFragmentKind = AstFragmentKind::TraitItems; + fn to_annotatable(self) -> Annotatable { + Annotatable::TraitItem(self.wrapped) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_trait_items() + } + fn id(&mut self) -> &mut NodeId { + &mut self.wrapped.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_assoc_item(self.wrapped, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, ast::AssocItemKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let item = self.wrapped.into_inner(); + match item.kind { + ast::AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + +struct ImplItemTag; +impl InvocationCollectorNode for AstLikeWrapper, ImplItemTag> { + type OutputTy = SmallVec<[P; 1]>; + const KIND: AstFragmentKind = AstFragmentKind::ImplItems; + fn to_annotatable(self) -> Annotatable { + Annotatable::ImplItem(self.wrapped) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_impl_items() + } + fn id(&mut self) -> &mut NodeId { + &mut self.wrapped.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_assoc_item(self.wrapped, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, ast::AssocItemKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let item = self.wrapped.into_inner(); + match item.kind { + ast::AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + +impl InvocationCollectorNode for P { + const KIND: AstFragmentKind = AstFragmentKind::ForeignItems; + fn to_annotatable(self) -> Annotatable { + Annotatable::ForeignItem(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_foreign_items() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_foreign_item(self, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.kind, ast::ForeignItemKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.into_inner(); + match node.kind { + ast::ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + +impl InvocationCollectorNode for ast::Variant { + const KIND: AstFragmentKind = AstFragmentKind::Variants; + fn to_annotatable(self) -> Annotatable { + Annotatable::Variant(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_variants() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_variant(self, visitor) + } +} + +impl InvocationCollectorNode for ast::FieldDef { + const KIND: AstFragmentKind = AstFragmentKind::FieldDefs; + fn to_annotatable(self) -> Annotatable { + Annotatable::FieldDef(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_field_defs() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_field_def(self, visitor) + } +} + +impl InvocationCollectorNode for ast::PatField { + const KIND: AstFragmentKind = AstFragmentKind::PatFields; + fn to_annotatable(self) -> Annotatable { + Annotatable::PatField(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_pat_fields() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_pat_field(self, visitor) + } +} + +impl InvocationCollectorNode for ast::ExprField { + const KIND: AstFragmentKind = AstFragmentKind::ExprFields; + fn to_annotatable(self) -> Annotatable { + Annotatable::ExprField(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_expr_fields() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_expr_field(self, visitor) + } +} + +impl InvocationCollectorNode for ast::Param { + const KIND: AstFragmentKind = AstFragmentKind::Params; + fn to_annotatable(self) -> Annotatable { + Annotatable::Param(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_params() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_param(self, visitor) + } +} + +impl InvocationCollectorNode for ast::GenericParam { + const KIND: AstFragmentKind = AstFragmentKind::GenericParams; + fn to_annotatable(self) -> Annotatable { + Annotatable::GenericParam(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_generic_params() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_generic_param(self, visitor) + } +} + +impl InvocationCollectorNode for ast::Arm { + const KIND: AstFragmentKind = AstFragmentKind::Arms; + fn to_annotatable(self) -> Annotatable { + Annotatable::Arm(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_arms() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_arm(self, visitor) + } +} + +impl InvocationCollectorNode for ast::Stmt { + type AttrsTy = ast::AttrVec; + const KIND: AstFragmentKind = AstFragmentKind::Stmts; + fn to_annotatable(self) -> Annotatable { + Annotatable::Stmt(P(self)) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_stmts() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { + noop_flat_map_stmt(self, visitor) + } + fn is_mac_call(&self) -> bool { + match &self.kind { + StmtKind::MacCall(..) => true, + StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)), + StmtKind::Semi(expr) => matches!(expr.kind, ast::ExprKind::MacCall(..)), + StmtKind::Expr(..) => unreachable!(), + StmtKind::Local(..) | StmtKind::Empty => false, + } + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + // We pull macro invocations (both attributes and fn-like macro calls) out of their + // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. + let (add_semicolon, mac, attrs) = match self.kind { + StmtKind::MacCall(mac) => { + let MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); + (style == MacStmtStyle::Semicolon, mac, attrs) + } + StmtKind::Item(item) => match item.into_inner() { + ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { + (mac.args.need_semicolon(), mac, attrs.into()) + } + _ => unreachable!(), + }, + StmtKind::Semi(expr) => match expr.into_inner() { + ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { + (mac.args.need_semicolon(), mac, attrs) + } + _ => unreachable!(), + }, + _ => unreachable!(), + }; + (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) + } + fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) { + // If this is a macro invocation with a semicolon, then apply that + // semicolon to the final statement produced by expansion. + if matches!(add_semicolon, AddSemicolon::Yes) { + if let Some(stmt) = stmts.pop() { + stmts.push(stmt.add_trailing_semicolon()); + } + } + } +} + +impl InvocationCollectorNode for ast::Crate { + type OutputTy = ast::Crate; + const KIND: AstFragmentKind = AstFragmentKind::Crate; + fn to_annotatable(self) -> Annotatable { + Annotatable::Crate(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_crate() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_visit(&mut self, visitor: &mut V) { + noop_visit_crate(self, visitor) + } +} + +impl InvocationCollectorNode for P { + type OutputTy = P; + const KIND: AstFragmentKind = AstFragmentKind::Ty; + fn to_annotatable(self) -> Annotatable { + unreachable!() + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_ty() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_visit(&mut self, visitor: &mut V) { + noop_visit_ty(self, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.kind, ast::TyKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.into_inner(); + match node.kind { + ast::TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + _ => unreachable!(), + } + } +} + +impl InvocationCollectorNode for P { + type OutputTy = P; + const KIND: AstFragmentKind = AstFragmentKind::Pat; + fn to_annotatable(self) -> Annotatable { + unreachable!() + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_pat() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_visit(&mut self, visitor: &mut V) { + noop_visit_pat(self, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.kind, ast::PatKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.into_inner(); + match node.kind { + ast::PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + _ => unreachable!(), + } + } +} + +impl InvocationCollectorNode for P { + type OutputTy = P; + type AttrsTy = ast::AttrVec; + const KIND: AstFragmentKind = AstFragmentKind::Expr; + fn to_annotatable(self) -> Annotatable { + Annotatable::Expr(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_expr() + } + fn id(&mut self) -> &mut NodeId { + &mut self.id + } + fn noop_visit(&mut self, visitor: &mut V) { + noop_visit_expr(self, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.kind, ast::ExprKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.into_inner(); + match node.kind { + ast::ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + +struct OptExprTag; +impl InvocationCollectorNode for AstLikeWrapper, OptExprTag> { + type OutputTy = Option>; + type AttrsTy = ast::AttrVec; + const KIND: AstFragmentKind = AstFragmentKind::OptExpr; + fn to_annotatable(self) -> Annotatable { + Annotatable::Expr(self.wrapped) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_opt_expr() + } + fn id(&mut self) -> &mut NodeId { + &mut self.wrapped.id + } + fn noop_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { + noop_visit_expr(&mut self.wrapped, visitor); + Some(self.wrapped) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) + } + fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { + let node = self.wrapped.into_inner(); + match node.kind { + ast::ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } + fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) { + cfg.maybe_emit_expr_attr_err(&attr); + } +} + struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, @@ -1039,39 +1603,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr } - fn take_stmt_bang( - &self, - stmt: ast::Stmt, - ) -> Result<(bool, MacCall, Vec), ast::Stmt> { - match stmt.kind { - StmtKind::MacCall(mac) => { - let MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); - Ok((style == MacStmtStyle::Semicolon, mac, attrs.into())) - } - StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => { - match item.into_inner() { - ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs)) - } - _ => unreachable!(), - } - } - StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => { - match expr.into_inner() { - ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { - Ok((mac.args.need_semicolon(), mac, attrs.into())) - } - _ => unreachable!(), - } - } - StmtKind::Local(..) | StmtKind::Empty | StmtKind::Item(..) | StmtKind::Semi(..) => { - Err(stmt) - } - StmtKind::Expr(..) => unreachable!(), - } - } - - fn configure(&self, node: T) -> Option { + fn configure(&mut self, node: T) -> Option { self.cfg.configure(node) } @@ -1120,507 +1652,162 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } } -} -/// Wraps a call to `noop_visit_*` / `noop_flat_map_*` -/// for an AST node that supports attributes -/// (see the `Annotatable` enum) -/// This method assigns a `NodeId`, and sets that `NodeId` -/// as our current 'lint node id'. If a macro call is found -/// inside this AST node, we will use this AST node's `NodeId` -/// to emit lints associated with that macro (allowing -/// `#[allow]` / `#[deny]` to be applied close to -/// the macro invocation). -/// -/// Do *not* call this for a macro AST node -/// (e.g. `ExprKind::MacCall`) - we cannot emit lints -/// at these AST nodes, since they are removed and -/// replaced with the result of macro expansion. -/// -/// All other `NodeId`s are assigned by `visit_id`. -/// * `self` is the 'self' parameter for the current method, -/// * `id` is a mutable reference to the `NodeId` field -/// of the current AST node. -/// * `closure` is a closure that executes the -/// `noop_visit_*` / `noop_flat_map_*` method -/// for the current AST node. -macro_rules! assign_id { - ($self:ident, $id:expr, $closure:expr) => {{ - let old_id = $self.cx.current_expansion.lint_node_id; - if $self.monotonic { - debug_assert_eq!(*$id, ast::DUMMY_NODE_ID); - let new_id = $self.cx.resolver.next_node_id(); - *$id = new_id; - $self.cx.current_expansion.lint_node_id = new_id; + fn flat_map_node>( + &mut self, + node: Node, + ) -> Node::OutputTy { + let mut node = configure!(self, node); + + if let Some(attr) = self.take_first_attr(&mut node) { + Node::pre_flat_map_node_collect_attr(&self.cfg, &attr.0); + self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::() + } else if node.is_mac_call() { + let (mac, attrs, add_semicolon) = node.take_mac_call(); + self.check_attributes(&attrs, &mac); + let mut res = self.collect_bang(mac, Node::KIND).make_ast::(); + Node::post_flat_map_node_collect_bang(&mut res, add_semicolon); + res + } else { + match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { + assign_id!(this, node.id(), || node.noop_flat_map(this)) + }) { + Ok(output) => output, + Err(node) => self.flat_map_node(node), + } } - let ret = ($closure)(); - $self.cx.current_expansion.lint_node_id = old_id; - ret - }}; + } + + fn visit_node + DummyAstNode>( + &mut self, + node: &mut Node, + ) { + if let Some(attr) = self.take_first_attr(node) { + visit_clobber(node, |node| { + self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::() + }) + } else if node.is_mac_call() { + visit_clobber(node, |node| { + // Do not clobber unless it's actually a macro (uncommon case). + let (mac, attrs, _) = node.take_mac_call(); + self.check_attributes(&attrs, &mac); + self.collect_bang(mac, Node::KIND).make_ast::() + }) + } else { + assign_id!(self, node.id(), || node.noop_visit(self)) + } + } } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { - fn visit_crate(&mut self, krate: &mut ast::Crate) { - visit_clobber(krate, |krate| { - let span = krate.span; - let mut krate = match self.configure(krate) { - Some(krate) => krate, - None => { - return ast::Crate { - attrs: Vec::new(), - items: Vec::new(), - span, - id: self.cx.resolver.next_node_id(), - is_placeholder: false, - }; - } - }; - - if let Some(attr) = self.take_first_attr(&mut krate) { - return self - .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate) - .make_crate(); - } - - assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self)); - krate - }) + fn flat_map_item(&mut self, node: P) -> SmallVec<[P; 1]> { + self.flat_map_node(node) } - fn visit_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr); - visit_clobber(expr.deref_mut(), |mut expr| { - if let Some(attr) = self.take_first_attr(&mut expr) { - // Collect the invoc regardless of whether or not attributes are permitted here - // expansion will eat the attribute so it won't error later. - self.cfg.maybe_emit_expr_attr_err(&attr.0); - - // AstFragmentKind::Expr requires the macro to emit an expression. - return self - .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr) - .make_expr() - .into_inner(); - } - - if let ast::ExprKind::MacCall(mac) = expr.kind { - self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner() - } else { - assign_id!(self, &mut expr.id, || { - ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); - }); - expr - } - }); + fn flat_map_trait_item(&mut self, node: P) -> SmallVec<[P; 1]> { + self.flat_map_node(AstLikeWrapper::new(node, TraitItemTag)) } - fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { - let mut arm = configure!(self, arm); - - if let Some(attr) = self.take_first_attr(&mut arm) { - return self - .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms) - .make_arms(); - } - - assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self)) + fn flat_map_impl_item(&mut self, node: P) -> SmallVec<[P; 1]> { + self.flat_map_node(AstLikeWrapper::new(node, ImplItemTag)) } - fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { - let mut field = configure!(self, field); - - if let Some(attr) = self.take_first_attr(&mut field) { - return self - .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::ExprFields) - .make_expr_fields(); - } - - assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self)) + fn flat_map_foreign_item( + &mut self, + node: P, + ) -> SmallVec<[P; 1]> { + self.flat_map_node(node) } - fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { - let mut fp = configure!(self, fp); - - if let Some(attr) = self.take_first_attr(&mut fp) { - return self - .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::PatFields) - .make_pat_fields(); - } - - assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self)) + fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> { + self.flat_map_node(node) } - fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { - let mut p = configure!(self, p); - - if let Some(attr) = self.take_first_attr(&mut p) { - return self - .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params) - .make_params(); - } - - assign_id!(self, &mut p.id, || noop_flat_map_param(p, self)) + fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { + self.flat_map_node(node) } - fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { - let mut sf = configure!(self, sf); - - if let Some(attr) = self.take_first_attr(&mut sf) { - return self - .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::FieldDefs) - .make_field_defs(); - } - - assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self)) + fn flat_map_pat_field(&mut self, node: ast::PatField) -> SmallVec<[ast::PatField; 1]> { + self.flat_map_node(node) } - fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { - let mut variant = configure!(self, variant); - - if let Some(attr) = self.take_first_attr(&mut variant) { - return self - .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants) - .make_variants(); - } - - assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self)) + fn flat_map_expr_field(&mut self, node: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { + self.flat_map_node(node) } - fn filter_map_expr(&mut self, expr: P) -> Option> { - let expr = configure!(self, expr); - expr.filter_map(|mut expr| { - if let Some(attr) = self.take_first_attr(&mut expr) { - self.cfg.maybe_emit_expr_attr_err(&attr.0); - - return self - .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) - .make_opt_expr() - .map(|expr| expr.into_inner()); - } - - if let ast::ExprKind::MacCall(mac) = expr.kind { - self.check_attributes(&expr.attrs, &mac); - self.collect_bang(mac, AstFragmentKind::OptExpr) - .make_opt_expr() - .map(|expr| expr.into_inner()) - } else { - assign_id!(self, &mut expr.id, || { - Some({ - noop_visit_expr(&mut expr, self); - expr - }) - }) - } - }) + fn flat_map_param(&mut self, node: ast::Param) -> SmallVec<[ast::Param; 1]> { + self.flat_map_node(node) } - fn visit_pat(&mut self, pat: &mut P) { - match pat.kind { - PatKind::MacCall(_) => {} - _ => return noop_visit_pat(pat, self), - } - - visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { - PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(), - _ => unreachable!(), - }); + fn flat_map_generic_param( + &mut self, + node: ast::GenericParam, + ) -> SmallVec<[ast::GenericParam; 1]> { + self.flat_map_node(node) } - fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - let mut stmt = configure!(self, stmt); + fn flat_map_arm(&mut self, node: ast::Arm) -> SmallVec<[ast::Arm; 1]> { + self.flat_map_node(node) + } - // We pull macro invocations (both attributes and fn-like macro calls) out of their - // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. + fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { // FIXME: invocations in semicolon-less expressions positions are expanded as expressions, // changing that requires some compatibility measures. - let mut stmt = if !stmt.is_expr() { - if let Some(attr) = self.take_first_attr(&mut stmt) { - return self - .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts) - .make_stmts(); - } - - match self.take_stmt_bang(stmt) { - Ok((add_semicolon, mac, attrs)) => { - self.check_attributes(&attrs, &mac); - let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts(); - - // If this is a macro invocation with a semicolon, then apply that - // semicolon to the final statement produced by expansion. - if add_semicolon { - if let Some(stmt) = stmts.pop() { - stmts.push(stmt.add_trailing_semicolon()); - } - } - - return stmts; + if node.is_expr() { + // The only way that we can end up with a `MacCall` expression statement, + // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the + // traiing expression in a block (e.g. `fn foo() { my_macro!() }`). + // Record this information, so that we can report a more specific + // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed. + // See #78991 for an investigation of treating macros in this position + // as statements, rather than expressions, during parsing. + let mut node = configure!(self, node); + return match &node.kind { + StmtKind::Expr(expr) + if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) => + { + self.cx.current_expansion.is_trailing_mac = true; + // Don't use `assign_id` for this statement - it may get removed + // entirely due to a `#[cfg]` on the contained expression + let res = noop_flat_map_stmt(node, self); + self.cx.current_expansion.is_trailing_mac = false; + res } - Err(stmt) => stmt, - } - } else { - stmt - }; - - // The only way that we can end up with a `MacCall` expression statement, - // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the - // traiing expression in a block (e.g. `fn foo() { my_macro!() }`). - // Record this information, so that we can report a more specific - // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed. - // See #78991 for an investigation of treating macros in this position - // as statements, rather than expressions, during parsing. - let res = match &stmt.kind { - StmtKind::Expr(expr) - if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) => - { - self.cx.current_expansion.is_trailing_mac = true; - // Don't use `assign_id` for this statement - it may get removed - // entirely due to a `#[cfg]` on the contained expression - noop_flat_map_stmt(stmt, self) - } - _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)), - }; - self.cx.current_expansion.is_trailing_mac = false; - res - } - - fn visit_block(&mut self, block: &mut P) { - let orig_dir_ownership = mem::replace( - &mut self.cx.current_expansion.dir_ownership, - DirOwnership::UnownedViaBlock, - ); - noop_visit_block(block, self); - self.cx.current_expansion.dir_ownership = orig_dir_ownership; - } - - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items) - .make_items(); + _ => assign_id!(self, &mut node.id, || noop_flat_map_stmt(node, self)), + }; } - let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. - let ident = item.ident; - let span = item.span; - - match item.kind { - ast::ItemKind::MacCall(ref mac) => { - self.check_attributes(&attrs, &mac); - item.attrs = attrs; - item.and_then(|item| match item.kind { - ItemKind::MacCall(mac) => { - self.collect_bang(mac, AstFragmentKind::Items).make_items() - } - _ => unreachable!(), - }) - } - ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => { - let (file_path, dir_path, dir_ownership) = match mod_kind { - ModKind::Loaded(_, inline, _) => { - // Inline `mod foo { ... }`, but we still need to push directories. - let (dir_path, dir_ownership) = mod_dir_path( - &self.cx.sess, - ident, - &attrs, - &self.cx.current_expansion.module, - self.cx.current_expansion.dir_ownership, - *inline, - ); - item.attrs = attrs; - (None, dir_path, dir_ownership) - } - ModKind::Unloaded => { - // We have an outline `mod foo;` so we need to parse the file. - let old_attrs_len = attrs.len(); - let ParsedExternalMod { - mut items, - inner_span, - file_path, - dir_path, - dir_ownership, - } = parse_external_mod( - &self.cx.sess, - ident, - span, - &self.cx.current_expansion.module, - self.cx.current_expansion.dir_ownership, - &mut attrs, - ); - - if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { - (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); - } - - *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); - item.attrs = attrs; - if item.attrs.len() > old_attrs_len { - // If we loaded an out-of-line module and added some inner attributes, - // then we need to re-configure it and re-collect attributes for - // resolution and expansion. - item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr( - attr, - Annotatable::Item(item), - AstFragmentKind::Items, - ) - .make_items(); - } - } - (Some(file_path), dir_path, dir_ownership) - } - }; - - // Set the module info before we flat map. - let mut module = self.cx.current_expansion.module.with_dir_path(dir_path); - module.mod_path.push(ident); - if let Some(file_path) = file_path { - module.file_path_stack.push(file_path); - } - - let orig_module = - mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); - let orig_dir_ownership = - mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); - - let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)); - - // Restore the module info. - self.cx.current_expansion.dir_ownership = orig_dir_ownership; - self.cx.current_expansion.module = orig_module; - - result - } - _ => { - item.attrs = attrs; - // The crate root is special - don't assign an ID to it. - if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) { - assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)) - } else { - noop_flat_map_item(item, self) - } - } - } + self.flat_map_node(node) } - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems) - .make_trait_items(); - } - - match item.kind { - ast::AssocItemKind::MacCall(ref mac) => { - self.check_attributes(&item.attrs, &mac); - item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => { - self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items() - } - _ => unreachable!(), - }) - } - _ => { - assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) - } - } + fn visit_crate(&mut self, node: &mut ast::Crate) { + self.visit_node(node) } - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems) - .make_impl_items(); - } - - match item.kind { - ast::AssocItemKind::MacCall(ref mac) => { - self.check_attributes(&item.attrs, &mac); - item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => { - self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items() - } - _ => unreachable!(), - }) - } - _ => { - assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) - } - } + fn visit_ty(&mut self, node: &mut P) { + self.visit_node(node) } - fn visit_ty(&mut self, ty: &mut P) { - match ty.kind { - ast::TyKind::MacCall(_) => {} - _ => return noop_visit_ty(ty, self), - }; - - visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { - ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(), - _ => unreachable!(), - }); + fn visit_pat(&mut self, node: &mut P) { + self.visit_node(node) } - fn flat_map_foreign_item( - &mut self, - foreign_item: P, - ) -> SmallVec<[P; 1]> { - let mut foreign_item = configure!(self, foreign_item); - - if let Some(attr) = self.take_first_attr(&mut foreign_item) { - return self - .collect_attr( - attr, - Annotatable::ForeignItem(foreign_item), - AstFragmentKind::ForeignItems, - ) - .make_foreign_items(); - } - - match foreign_item.kind { - ast::ForeignItemKind::MacCall(ref mac) => { - self.check_attributes(&foreign_item.attrs, &mac); - foreign_item.and_then(|item| match item.kind { - ast::ForeignItemKind::MacCall(mac) => { - self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items() - } - _ => unreachable!(), - }) - } - _ => { - assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item( - foreign_item, - self - )) - } - } + fn visit_expr(&mut self, node: &mut P) { + self.cfg.configure_expr(node); + self.visit_node(node) } - fn flat_map_generic_param( - &mut self, - param: ast::GenericParam, - ) -> SmallVec<[ast::GenericParam; 1]> { - let mut param = configure!(self, param); - - if let Some(attr) = self.take_first_attr(&mut param) { - return self - .collect_attr( - attr, - Annotatable::GenericParam(param), - AstFragmentKind::GenericParams, - ) - .make_generic_params(); - } + fn filter_map_expr(&mut self, node: P) -> Option> { + self.flat_map_node(AstLikeWrapper::new(node, OptExprTag)) + } - assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self)) + fn visit_block(&mut self, node: &mut P) { + let orig_dir_ownership = mem::replace( + &mut self.cx.current_expansion.dir_ownership, + DirOwnership::UnownedViaBlock, + ); + noop_visit_block(node, self); + self.cx.current_expansion.dir_ownership = orig_dir_ownership; } fn visit_id(&mut self, id: &mut ast::NodeId) { diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 47a64b457d0ca..5599c1df6d9de 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(associated_type_bounds)] +#![feature(associated_type_defaults)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![cfg_attr(bootstrap, feature(destructuring_assignment))] From 452346677084a954b78636f222788b8f072b8572 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 7 Jan 2022 14:54:16 +0800 Subject: [PATCH 14/21] expand: Import more AST enums --- compiler/rustc_expand/src/expand.rs | 70 ++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4c50685d5f334..07ce901fb417a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,9 +11,9 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AstLike, AstLikeWrapper, Block, Inline, ItemKind, MacArgs, MacCall}; -use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; -use rustc_ast::{NodeId, Path, StmtKind}; +use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind}; +use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; +use rustc_ast::{NodeId, PatKind, StmtKind, TyKind}; use rustc_ast_pretty::pprust; use rustc_attr::is_builtin_attr; use rustc_data_structures::map_in_place::MapInPlace; @@ -317,10 +317,10 @@ pub enum InvocationKind { pos: usize, item: Annotatable, // Required for resolving derive helper attributes. - derives: Vec, + derives: Vec, }, Derive { - path: Path, + path: ast::Path, item: Annotatable, }, } @@ -678,7 +678,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate, ), Annotatable::Item(item_inner) - if matches!(attr.style, ast::AttrStyle::Inner) + if matches!(attr.style, AttrStyle::Inner) && matches!( item_inner.kind, ItemKind::Mod( @@ -746,7 +746,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } - let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; + let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path }; let items = match expander.expand(self.cx, span, &meta, item) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { @@ -808,7 +808,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { fn visit_item(&mut self, item: &'ast ast::Item) { match &item.kind { - ast::ItemKind::Mod(_, mod_kind) + ItemKind::Mod(_, mod_kind) if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => { feature_err( @@ -836,7 +836,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { &mut self, toks: TokenStream, kind: AstFragmentKind, - path: &Path, + path: &ast::Path, span: Span, ) -> AstFragment { let mut parser = self.cx.new_parser_from_tts(toks); @@ -928,7 +928,7 @@ pub fn parse_ast_fragment<'a>( pub fn ensure_complete_parse<'a>( this: &mut Parser<'a>, - macro_path: &Path, + macro_path: &ast::Path, kind_name: &str, span: Span, ) { @@ -1053,12 +1053,12 @@ impl InvocationCollectorNode for P { noop_flat_map_item(self, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.kind, ast::ItemKind::MacCall(..)) + matches!(self.kind, ItemKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - ast::ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1067,13 +1067,13 @@ impl InvocationCollectorNode for P { collector: &mut InvocationCollector<'_, '_>, noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, ) -> Result { - if !matches!(node.kind, ast::ItemKind::Mod(..)) { + if !matches!(node.kind, ItemKind::Mod(..)) { return Ok(noop_flat_map(node, collector)); } // Work around borrow checker not seeing through `P`'s deref. let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs)); - let ast::ItemKind::Mod(_, mod_kind) = &mut node.kind else { + let ItemKind::Mod(_, mod_kind) = &mut node.kind else { unreachable!() }; @@ -1157,12 +1157,12 @@ impl InvocationCollectorNode for AstLikeWrapper, TraitItemTag> noop_flat_map_assoc_item(self.wrapped, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.wrapped.kind, ast::AssocItemKind::MacCall(..)) + matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { - ast::AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), + AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1185,12 +1185,12 @@ impl InvocationCollectorNode for AstLikeWrapper, ImplItemTag> noop_flat_map_assoc_item(self.wrapped, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.wrapped.kind, ast::AssocItemKind::MacCall(..)) + matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let item = self.wrapped.into_inner(); match item.kind { - ast::AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), + AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1211,12 +1211,12 @@ impl InvocationCollectorNode for P { noop_flat_map_foreign_item(self, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.kind, ast::ForeignItemKind::MacCall(..)) + matches!(self.kind, ForeignItemKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - ast::ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1353,7 +1353,7 @@ impl InvocationCollectorNode for ast::Stmt { match &self.kind { StmtKind::MacCall(..) => true, StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)), - StmtKind::Semi(expr) => matches!(expr.kind, ast::ExprKind::MacCall(..)), + StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)), StmtKind::Expr(..) => unreachable!(), StmtKind::Local(..) | StmtKind::Empty => false, } @@ -1363,7 +1363,7 @@ impl InvocationCollectorNode for ast::Stmt { // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { StmtKind::MacCall(mac) => { - let MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); + let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); (style == MacStmtStyle::Semicolon, mac, attrs) } StmtKind::Item(item) => match item.into_inner() { @@ -1373,7 +1373,7 @@ impl InvocationCollectorNode for ast::Stmt { _ => unreachable!(), }, StmtKind::Semi(expr) => match expr.into_inner() { - ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => { + ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => { (mac.args.need_semicolon(), mac, attrs) } _ => unreachable!(), @@ -1431,7 +1431,7 @@ impl InvocationCollectorNode for P { fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - ast::TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), _ => unreachable!(), } } @@ -1453,12 +1453,12 @@ impl InvocationCollectorNode for P { noop_visit_pat(self, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.kind, ast::PatKind::MacCall(..)) + matches!(self.kind, PatKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - ast::PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), + PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No), _ => unreachable!(), } } @@ -1481,12 +1481,12 @@ impl InvocationCollectorNode for P { noop_visit_expr(self, visitor) } fn is_mac_call(&self) -> bool { - matches!(self.kind, ast::ExprKind::MacCall(..)) + matches!(self.kind, ExprKind::MacCall(..)) } fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.into_inner(); match node.kind { - ast::ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1516,7 +1516,7 @@ impl InvocationCollectorNode for AstLikeWrapper, OptExprTag> { fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { let node = self.wrapped.into_inner(); match node.kind { - ast::ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1560,7 +1560,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr( &mut self, - (attr, pos, derives): (ast::Attribute, usize, Vec), + (attr, pos, derives): (ast::Attribute, usize, Vec), item: Annotatable, kind: AstFragmentKind, ) -> AstFragment { @@ -1573,7 +1573,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn take_first_attr( &self, item: &mut impl AstLike, - ) -> Option<(ast::Attribute, usize, Vec)> { + ) -> Option<(ast::Attribute, usize, Vec)> { let mut attr = None; item.visit_attrs(|attrs| { @@ -1609,7 +1609,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. - fn check_attributes(&self, attrs: &[ast::Attribute], call: &MacCall) { + fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { let features = self.cx.ecfg.features.unwrap(); let mut attrs = attrs.iter().peekable(); let mut span: Option = None; @@ -1764,7 +1764,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let mut node = configure!(self, node); return match &node.kind { StmtKind::Expr(expr) - if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) => + if matches!(**expr, ast::Expr { kind: ExprKind::MacCall(..), .. }) => { self.cx.current_expansion.is_trailing_mac = true; // Don't use `assign_id` for this statement - it may get removed @@ -1801,7 +1801,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.flat_map_node(AstLikeWrapper::new(node, OptExprTag)) } - fn visit_block(&mut self, node: &mut P) { + fn visit_block(&mut self, node: &mut P) { let orig_dir_ownership = mem::replace( &mut self.cx.current_expansion.dir_ownership, DirOwnership::UnownedViaBlock, @@ -1810,7 +1810,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cx.current_expansion.dir_ownership = orig_dir_ownership; } - fn visit_id(&mut self, id: &mut ast::NodeId) { + fn visit_id(&mut self, id: &mut NodeId) { // We may have already assigned a `NodeId` // by calling `assign_id` if self.monotonic && *id == ast::DUMMY_NODE_ID { From 5acd1f91a01eacbe1f7feccf6f1c6775d3c4d1b4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 29 Aug 2021 21:41:46 +0300 Subject: [PATCH 15/21] rustdoc: Introduce a resolver cache for sharing data between early doc link resolution and later passes --- .../src/rmeta/decoder/cstore_impl.rs | 14 +- compiler/rustc_middle/src/query/mod.rs | 7 - src/librustdoc/clean/blanket_impl.rs | 201 +++++++++--------- src/librustdoc/clean/inline.rs | 3 +- src/librustdoc/clean/utils.rs | 1 + src/librustdoc/core.rs | 90 +++----- src/librustdoc/lib.rs | 12 +- .../passes/collect_intra_doc_links.rs | 2 +- .../passes/collect_intra_doc_links/early.rs | 144 ++++++++----- src/librustdoc/passes/collect_trait_impls.rs | 75 ++++--- 10 files changed, 290 insertions(+), 259 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index aac0aa61ea65e..a1fffd2ebbbf2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -10,6 +10,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule}; @@ -192,8 +193,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } - all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } - implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } visibility => { cdata.get_visibility(def_id.index) } @@ -473,6 +472,17 @@ impl CStore { ) -> Span { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } + + pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec { + self.get_crate_data(cnum).get_traits().collect() + } + + pub fn trait_impls_in_crate_untracked( + &self, + cnum: CrateNum, + ) -> Vec<(DefId, Option)> { + self.get_crate_data(cnum).get_trait_impls().collect() + } } impl CrateStore for CStore { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b3db2e6340024..44306375fe69f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1416,13 +1416,6 @@ rustc_queries! { separate_provide_extern } - /// Given a crate, look up all trait impls in that crate. - /// Return `(impl_id, self_ty)`. - query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option)] { - desc { "looking up all (?) trait implementations" } - separate_provide_extern - } - query is_dllimport_foreign_item(def_id: DefId) -> bool { desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index f54ab9f2b11aa..eafc74b9945ba 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -19,118 +19,119 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); - for trait_def_id in self.cx.tcx.all_traits() { - if !self.cx.cache.access_levels.is_public(trait_def_id) - || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() - { - continue; - } - // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls - let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id); - for &impl_def_id in trait_impls.blanket_impls() { - trace!( - "get_blanket_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, - impl_def_id - ); - let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); - let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| { - let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); - let ty = ty.subst(infcx.tcx, substs); - let param_env = param_env.subst(infcx.tcx, substs); + self.cx.with_all_traits(|cx, all_traits| { + for &trait_def_id in all_traits { + if !cx.cache.access_levels.is_public(trait_def_id) + || cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() + { + continue; + } + // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls + let trait_impls = cx.tcx.trait_impls_of(trait_def_id); + for &impl_def_id in trait_impls.blanket_impls() { + trace!( + "get_blanket_impls: Considering impl for trait '{:?}' {:?}", + trait_def_id, + impl_def_id + ); + let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); + let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); + let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| { + let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); + let ty = ty.subst(infcx.tcx, substs); + let param_env = param_env.subst(infcx.tcx, substs); - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); - let trait_ref = trait_ref.subst(infcx.tcx, impl_substs); + let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + let trait_ref = trait_ref.subst(infcx.tcx, impl_substs); - // Require the type the impl is implemented on to match - // our type, and ignore the impl if there was a mismatch. - let cause = traits::ObligationCause::dummy(); - let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty); - if let Ok(InferOk { value: (), obligations }) = eq_result { - // FIXME(eddyb) ignoring `obligations` might cause false positives. - drop(obligations); + // Require the type the impl is implemented on to match + // our type, and ignore the impl if there was a mismatch. + let cause = traits::ObligationCause::dummy(); + let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty); + if let Ok(InferOk { value: (), obligations }) = eq_result { + // FIXME(eddyb) ignoring `obligations` might cause false positives. + drop(obligations); - trace!( - "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", - param_env, - trait_ref, - ty - ); - let predicates = self - .cx - .tcx - .predicates_of(impl_def_id) - .instantiate(self.cx.tcx, impl_substs) - .predicates - .into_iter() - .chain(Some( - ty::Binder::dummy(trait_ref) - .to_poly_trait_predicate() - .map_bound(ty::PredicateKind::Trait) - .to_predicate(infcx.tcx), - )); - for predicate in predicates { - debug!("testing predicate {:?}", predicate); - let obligation = traits::Obligation::new( - traits::ObligationCause::dummy(), + trace!( + "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", param_env, - predicate, + trait_ref, + ty ); - match infcx.evaluate_obligation(&obligation) { - Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError::Canonical) => {} - Err(traits::OverflowError::ErrorReporting) => {} - _ => { - return false; + let predicates = cx + .tcx + .predicates_of(impl_def_id) + .instantiate(cx.tcx, impl_substs) + .predicates + .into_iter() + .chain(Some( + ty::Binder::dummy(trait_ref) + .to_poly_trait_predicate() + .map_bound(ty::PredicateKind::Trait) + .to_predicate(infcx.tcx), + )); + for predicate in predicates { + debug!("testing predicate {:?}", predicate); + let obligation = traits::Obligation::new( + traits::ObligationCause::dummy(), + param_env, + predicate, + ); + match infcx.evaluate_obligation(&obligation) { + Ok(eval_result) if eval_result.may_apply() => {} + Err(traits::OverflowError::Canonical) => {} + Err(traits::OverflowError::ErrorReporting) => {} + _ => { + return false; + } } } + true + } else { + false } - true - } else { - false + }); + debug!( + "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}", + may_apply, trait_ref, ty + ); + if !may_apply { + continue; } - }); - debug!( - "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}", - may_apply, trait_ref, ty - ); - if !may_apply { - continue; - } - self.cx.generated_synthetics.insert((ty, trait_def_id)); + cx.generated_synthetics.insert((ty, trait_def_id)); - impls.push(Item { - name: None, - attrs: Default::default(), - visibility: Inherited, - def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: box ImplItem(Impl { - unsafety: hir::Unsafety::Normal, - generics: clean_ty_generics( - self.cx, - self.cx.tcx.generics_of(impl_def_id), - self.cx.tcx.explicit_predicates_of(impl_def_id), - ), - // FIXME(eddyb) compute both `trait_` and `for_` from - // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(trait_ref.clean(self.cx)), - for_: ty.clean(self.cx), - items: self - .cx - .tcx - .associated_items(impl_def_id) - .in_definition_order() - .map(|x| x.clean(self.cx)) - .collect::>(), - polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)), - }), - cfg: None, - }); + impls.push(Item { + name: None, + attrs: Default::default(), + visibility: Inherited, + def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, + kind: box ImplItem(Impl { + unsafety: hir::Unsafety::Normal, + generics: clean_ty_generics( + cx, + cx.tcx.generics_of(impl_def_id), + cx.tcx.explicit_predicates_of(impl_def_id), + ), + // FIXME(eddyb) compute both `trait_` and `for_` from + // the post-inference `trait_ref`, as it's more accurate. + trait_: Some(trait_ref.clean(cx)), + for_: ty.clean(cx), + items: cx + .tcx + .associated_items(impl_def_id) + .in_definition_order() + .map(|x| x.clean(cx)) + .collect::>(), + polarity: ty::ImplPolarity::Positive, + kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)), + }), + cfg: None, + }); + } } - } + }); + impls } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index ce0ac322af914..a8101845fb647 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -291,6 +291,7 @@ crate fn build_impls( attrs: Option>, ret: &mut Vec, ) { + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); let tcx = cx.tcx; // for each implementation of an item represented by `did`, build the clean::Item for that impl @@ -338,7 +339,7 @@ crate fn build_impl( return; } - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl"); + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl"); let tcx = cx.tcx; let associated_trait = tcx.impl_trait_ref(did); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 43dcb611a377d..f0e9b716081ac 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -179,6 +179,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret: }; if let Some(prim) = target.primitive_type() { + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) { inline::build_impl(cx, None, did, None, ret); } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 32b66278bf423..22f59d39799c4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,30 +1,23 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; -use rustc_driver::abort_on_err; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::HirId; -use rustc_hir::{ - intravisit::{self, NestedVisitorMap, Visitor}, - Path, -}; -use rustc_interface::{interface, Queries}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{HirId, Path}; +use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; -use rustc_resolve::Namespace::TypeNS; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::lint; use rustc_session::DiagnosticOutput; use rustc_session::Session; -use rustc_span::def_id::CRATE_DEF_INDEX; -use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{source_map, Span}; use std::cell::RefCell; use std::lazy::SyncLazy; @@ -39,14 +32,20 @@ use crate::passes::{self, Condition::*}; crate use rustc_session::config::{DebuggingOptions, Input, Options}; +crate struct ResolverCaches { + pub all_traits: Option>, + pub all_trait_impls: Option>, +} + crate struct DocContext<'tcx> { crate tcx: TyCtxt<'tcx>, /// Name resolver. Used for intra-doc links. /// /// The `Rc>` wrapping is needed because that is what's returned by - /// [`Queries::expansion()`]. + /// [`rustc_interface::Queries::expansion()`]. // FIXME: see if we can get rid of this RefCell somehow crate resolver: Rc>, + crate resolver_caches: ResolverCaches, /// Used for normalization. /// /// Most of this logic is copied from rustc_lint::late. @@ -123,6 +122,18 @@ impl<'tcx> DocContext<'tcx> { _ => None, } } + + crate fn with_all_traits(&mut self, f: impl FnOnce(&mut Self, &[DefId])) { + let all_traits = self.resolver_caches.all_traits.take(); + f(self, all_traits.as_ref().expect("`all_traits` are already borrowed")); + self.resolver_caches.all_traits = all_traits; + } + + crate fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) { + let all_trait_impls = self.resolver_caches.all_trait_impls.take(); + f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed")); + self.resolver_caches.all_trait_impls = all_trait_impls; + } } /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. @@ -284,49 +295,10 @@ crate fn create_config( } } -crate fn create_resolver<'a>( - externs: config::Externs, - queries: &Queries<'a>, - sess: &Session, -) -> Rc> { - let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek(); - let resolver = resolver.clone(); - - let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate); - - // FIXME: somehow rustdoc is still missing crates even though we loaded all - // the known necessary crates. Load them all unconditionally until we find a way to fix this. - // DO NOT REMOVE THIS without first testing on the reproducer in - // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb - let extern_names: Vec = externs - .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| name) - .cloned() - .collect(); - resolver.borrow_mut().access(|resolver| { - sess.time("load_extern_crates", || { - for extern_name in &extern_names { - debug!("loading extern crate {}", extern_name); - if let Err(()) = resolver - .resolve_str_path_error( - DUMMY_SP, - extern_name, - TypeNS, - LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), - ) { - warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name) - } - } - }); - }); - - resolver -} - crate fn run_global_ctxt( tcx: TyCtxt<'_>, resolver: Rc>, + resolver_caches: ResolverCaches, show_coverage: bool, render_options: RenderOptions, output_format: OutputFormat, @@ -355,6 +327,14 @@ crate fn run_global_ctxt( }); rustc_passes::stability::check_unused_or_stable_features(tcx); + let auto_traits = resolver_caches + .all_traits + .as_ref() + .expect("`all_traits` are already borrowed") + .iter() + .copied() + .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)) + .collect(); let access_levels = AccessLevels { map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(), }; @@ -362,16 +342,14 @@ crate fn run_global_ctxt( let mut ctxt = DocContext { tcx, resolver, + resolver_caches, param_env: ParamEnv::empty(), external_traits: Default::default(), active_extern_traits: Default::default(), substs: Default::default(), impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), - auto_traits: tcx - .all_traits() - .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)) - .collect(), + auto_traits, module_trait_cache: FxHashMap::default(), cache: Cache::new(access_levels, render_options.document_private), inlined: FxHashSet::default(), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 014ac484dcfae..d7741c4fde239 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -82,6 +82,7 @@ use rustc_session::getopts; use rustc_session::{early_error, early_warn}; use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; +use crate::passes::collect_intra_doc_links; /// A macro to create a FxHashMap. /// @@ -798,7 +799,15 @@ fn main_options(options: config::Options) -> MainResult { // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let resolver = core::create_resolver(externs, queries, sess); + // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the + // two copies because one of the copies can be modified after `TyCtxt` construction. + let (resolver, resolver_caches) = { + let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek(); + let resolver_caches = resolver.borrow_mut().access(|resolver| { + collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate, externs) + }); + (resolver.clone(), resolver_caches) + }; if sess.diagnostic().has_errors_or_lint_errors() { sess.fatal("Compilation failed, aborting rustdoc"); @@ -811,6 +820,7 @@ fn main_options(options: config::Options) -> MainResult { core::run_global_ctxt( tcx, resolver, + resolver_caches, show_coverage, render_options, output_format, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7953008628204..49ff4517a4eb0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -38,7 +38,7 @@ use crate::passes::Pass; use crate::visit::DocVisitor; mod early; -crate use early::load_intra_link_crates; +crate use early::early_resolve_intra_doc_links; crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { name: "collect-intra-doc-links", diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 4cebf741e2002..31d6ac44a9460 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -1,98 +1,136 @@ -use ast::visit; -use rustc_ast as ast; +use crate::clean; +use crate::core::ResolverCaches; +use crate::html::markdown::markdown_links; +use crate::passes::collect_intra_doc_links::preprocess_link; + +use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_ast::{self as ast, ItemKind}; +use rustc_ast_lowering::ResolverAstLowering; use rustc_hir::def::Namespace::TypeNS; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; -use rustc_interface::interface; -use rustc_span::Span; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_resolve::Resolver; +use rustc_session::config::Externs; +use rustc_span::{Span, DUMMY_SP}; -use std::cell::RefCell; use std::mem; -use std::rc::Rc; - -type Resolver = Rc>; -// Letting the resolver escape at the end of the function leads to inconsistencies between the -// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates -// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ... -crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver { - let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver }; - // `walk_crate` doesn't visit the crate itself for some reason. + +crate fn early_resolve_intra_doc_links( + resolver: &mut Resolver<'_>, + krate: &ast::Crate, + externs: Externs, +) -> ResolverCaches { + let mut loader = IntraLinkCrateLoader { + resolver, + current_mod: CRATE_DEF_ID, + all_traits: Default::default(), + all_trait_impls: Default::default(), + }; + + // Overridden `visit_item` below doesn't apply to the crate root, + // so we have to visit its attributes and exports separately. loader.load_links_in_attrs(&krate.attrs, krate.span); visit::walk_crate(&mut loader, krate); - loader.resolver + loader.fill_resolver_caches(); + + // FIXME: somehow rustdoc is still missing crates even though we loaded all + // the known necessary crates. Load them all unconditionally until we find a way to fix this. + // DO NOT REMOVE THIS without first testing on the reproducer in + // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb + for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) { + let _ = loader.resolver.resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + CRATE_DEF_ID.to_def_id(), + ); + } + + ResolverCaches { + all_traits: Some(loader.all_traits), + all_trait_impls: Some(loader.all_trait_impls), + } } -struct IntraLinkCrateLoader { +struct IntraLinkCrateLoader<'r, 'ra> { + resolver: &'r mut Resolver<'ra>, current_mod: LocalDefId, - resolver: Rc>, + all_traits: Vec, + all_trait_impls: Vec, } -impl IntraLinkCrateLoader { - fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { - use crate::html::markdown::markdown_links; - use crate::passes::collect_intra_doc_links::preprocess_link; +impl IntraLinkCrateLoader<'_, '_> { + fn fill_resolver_caches(&mut self) { + for cnum in self.resolver.cstore().crates_untracked() { + let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum); + let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum); - // FIXME: this probably needs to consider inlining - let attrs = crate::clean::Attributes::from_ast(attrs, None); + self.all_traits.extend(all_traits); + self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id)); + } + } + + fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { + // FIXME: this needs to consider export inlining. + let attrs = clean::Attributes::from_ast(attrs, None); for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() { - debug!(?doc); - for link in markdown_links(doc.as_str()) { - debug!(?link.link); + let module_id = parent_module.unwrap_or(self.current_mod.to_def_id()); + + for link in markdown_links(&doc.as_str()) { let path_str = if let Some(Ok(x)) = preprocess_link(&link) { x.path_str } else { continue; }; - self.resolver.borrow_mut().access(|resolver| { - let _ = resolver.resolve_str_path_error( - span, - &path_str, - TypeNS, - parent_module.unwrap_or_else(|| self.current_mod.to_def_id()), - ); - }); + let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id); } } } } -impl visit::Visitor<'_> for IntraLinkCrateLoader { - fn visit_foreign_item(&mut self, item: &ast::ForeignItem) { - self.load_links_in_attrs(&item.attrs, item.span); - visit::walk_foreign_item(self, item) - } - +impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> { fn visit_item(&mut self, item: &ast::Item) { - use rustc_ast_lowering::ResolverAstLowering; - - if let ast::ItemKind::Mod(..) = item.kind { - let new_mod = - self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id)); - let old_mod = mem::replace(&mut self.current_mod, new_mod); + if let ItemKind::Mod(..) = item.kind { + let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id)); self.load_links_in_attrs(&item.attrs, item.span); visit::walk_item(self, item); self.current_mod = old_mod; } else { + match item.kind { + ItemKind::Trait(..) => { + self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id()); + } + ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => { + self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id()); + } + _ => {} + } self.load_links_in_attrs(&item.attrs, item.span); visit::walk_item(self, item); } } - // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too. - - fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) { + fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) { self.load_links_in_attrs(&item.attrs, item.span); visit::walk_assoc_item(self, item, ctxt) } - fn visit_field_def(&mut self, field: &ast::FieldDef) { - self.load_links_in_attrs(&field.attrs, field.span); - visit::walk_field_def(self, field) + fn visit_foreign_item(&mut self, item: &ast::ForeignItem) { + self.load_links_in_attrs(&item.attrs, item.span); + visit::walk_foreign_item(self, item) } fn visit_variant(&mut self, v: &ast::Variant) { self.load_links_in_attrs(&v.attrs, v.span); visit::walk_variant(self, v) } + + fn visit_field_def(&mut self, field: &ast::FieldDef) { + self.load_links_in_attrs(&field.attrs, field.span); + visit::walk_field_def(self, field) + } + + // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters), + // then this will have to implement other visitor methods too. } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index cc1d994dc99f0..66ac612ea37c4 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -34,16 +34,18 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate let mut new_items = Vec::new(); - for &cnum in cx.tcx.crates(()).iter() { - for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() { - inline::build_impl(cx, None, did, None, &mut new_items); + // External trait impls. + cx.with_all_trait_impls(|cx, all_trait_impls| { + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); + for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) { + inline::build_impl(cx, None, impl_def_id, None, &mut new_items); } - } + }); // Also try to inline primitive impls from other crates. - for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { - if !def_id.is_local() { - cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { + cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { + for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { + if !def_id.is_local() { inline::build_impl(cx, None, def_id, None, &mut new_items); // FIXME(eddyb) is this `doc(hidden)` check needed? @@ -51,9 +53,9 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate let impls = get_auto_trait_and_blanket_impls(cx, def_id); new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id))); } - }); + } } - } + }); let mut cleaner = BadImplStripper { prims, items: crate_items }; let mut type_did_to_deref_target: FxHashMap = FxHashMap::default(); @@ -126,36 +128,33 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate } }); - // `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations` - // doesn't work with it anyway, so pull them from the HIR map instead - let mut extra_attrs = Vec::new(); - for trait_did in cx.tcx.all_traits() { - for &impl_did in cx.tcx.hir().trait_impls(trait_did) { - let impl_did = impl_did.to_def_id(); - cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| { - let mut parent = cx.tcx.parent(impl_did); - while let Some(did) = parent { - extra_attrs.extend( - cx.tcx - .get_attrs(did) - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .filter(|attr| { - if let Some([attr]) = attr.meta_item_list().as_deref() { - attr.has_name(sym::cfg) - } else { - false - } - }) - .cloned(), - ); - parent = cx.tcx.parent(did); - } - inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items); - extra_attrs.clear(); - }); + // Local trait impls. + cx.with_all_trait_impls(|cx, all_trait_impls| { + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); + let mut attr_buf = Vec::new(); + for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) { + let mut parent = cx.tcx.parent(impl_def_id); + while let Some(did) = parent { + attr_buf.extend( + cx.tcx + .get_attrs(did) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .filter(|attr| { + if let Some([attr]) = attr.meta_item_list().as_deref() { + attr.has_name(sym::cfg) + } else { + false + } + }) + .cloned(), + ); + parent = cx.tcx.parent(did); + } + inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items); + attr_buf.clear(); } - } + }); if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind { items.extend(synth_impls); From dd9501f8d3e5e09e3e4d054f7e57d06a5b45e2f2 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 7 Jan 2022 16:48:47 +0000 Subject: [PATCH 16/21] Fix broken link --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 987431a2dbfd9..9b350d0a03b50 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -120,6 +120,7 @@ and related tools. [89652]: https://github.com/rust-lang/rust/pull/89652/ [89677]: https://github.com/rust-lang/rust/pull/89677/ [89951]: https://github.com/rust-lang/rust/pull/89951/ +[90041]: https://github.com/rust-lang/rust/pull/90041/ [90058]: https://github.com/rust-lang/rust/pull/90058/ [90104]: https://github.com/rust-lang/rust/pull/90104/ [90117]: https://github.com/rust-lang/rust/pull/90117/ From 81963b12c540bbe1053fc4b134715ba286185e73 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 7 Jan 2022 16:49:14 +0000 Subject: [PATCH 17/21] Clarify that -C strip is only in rustc, not cargo, in 1.58 --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 9b350d0a03b50..7aaa6079ef8ab 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,7 +12,7 @@ Compiler -------- - [Add LLVM CFI support to the Rust compiler][89652] -- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. +- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. Note that this release only includes support in rustc, not directly in cargo. - [Add support for LLVM coverage mapping format versions 5 and 6][91207] - [Emit LLVM optimization remarks when enabled with `-Cremark`][90833] - [Update the minimum external LLVM to 12][90175] From 2b03ed19f665fa599f3710e4ecd6ca28c945e664 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sat, 8 Jan 2022 16:57:20 +0300 Subject: [PATCH 18/21] Make `Atomic*::from_mut` return `&mut Atomic*` --- library/core/src/sync/atomic.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1dd3b2d8e3c8d..27243d8ca7030 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -333,10 +333,10 @@ impl AtomicBool { #[inline] #[cfg(target_has_atomic_equal_alignment = "8")] #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut bool) -> &Self { + pub fn from_mut(v: &mut bool) -> &mut Self { // SAFETY: the mutable reference guarantees unique ownership, and // alignment of both `bool` and `Self` is 1. - unsafe { &*(v as *mut bool as *mut Self) } + unsafe { &mut *(v as *mut bool as *mut Self) } } /// Consumes the atomic and returns the contained value. @@ -934,14 +934,14 @@ impl AtomicPtr { #[inline] #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut *mut T) -> &Self { + pub fn from_mut(v: &mut *mut T) -> &mut Self { use crate::mem::align_of; let [] = [(); align_of::>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. // - the alignment of `*mut T` and `Self` is the same on all platforms // supported by rust, as verified above. - unsafe { &*(v as *mut *mut T as *mut Self) } + unsafe { &mut *(v as *mut *mut T as *mut Self) } } /// Consumes the atomic and returns the contained value. @@ -1447,14 +1447,14 @@ macro_rules! atomic_int { #[inline] #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] - pub fn from_mut(v: &mut $int_type) -> &Self { + pub fn from_mut(v: &mut $int_type) -> &mut Self { use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. // - the alignment of `$int_type` and `Self` is the // same, as promised by $cfg_align and verified above. - unsafe { &*(v as *mut $int_type as *mut Self) } + unsafe { &mut *(v as *mut $int_type as *mut Self) } } /// Consumes the atomic and returns the contained value. From 45a43debb6c87f7ef927dc6574440744a1a67ceb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 8 Jan 2022 16:03:44 +0100 Subject: [PATCH 19/21] Remove useless collapse toggle on "all items" page --- src/librustdoc/html/render/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 16334890da674..7adf63f26f602 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -312,14 +312,6 @@ impl AllTypes { f.write_str( "

\ List of all items\ - \ - \ - \ - []\ - \ - -

", ); // Note: print_entries does not escape the title, because we know the current set of titles From 1a966235138ad68967aa0892aa0621315081e4e8 Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Sat, 8 Jan 2022 00:03:02 +0100 Subject: [PATCH 20/21] Implemented const casts of raw pointers This adds `as_mut()` method for `*const T` and `as_const()` for `*mut T` which are intended to make casting of consts safer. This was discussed in the [internals discussion][discussion]. [discussion]: https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933 --- library/core/src/ptr/const_ptr.rs | 10 ++++++++++ library/core/src/ptr/mut_ptr.rs | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a93327a0132ed..7b826f921ca87 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -48,6 +48,16 @@ impl *const T { self as _ } + /// Changes constness without changing the type. + /// + /// This is a bit safer than `as` because it wouldn't silently change the type if the code is + /// refactored. + #[unstable(feature = "ptr_const_cast", issue = "92675")] + #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + pub const fn as_mut(self) -> *mut T { + self as _ + } + /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5fd3b2ebc6098..6c50d4052976f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -47,6 +47,20 @@ impl *mut T { self as _ } + /// Changes constness without changing the type. + /// + /// This is a bit safer than `as` because it wouldn't silently change the type if the code is + /// refactored. + /// + /// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry + /// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit + /// coercion. + #[unstable(feature = "ptr_const_cast", issue = "92675")] + #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + pub const fn as_const(self) -> *const T { + self as _ + } + /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. From 0e13d0c20e8f64605c13c7ed6a086789e4de25cd Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 8 Jan 2022 21:34:01 +0100 Subject: [PATCH 21/21] remove float methods --- RELEASES.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 7aaa6079ef8ab..d6f5909a2ebc0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -53,16 +53,6 @@ These APIs are now usable in const contexts: - [`Duration::checked_mul`] - [`Duration::saturating_mul`] - [`Duration::checked_div`] -- [`Duration::as_secs_f64`] -- [`Duration::as_secs_f32`] -- [`Duration::from_secs_f64`] -- [`Duration::from_secs_f32`] -- [`Duration::mul_f64`] -- [`Duration::mul_f32`] -- [`Duration::div_f64`] -- [`Duration::div_f32`] -- [`Duration::div_duration_f64`] -- [`Duration::div_duration_f32`] - [`MaybeUninit::as_ptr`] - [`MaybeUninit::as_mut_ptr`] - [`MaybeUninit::assume_init`]