From 571b0fef01ea994cd9a81405283049b5595499c5 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Mon, 13 Mar 2023 01:31:02 -0400 Subject: [PATCH 001/217] Clarify stability guarantee for lifetimes in enum discriminants --- library/core/src/mem/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index a67df7ed557a1..aa53aa29bdbf3 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1118,6 +1118,11 @@ impl fmt::Debug for Discriminant { /// /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations /// +/// The value of a [`Discriminant`] is independent of any *lifetimes* in `T`. As such, reading +/// or writing a `Discriminant>` as a `Discriminant>` (whether via [`transmute`] or +/// otherwise) is always sound. Note that this is **not** true for other kinds of generic +/// parameters; `Discriminant>` and `Discriminant>` might be incompatible. +/// /// # Examples /// /// This can be used to compare enums that carry data, while disregarding From f65fbe95171033f1d7377f13500de5e13e6f7ca1 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 31 Jul 2023 12:34:55 -0400 Subject: [PATCH 002/217] Add char::MIN --- library/core/src/char/methods.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 515b8d20ead86..cca32c2dd37d3 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -9,6 +9,21 @@ use crate::unicode::{self, conversions}; use super::*; impl char { + /// The lowest valid code point a `char` can have, `'\0'`. + /// + /// # Examples + /// + /// ``` + /// # fn something_which_returns_char() -> char { 'a' } + /// let c: char = something_which_returns_char(); + /// assert!(char::MIN <= c); + /// + /// let value_at_min = char::MIN as u32; + /// assert_eq!(char::from_u32(value_at_min), Some('\0')); + /// ``` + #[unstable(feature = "char_min", issue = "114298")] + pub const MIN: char = '\0'; + /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// /// # Examples From b64f3c7181ccc66aca595c2b95e5a2c64b9525c6 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 31 Jul 2023 13:21:42 -0400 Subject: [PATCH 003/217] Add note on gap for MIN/MAX --- library/core/src/char/methods.rs | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index cca32c2dd37d3..c875f4503be37 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -11,9 +11,27 @@ use super::*; impl char { /// The lowest valid code point a `char` can have, `'\0'`. /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count(); + /// assert!(dist < size); + /// ``` + /// + /// Despite this gap, the `MIN` and [`MAX`] values can be used as bounds for + /// all `char` values. + /// + /// [`MAX`]: char::MAX + /// /// # Examples /// /// ``` + /// #![feature(char_min)] /// # fn something_which_returns_char() -> char { 'a' } /// let c: char = something_which_returns_char(); /// assert!(char::MIN <= c); @@ -26,6 +44,23 @@ impl char { /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count(); + /// assert!(dist < size); + /// ``` + /// + /// Despite this gap, the [`MIN`] and `MAX` values can be used as bounds for + /// all `char` values. + /// + /// [`MIN`]: char::MIN + /// /// # Examples /// /// ``` From 0165a4cf5f1b22a51d316e73d28422104b05ce6d Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 31 Jul 2023 13:22:16 -0400 Subject: [PATCH 004/217] Use u32::from for MIN/MAX examples --- library/core/src/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index c875f4503be37..c5eccf2998f3b 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -36,7 +36,7 @@ impl char { /// let c: char = something_which_returns_char(); /// assert!(char::MIN <= c); /// - /// let value_at_min = char::MIN as u32; + /// let value_at_min = u32::from(char::MIN); /// assert_eq!(char::from_u32(value_at_min), Some('\0')); /// ``` #[unstable(feature = "char_min", issue = "114298")] @@ -68,7 +68,7 @@ impl char { /// let c: char = something_which_returns_char(); /// assert!(c <= char::MAX); /// - /// let value_at_max = char::MAX as u32; + /// let value_at_max = u32::from(char::MAX); /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); /// assert_eq!(char::from_u32(value_at_max + 1), None); /// ``` From bd6ccf31de722eb75478c418cac8b5ff5338c53d Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 31 Jul 2023 13:24:30 -0400 Subject: [PATCH 005/217] Can't compare usize and u32 --- library/core/src/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index c5eccf2998f3b..feb8ee2bbda21 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -19,7 +19,7 @@ impl char { /// ``` /// #![feature(char_min)] /// let dist = u32::from(char::MAX) - u32::from(char::MIN); - /// let size = (char::MIN..=char::MAX).count(); + /// let size = (char::MIN..=char::MAX).count() as u32; /// assert!(dist < size); /// ``` /// @@ -52,7 +52,7 @@ impl char { /// ``` /// #![feature(char_min)] /// let dist = u32::from(char::MAX) - u32::from(char::MIN); - /// let size = (char::MIN..=char::MAX).count(); + /// let size = (char::MIN..=char::MAX).count() as u32; /// assert!(dist < size); /// ``` /// From 9fce8abe0bf135d05731dff415e6312472c043b7 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 31 Jul 2023 15:08:52 -0400 Subject: [PATCH 006/217] I'm mathematically challenged --- library/core/src/char/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index feb8ee2bbda21..4ac956e7b76dc 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -20,7 +20,7 @@ impl char { /// #![feature(char_min)] /// let dist = u32::from(char::MAX) - u32::from(char::MIN); /// let size = (char::MIN..=char::MAX).count() as u32; - /// assert!(dist < size); + /// assert!(size < dist); /// ``` /// /// Despite this gap, the `MIN` and [`MAX`] values can be used as bounds for @@ -53,7 +53,7 @@ impl char { /// #![feature(char_min)] /// let dist = u32::from(char::MAX) - u32::from(char::MIN); /// let size = (char::MIN..=char::MAX).count() as u32; - /// assert!(dist < size); + /// assert!(size < dist); /// ``` /// /// Despite this gap, the [`MIN`] and `MAX` values can be used as bounds for From ad4dd759d84b02ed8bf0508ae54d9638c139dc5c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 7 Aug 2023 10:09:20 +0000 Subject: [PATCH 007/217] Ignore ICE dumps in git --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 485968d9c56ff..4c8d1a0376426 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ build/ \#* \#*\# .#* +rustc-ice-*.txt ## Tags tags From fb7f1a81274ecc3987739793caff47af8cd6eb27 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 11 Nov 2021 21:03:47 +0000 Subject: [PATCH 008/217] std::process (unix): Implement From etc. for imp::Stdio This involves adding a new variant `imp::Stdio::StaticFd`. Signed-off-by: Ian Jackson --- .../src/sys/unix/process/process_common.rs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 640648e870748..9cc13ba6f98e4 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -13,7 +13,7 @@ use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; use crate::sys_common::process::{CommandEnv, CommandEnvs}; -use crate::sys_common::IntoInner; +use crate::sys_common::{FromInner, IntoInner}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -150,6 +150,7 @@ pub enum Stdio { Null, MakePipe, Fd(FileDesc), + StaticFd(BorrowedFd<'static>), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -463,6 +464,11 @@ impl Stdio { } } + Stdio::StaticFd(fd) => { + let fd = FileDesc::from_inner(fd.try_clone_to_owned()?); + Ok((ChildStdio::Owned(fd), None)) + } + Stdio::MakePipe => { let (reader, writer) = pipe::anon_pipe()?; let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; @@ -497,6 +503,28 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(_: io::Stdout) -> Stdio { + // This ought really to be is Stdio::StaticFd(input_argument.as_fd()). + // But AsFd::as_fd takes its argument by reference, and yields + // a bounded lifetime, so it's no use here. There is no AsStaticFd. + // + // Additionally AsFd is only implemented for the *locked* versions. + // We don't want to lock them here. (The implications of not locking + // are the same as those for process::Stdio::inherit().) + // + // Arguably the hypothetical AsStaticFd and AsFd<'static> + // should be implemented for io::Stdout, not just for StdoutLocked. + Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }) + } +} + +impl From for Stdio { + fn from(_: io::Stderr) -> Stdio { + Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) }) + } +} + impl ChildStdio { pub fn fd(&self) -> Option { match *self { From deda7d330177ead49411da1005c9902430688094 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 3 Jan 2023 15:01:19 +0000 Subject: [PATCH 009/217] std::process (windows): refactor Stdio::to_handle slightly We're going to want to reuse this bit of code. --- library/std/src/sys/windows/process.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index e3493cbb85094..4d92caee8520b 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -521,17 +521,18 @@ fn program_exists(path: &Path) -> Option> { impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option) -> io::Result { - match *self { - Stdio::Inherit => match stdio::get_handle(stdio_id) { - Ok(io) => unsafe { - let io = Handle::from_raw_handle(io); - let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_raw_handle(); - ret - }, - // If no stdio handle is available, then propagate the null value. - Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) }, + let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) { + Ok(io) => unsafe { + let io = Handle::from_raw_handle(io); + let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); + io.into_raw_handle(); + ret }, + // If no stdio handle is available, then propagate the null value. + Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) }, + }; + match *self { + Stdio::Inherit => use_stdio_id(stdio_id), Stdio::MakePipe => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; From 1bab95bf7f82a56cef02299dcc7b12e68daf4c51 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 8 Nov 2021 18:38:04 +0000 Subject: [PATCH 010/217] std::process (windows): Implement From etc. for imp::Stdio This involves a new variant `imp;::Stdio::InheritSpecific`. Signed-off-by: Ian Jackson --- library/std/src/sys/windows/process.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 4d92caee8520b..02ca4fc615a00 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -170,6 +170,7 @@ pub struct Command { pub enum Stdio { Inherit, + InheritSpecific { from_stdio_id: c::DWORD }, Null, MakePipe, Pipe(AnonPipe), @@ -533,6 +534,7 @@ impl Stdio { }; match *self { Stdio::Inherit => use_stdio_id(stdio_id), + Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id), Stdio::MakePipe => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; @@ -580,6 +582,18 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(_: io::Stdout) -> Stdio { + Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE } + } +} + +impl From for Stdio { + fn from(_: io::Stderr) -> Stdio { + Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE } + } +} + //////////////////////////////////////////////////////////////////////////////// // Processes //////////////////////////////////////////////////////////////////////////////// From 36295fad122fd7b94d46f7bcc83a7432b94aee96 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 1 Sep 2021 16:39:02 +0100 Subject: [PATCH 011/217] std::process: impl From (etc.) for Stdio Signed-off-by: Ian Jackson --- library/std/src/process.rs | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 8f3201b0091d3..c9dfd30084498 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1491,6 +1491,66 @@ impl From for Stdio { } } +#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + /// Redirect command stdout/stderr to our stdout + /// + /// # Examples + /// + /// ```rust + /// #![feature(exit_status_error)] + /// use std::io; + /// use std::process::Command; + /// + /// # fn test() -> Result<(), Box> { + /// let output = Command::new("whoami") + // "whoami" is a command which exists on both Unix and Windows, + // and which succeeds, producing some stdout output but no stderr. + /// .stdout(io::stdout()) + /// .output()?; + /// output.status.exit_ok()?; + /// assert!(output.stdout.is_empty()); + /// # Ok(()) + /// # } + /// # + /// # if cfg!(unix) { + /// # test().unwrap(); + /// # } + /// ``` + fn from(inherit: io::Stdout) -> Stdio { + Stdio::from_inner(inherit.into()) + } +} + +#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + /// Redirect command stdout/stderr to our stderr + /// + /// # Examples + /// + /// ```rust + /// #![feature(exit_status_error)] + /// use std::io; + /// use std::process::Command; + /// + /// # fn test() -> Result<(), Box> { + /// let output = Command::new("whoami") + /// .stdout(io::stderr()) + /// .output()?; + /// output.status.exit_ok()?; + /// assert!(output.stdout.is_empty()); + /// # Ok(()) + /// # } + /// # + /// # if cfg!(unix) { + /// # test().unwrap(); + /// # } + /// ``` + fn from(inherit: io::Stderr) -> Stdio { + Stdio::from_inner(inherit.into()) + } +} + /// Describes the result of a process after it has terminated. /// /// This `struct` is used to represent the exit status or other termination of a child process. From 621be609b5b54b818e8b496023a10784ea9cbb8a Mon Sep 17 00:00:00 2001 From: Seth Pellegrino Date: Tue, 23 May 2023 15:08:23 -0700 Subject: [PATCH 012/217] feat: `riscv-interrupt-{m,s}` calling conventions Similar to prior support added for the mips430, avr, and x86 targets this change implements the rough equivalent of clang's [`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling e.g. ```rust static mut CNT: usize = 0; pub extern "riscv-interrupt-m" fn isr_m() { unsafe { CNT += 1; } } ``` to produce highly effective assembly like: ```asm pub extern "riscv-interrupt-m" fn isr_m() { 420003a0: 1141 addi sp,sp,-16 unsafe { CNT += 1; 420003a2: c62a sw a0,12(sp) 420003a4: c42e sw a1,8(sp) 420003a6: 3fc80537 lui a0,0x3fc80 420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0> 420003ae: 0585 addi a1,a1,1 420003b0: 62b52e23 sw a1,1596(a0) } } 420003b4: 4532 lw a0,12(sp) 420003b6: 45a2 lw a1,8(sp) 420003b8: 0141 addi sp,sp,16 420003ba: 30200073 mret ``` (disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`) This outcome is superior to hand-coded interrupt routines which, lacking visibility into any non-assembly body of the interrupt handler, have to be very conservative and save the [entire CPU state to the stack frame][full-frame-save]. By instead asking LLVM to only save the registers that it uses, we defer the decision to the tool with the best context: it can more accurately account for the cost of spills if it knows that every additional register used is already at the cost of an implicit spill. At the LLVM level, this is apparently [implemented by] marking every register as "[callee-save]," matching the semantics of an interrupt handler nicely (it has to leave the CPU state just as it found it after its `{m|s}ret`). This approach is not suitable for every interrupt handler, as it makes no attempt to e.g. save the state in a user-accessible stack frame. For a full discussion of those challenges and tradeoffs, please refer to [the interrupt calling conventions RFC][rfc]. Inside rustc, this implementation differs from prior art because LLVM does not expose the "all-saved" function flavor as a calling convention directly, instead preferring to use an attribute that allows for differentiating between "machine-mode" and "superivsor-mode" interrupts. Finally, some effort has been made to guide those who may not yet be aware of the differences between machine-mode and supervisor-mode interrupts as to why no `riscv-interrupt` calling convention is exposed through rustc, and similarly for why `riscv-interrupt-u` makes no appearance (as it would complicate future LLVM upgrades). [clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v [full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469 [implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67 [callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37 [rfc]: https://github.com/rust-lang/rfcs/pull/3246 --- src/abi/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 2c038f22ca99b..b7f56a2986cfc 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -48,7 +48,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call default_call_conv } - Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"), + Conv::X86Intr | Conv::RiscvInterrupt { .. } => { + sess.fatal(format!("interrupt call conv {c:?} not yet implemented")) + } Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"), Conv::CCmseNonSecureCall => { From b1072412189eb27934ada08a13805fc5d3ce8f25 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 8 Aug 2023 18:28:20 +0800 Subject: [PATCH 013/217] rustc: Move `crate_types` from `Session` to `GlobalCtxt` Removes a piece of mutable state. Follow up to #114578. --- src/driver/jit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 3ea3884214805..1c606494f383e 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -98,7 +98,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { tcx.sess.fatal("JIT mode doesn't work with `cargo check`"); } - if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) { + if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) { tcx.sess.fatal("can't jit non-executable crate"); } From 59cabd70321e9dd7a9b8d670d28cc3c4a70d4337 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:20:12 +0000 Subject: [PATCH 014/217] Merge commit '8f9ac9c22d6594cf059d8e6c71d414cc5ccd7975' into sync_cg_clif-2023-08-09 --- .github/workflows/audit.yml | 19 ++++++ build_system/abi_cafe.rs | 10 +-- build_system/bench.rs | 8 +-- build_system/build_backend.rs | 16 ++--- build_system/build_sysroot.rs | 35 ++++++----- build_system/main.rs | 5 +- build_system/path.rs | 2 +- build_system/prepare.rs | 14 ++--- build_system/shared_utils.rs | 26 ++++++++ build_system/tests.rs | 36 +++++------ build_system/usage.txt | 2 +- build_system/utils.rs | 19 +++--- example/mini_core.rs | 2 +- example/mini_core_hello_world.rs | 2 +- ...ortable-simd-Allow-internal-features.patch | 24 +++++++ patches/stdlib-lock.toml | 4 +- rust-toolchain | 2 +- scripts/cargo-clif.rs | 63 ++++++++++--------- scripts/test_rustc_tests.sh | 8 ++- src/lib.rs | 7 +++ 20 files changed, 194 insertions(+), 110 deletions(-) create mode 100644 .github/workflows/audit.yml create mode 100644 build_system/shared_utils.rs create mode 100644 patches/0001-portable-simd-Allow-internal-features.patch diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 0000000000000..3efdec4155932 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,19 @@ +name: Security audit +on: + workflow_dispatch: + schedule: + - cron: '0 10 * * 1' # every monday at 10:00 UTC +permissions: + issues: write + checks: write +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: | + sed -i 's/components.*/components = []/' rust-toolchain + echo 'profile = "minimal"' >> rust-toolchain + - uses: rustsec/audit-check@v1.4.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 29c127bf50ede..2e7ba1b2060b6 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -1,8 +1,8 @@ -use super::build_sysroot; -use super::path::Dirs; -use super::prepare::GitRepo; -use super::utils::{spawn_and_wait, CargoProject, Compiler}; -use super::{CodegenBackend, SysrootKind}; +use crate::build_sysroot; +use crate::path::Dirs; +use crate::prepare::GitRepo; +use crate::utils::{spawn_and_wait, CargoProject, Compiler}; +use crate::{CodegenBackend, SysrootKind}; static ABI_CAFE_REPO: GitRepo = GitRepo::github( "Gankra", diff --git a/build_system/bench.rs b/build_system/bench.rs index cec608ea0422d..6c64faaa2563e 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -2,10 +2,10 @@ use std::env; use std::io::Write; use std::path::Path; -use super::path::{Dirs, RelPath}; -use super::prepare::GitRepo; -use super::rustc_info::get_file_name; -use super::utils::{hyperfine_command, spawn_and_wait, Compiler}; +use crate::path::{Dirs, RelPath}; +use crate::prepare::GitRepo; +use crate::rustc_info::get_file_name; +use crate::utils::{hyperfine_command, spawn_and_wait, Compiler}; static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( "ebobby", diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index 1c5db23299d6a..e434c36f99227 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -1,9 +1,9 @@ -use std::env; use std::path::PathBuf; -use super::path::{Dirs, RelPath}; -use super::rustc_info::get_file_name; -use super::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup}; +use crate::path::{Dirs, RelPath}; +use crate::rustc_info::get_file_name; +use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; +use crate::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup}; pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); @@ -18,11 +18,11 @@ pub(crate) fn build_backend( let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); maybe_incremental(&mut cmd); - let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + let mut rustflags = rustflags_from_env("RUSTFLAGS"); if is_ci() { // Deny warnings on CI - rustflags += " -Dwarnings"; + rustflags.push("-Dwarnings".to_owned()); if !is_ci_opt() { cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); @@ -42,10 +42,10 @@ pub(crate) fn build_backend( _ => unreachable!(), } - cmd.env("RUSTFLAGS", rustflags); + rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); eprintln!("[BUILD] rustc_codegen_cranelift"); - super::utils::spawn_and_wait(cmd); + crate::utils::spawn_and_wait(cmd); CG_CLIF .target_dir(dirs) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 04097936d03d0..31a4b209826f9 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -2,13 +2,13 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use super::path::{Dirs, RelPath}; -use super::rustc_info::get_file_name; -use super::utils::{ +use crate::path::{Dirs, RelPath}; +use crate::rustc_info::get_file_name; +use crate::utils::{ maybe_incremental, remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler, LogGroup, }; -use super::{CodegenBackend, SysrootKind}; +use crate::{config, CodegenBackend, SysrootKind}; static DIST_DIR: RelPath = RelPath::DIST; static BIN_DIR: RelPath = RelPath::DIST.join("bin"); @@ -128,8 +128,8 @@ pub(crate) fn build_sysroot( cargo: bootstrap_host_compiler.cargo.clone(), rustc: rustc_clif.clone(), rustdoc: rustdoc_clif.clone(), - rustflags: String::new(), - rustdocflags: String::new(), + rustflags: vec![], + rustdocflags: vec![], triple: target_triple, runner: vec![], } @@ -185,7 +185,7 @@ fn build_sysroot_for_triple( #[must_use] fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { - let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc); + let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; @@ -234,32 +234,32 @@ fn build_clif_sysroot_for_triple( let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel); - if !super::config::get_bool("keep_sysroot") { + if !config::get_bool("keep_sysroot") { // Cleanup the deps dir, but keep build scripts and the incremental cache for faster // recompilation as they are not affected by changes in cg_clif. remove_dir_if_exists(&build_dir.join("deps")); } // Build sysroot - let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string(); + let mut rustflags = vec!["-Zforce-unstable-if-unmarked".to_owned(), "-Cpanic=abort".to_owned()]; match cg_clif_dylib_path { CodegenBackend::Local(path) => { - rustflags.push_str(&format!(" -Zcodegen-backend={}", path.to_str().unwrap())); + rustflags.push(format!("-Zcodegen-backend={}", path.to_str().unwrap())); } CodegenBackend::Builtin(name) => { - rustflags.push_str(&format!(" -Zcodegen-backend={name}")); + rustflags.push(format!("-Zcodegen-backend={name}")); } }; // Necessary for MinGW to find rsbegin.o and rsend.o - rustflags - .push_str(&format!(" --sysroot {}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap())); + rustflags.push("--sysroot".to_owned()); + rustflags.push(RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap().to_owned()); if channel == "release" { // Incremental compilation by default disables mir inlining. This leads to both a decent // compile perf and a significant runtime perf regression. As such forcefully enable mir // inlining. - rustflags.push_str(" -Zinline-mir"); + rustflags.push("-Zinline-mir".to_owned()); } - compiler.rustflags += &rustflags; + compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); maybe_incremental(&mut build_cmd); if channel == "release" { @@ -289,8 +289,8 @@ fn build_clif_sysroot_for_triple( } fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { - if !super::config::get_bool("keep_sysroot") { - super::prepare::prepare_stdlib(dirs, &compiler.rustc); + if !config::get_bool("keep_sysroot") { + crate::prepare::prepare_stdlib(dirs, &compiler.rustc); } if !compiler.triple.ends_with("windows-gnu") { @@ -306,6 +306,7 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o")); let mut build_rtstartup_cmd = Command::new(&compiler.rustc); build_rtstartup_cmd + .arg("-Ainternal_features") // Missing #[allow(internal_features)] .arg("--target") .arg(&compiler.triple) .arg("--emit=obj") diff --git a/build_system/main.rs b/build_system/main.rs index 3bc78d5db94fa..798ae9dbd5006 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -16,6 +16,7 @@ mod config; mod path; mod prepare; mod rustc_info; +mod shared_utils; mod tests; mod utils; @@ -169,8 +170,8 @@ fn main() { cargo, rustc, rustdoc, - rustflags: String::new(), - rustdocflags: String::new(), + rustflags: vec![], + rustdocflags: vec![], triple, runner: vec![], } diff --git a/build_system/path.rs b/build_system/path.rs index 4f86c0fd29d6a..8572815fc55e4 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -1,7 +1,7 @@ use std::fs; use std::path::PathBuf; -use super::utils::remove_dir_if_exists; +use crate::utils::remove_dir_if_exists; #[derive(Debug, Clone)] pub(crate) struct Dirs { diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 3ee2e8f4a4e34..165296cb4a98f 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -3,18 +3,18 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use super::build_sysroot::STDLIB_SRC; -use super::path::{Dirs, RelPath}; -use super::rustc_info::get_default_sysroot; -use super::utils::{ +use crate::build_sysroot::STDLIB_SRC; +use crate::path::{Dirs, RelPath}; +use crate::rustc_info::get_default_sysroot; +use crate::utils::{ copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait, }; pub(crate) fn prepare(dirs: &Dirs) { RelPath::DOWNLOAD.ensure_exists(dirs); - super::tests::RAND_REPO.fetch(dirs); - super::tests::REGEX_REPO.fetch(dirs); - super::tests::PORTABLE_SIMD_REPO.fetch(dirs); + crate::tests::RAND_REPO.fetch(dirs); + crate::tests::REGEX_REPO.fetch(dirs); + crate::tests::PORTABLE_SIMD_REPO.fetch(dirs); } pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) { diff --git a/build_system/shared_utils.rs b/build_system/shared_utils.rs new file mode 100644 index 0000000000000..0aea545ff7dae --- /dev/null +++ b/build_system/shared_utils.rs @@ -0,0 +1,26 @@ +// This file is used by both the build system as well as cargo-clif.rs + +// Adapted from https://github.com/rust-lang/cargo/blob/6dc1deaddf62c7748c9097c7ea88e9ec77ff1a1a/src/cargo/core/compiler/build_context/target_info.rs#L750-L77 +pub(crate) fn rustflags_from_env(kind: &str) -> Vec { + // First try CARGO_ENCODED_RUSTFLAGS from the environment. + // Prefer this over RUSTFLAGS since it's less prone to encoding errors. + if let Ok(a) = std::env::var(format!("CARGO_ENCODED_{}", kind)) { + if a.is_empty() { + return Vec::new(); + } + return a.split('\x1f').map(str::to_string).collect(); + } + + // Then try RUSTFLAGS from the environment + if let Ok(a) = std::env::var(kind) { + let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); + return args.collect(); + } + + // No rustflags to be collected from the environment + Vec::new() +} + +pub(crate) fn rustflags_to_cmd_env(cmd: &mut std::process::Command, kind: &str, flags: &[String]) { + cmd.env(format!("CARGO_ENCODED_{}", kind), flags.join("\x1f")); +} diff --git a/build_system/tests.rs b/build_system/tests.rs index 0254d18cf7c2d..e7bd8b1278c66 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -1,16 +1,17 @@ -use super::build_sysroot; -use super::config; -use super::path::{Dirs, RelPath}; -use super::prepare::{apply_patches, GitRepo}; -use super::rustc_info::get_default_sysroot; -use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup}; -use super::{CodegenBackend, SysrootKind}; -use std::env; use std::ffi::OsStr; use std::fs; use std::path::PathBuf; use std::process::Command; +use crate::build_sysroot; +use crate::config; +use crate::path::{Dirs, RelPath}; +use crate::prepare::{apply_patches, GitRepo}; +use crate::rustc_info::get_default_sysroot; +use crate::shared_utils::rustflags_from_env; +use crate::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, LogGroup}; +use crate::{CodegenBackend, SysrootKind}; + static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); struct TestCase { @@ -306,7 +307,7 @@ pub(crate) fn run_tests( ); // Rust's build system denies a couple of lints that trigger on several of the test // projects. Changing the code to fix them is not worth it, so just silence all lints. - target_compiler.rustflags += " --cap-lints=allow"; + target_compiler.rustflags.push("--cap-lints=allow".to_owned()); let runner = TestRunner::new( dirs.clone(), @@ -350,18 +351,15 @@ impl<'a> TestRunner<'a> { is_native: bool, stdlib_source: PathBuf, ) -> Self { - if let Ok(rustflags) = env::var("RUSTFLAGS") { - target_compiler.rustflags.push(' '); - target_compiler.rustflags.push_str(&rustflags); - } - if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") { - target_compiler.rustdocflags.push(' '); - target_compiler.rustdocflags.push_str(&rustdocflags); - } + target_compiler.rustflags.extend(rustflags_from_env("RUSTFLAGS")); + target_compiler.rustdocflags.extend(rustflags_from_env("RUSTDOCFLAGS")); // FIXME fix `#[linkage = "extern_weak"]` without this if target_compiler.triple.contains("darwin") { - target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup"); + target_compiler.rustflags.extend([ + "-Clink-arg=-undefined".to_owned(), + "-Clink-arg=dynamic_lookup".to_owned(), + ]); } let jit_supported = use_unstable_features @@ -470,7 +468,7 @@ impl<'a> TestRunner<'a> { S: AsRef, { let mut cmd = Command::new(&self.target_compiler.rustc); - cmd.args(self.target_compiler.rustflags.split_whitespace()); + cmd.args(&self.target_compiler.rustflags); cmd.arg("-L"); cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display())); cmd.arg("--out-dir"); diff --git a/build_system/usage.txt b/build_system/usage.txt index 6d3b3a13d6e75..f652599447bcf 100644 --- a/build_system/usage.txt +++ b/build_system/usage.txt @@ -43,7 +43,7 @@ REQUIREMENTS: * Rustup: By default rustup is used to install the right nightly version. If you don't want to use rustup, you can manually install the nightly version indicated by rust-toolchain.toml and point the CARGO, RUSTC and RUSTDOC env vars to the right executables. - * Git: `./y.sh prepare` uses git for applying patches and on Windows for downloading test repos. + * Git: Git is used for applying patches and on Windows for downloading test repos. * Curl and tar (non-Windows only): Used by `./y.sh prepare` to download a single commit for repos. Git will be used to clone the whole repo when using Windows. * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.sh bench`. diff --git a/build_system/utils.rs b/build_system/utils.rs index 97c82d501c5a9..24624cdeab1f1 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -5,15 +5,16 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; -use super::path::{Dirs, RelPath}; +use crate::path::{Dirs, RelPath}; +use crate::shared_utils::rustflags_to_cmd_env; #[derive(Clone, Debug)] pub(crate) struct Compiler { pub(crate) cargo: PathBuf, pub(crate) rustc: PathBuf, pub(crate) rustdoc: PathBuf, - pub(crate) rustflags: String, - pub(crate) rustdocflags: String, + pub(crate) rustflags: Vec, + pub(crate) rustdocflags: Vec, pub(crate) triple: String, pub(crate) runner: Vec, } @@ -23,8 +24,8 @@ impl Compiler { match self.triple.as_str() { "aarch64-unknown-linux-gnu" => { // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - self.rustflags += " -Clinker=aarch64-linux-gnu-gcc"; - self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc"; + self.rustflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned()); + self.rustdocflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned()); self.runner = vec![ "qemu-aarch64".to_owned(), "-L".to_owned(), @@ -33,8 +34,8 @@ impl Compiler { } "s390x-unknown-linux-gnu" => { // We are cross-compiling for s390x. Use the correct linker and run tests in qemu. - self.rustflags += " -Clinker=s390x-linux-gnu-gcc"; - self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc"; + self.rustflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned()); + self.rustdocflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned()); self.runner = vec![ "qemu-s390x".to_owned(), "-L".to_owned(), @@ -100,8 +101,8 @@ impl CargoProject { cmd.env("RUSTC", &compiler.rustc); cmd.env("RUSTDOC", &compiler.rustdoc); - cmd.env("RUSTFLAGS", &compiler.rustflags); - cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags); + rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &compiler.rustflags); + rustflags_to_cmd_env(&mut cmd, "RUSTDOCFLAGS", &compiler.rustdocflags); if !compiler.runner.is_empty() { cmd.env( format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")), diff --git a/example/mini_core.rs b/example/mini_core.rs index 9ecc4c5dd5b64..34c7e44b2881c 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -11,7 +11,7 @@ thread_local )] #![no_core] -#![allow(dead_code)] +#![allow(dead_code, internal_features)] #[lang = "sized"] pub trait Sized {} diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index d97fab9eb4227..91de04d97702f 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -1,6 +1,6 @@ #![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)] #![no_core] -#![allow(dead_code, non_camel_case_types)] +#![allow(dead_code, non_camel_case_types, internal_features)] extern crate mini_core; diff --git a/patches/0001-portable-simd-Allow-internal-features.patch b/patches/0001-portable-simd-Allow-internal-features.patch new file mode 100644 index 0000000000000..87252df1eabe3 --- /dev/null +++ b/patches/0001-portable-simd-Allow-internal-features.patch @@ -0,0 +1,24 @@ +From fcf75306d88e533b83eaff3f8d0ab9f307e8a84d Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Wed, 9 Aug 2023 10:01:17 +0000 +Subject: [PATCH] Allow internal features + +--- + crates/core_simd/src/lib.rs | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs +index fde406b..b386116 100644 +--- a/crates/core_simd/src/lib.rs ++++ b/crates/core_simd/src/lib.rs +@@ -19,6 +19,7 @@ + #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really + #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] + #![unstable(feature = "portable_simd", issue = "86656")] ++#![allow(internal_features)] + //! Portable SIMD module. + + #[path = "mod.rs"] +-- +2.34.1 + diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index aea47bdfba262..fa175edcae60f 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -74,9 +74,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.95" +version = "0.1.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6866e0f3638013234db3c89ead7a14d278354338e7237257407500009012b23f" +checksum = "d6c0f24437059853f0fa64afc51f338f93647a3de4cf3358ba1bb4171a199775" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/rust-toolchain b/rust-toolchain index 34514658359cb..5689bdee64d26 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-07-22" +channel = "nightly-2023-08-08" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index f73b2012684cd..1e14f41d4a2c2 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -3,6 +3,8 @@ use std::env; use std::os::unix::process::CommandExt; use std::process::Command; +include!("../build_system/shared_utils.rs"); + fn main() { let current_exe = env::current_exe().unwrap(); let mut sysroot = current_exe.parent().unwrap(); @@ -10,27 +12,19 @@ fn main() { sysroot = sysroot.parent().unwrap(); } - let mut rustflags = String::new(); - rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend="); + let mut rustflags = vec!["-Cpanic=abort".to_owned(), "-Zpanic-abort-tests".to_owned()]; if let Some(name) = option_env!("BUILTIN_BACKEND") { - rustflags.push_str(name); + rustflags.push(format!("-Zcodegen-backend={name}")); } else { - rustflags.push_str( - sysroot - .join(if cfg!(windows) { "bin" } else { "lib" }) - .join( - env::consts::DLL_PREFIX.to_string() - + "rustc_codegen_cranelift" - + env::consts::DLL_SUFFIX, - ) - .to_str() - .unwrap(), + let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( + env::consts::DLL_PREFIX.to_string() + + "rustc_codegen_cranelift" + + env::consts::DLL_SUFFIX, ); + rustflags.push(format!("-Zcodegen-backend={}", dylib.to_str().unwrap())); } - rustflags.push_str(" --sysroot "); - rustflags.push_str(sysroot.to_str().unwrap()); - env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags); - env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags); + rustflags.push("--sysroot".to_owned()); + rustflags.push(sysroot.to_str().unwrap().to_owned()); let cargo = if let Some(cargo) = option_env!("CARGO") { cargo @@ -49,10 +43,7 @@ fn main() { let args: Vec<_> = match args.get(0).map(|arg| &**arg) { Some("jit") => { - env::set_var( - "RUSTFLAGS", - env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic", - ); + rustflags.push("-Cprefer-dynamic".to_owned()); args.remove(0); IntoIterator::into_iter(["rustc".to_string()]) .chain(args) @@ -64,10 +55,7 @@ fn main() { .collect() } Some("lazy-jit") => { - env::set_var( - "RUSTFLAGS", - env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic", - ); + rustflags.push("-Cprefer-dynamic".to_owned()); args.remove(0); IntoIterator::into_iter(["rustc".to_string()]) .chain(args) @@ -81,11 +69,28 @@ fn main() { _ => args, }; + let mut cmd = Command::new(cargo); + cmd.args(args); + rustflags_to_cmd_env( + &mut cmd, + "RUSTFLAGS", + &rustflags_from_env("RUSTFLAGS") + .into_iter() + .chain(rustflags.iter().map(|flag| flag.clone())) + .collect::>(), + ); + rustflags_to_cmd_env( + &mut cmd, + "RUSTDOCFLAGS", + &rustflags_from_env("RUSTDOCFLAGS") + .into_iter() + .chain(rustflags.iter().map(|flag| flag.clone())) + .collect::>(), + ); + #[cfg(unix)] - panic!("Failed to spawn cargo: {}", Command::new(cargo).args(args).exec()); + panic!("Failed to spawn cargo: {}", cmd.exec()); #[cfg(not(unix))] - std::process::exit( - Command::new(cargo).args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1), - ); + std::process::exit(cmd.spawn().unwrap().wait().unwrap().code().unwrap_or(1)); } diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 83cbe0db63343..c163b8543848d 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -49,6 +49,8 @@ rm tests/ui/proc-macro/allowed-signatures.rs # vendor intrinsics rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" +rm tests/ui/simd/intrinsic/generic-bswap-byte.rs # simd_bswap not yet implemented +rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # many missing simd intrinsics # exotic linkages rm tests/ui/issues/issue-33992.rs # unsupported linkages @@ -124,6 +126,8 @@ rm tests/ui/typeck/issue-46112.rs # same rm tests/ui/consts/const_cmp_type_id.rs # same rm tests/ui/consts/issue-73976-monomorphic.rs # same rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same +rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same +rm tests/ui/consts/issue-94675.rs # same # rustdoc-clif passes extra args, suppressing the help message when no args are passed rm -r tests/run-make/issue-88756-default-output @@ -158,8 +162,6 @@ rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd -rm tests/ui/panic-handler/weak-lang-item-2.rs # Will be fixed by #113568 - cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist # prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by @@ -172,7 +174,7 @@ index ea06b620c4c..b969d0009c6 100644 @@ -9,7 +9,7 @@ RUSTC_ORIGINAL := \$(RUSTC) BARE_RUSTC := \$(HOST_RPATH_ENV) '\$(RUSTC)' BARE_RUSTDOC := \$(HOST_RPATH_ENV) '\$(RUSTDOC)' - RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS) + RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS) -Ainternal_features -RUSTDOC := \$(BARE_RUSTDOC) -L \$(TARGET_RPATH_DIR) +RUSTDOC := \$(BARE_RUSTDOC) ifdef RUSTC_LINKER diff --git a/src/lib.rs b/src/lib.rs index ebd153cb71d79..d01ded8abaa52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,6 +260,13 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc "elf_gd", BinaryFormat::Macho => "macho", From c4948dc37f9863aa45fda35f705a83c3744b073b Mon Sep 17 00:00:00 2001 From: dirreke Date: Mon, 14 Aug 2023 22:57:38 +0800 Subject: [PATCH 015/217] Upgrade Object and related deps --- Cargo.lock | 38 +++++++++++++++++++++++++++++++------- Cargo.toml | 4 ++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af8e43da4eafe..7d18679c68165 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.27.2", "hashbrown 0.13.2", "log", "regalloc2", @@ -180,7 +180,7 @@ dependencies = [ "cranelift-control", "cranelift-module", "log", - "object", + "object 0.30.4", "target-lexicon", ] @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fallible-iterator" @@ -216,6 +216,15 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +dependencies = [ + "indexmap 2.0.0", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -236,6 +245,9 @@ name = "hashbrown" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash", +] [[package]] name = "indexmap" @@ -309,6 +321,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +dependencies = [ + "crc32fast", + "hashbrown 0.14.0", + "indexmap 2.0.0", + "memchr", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -356,10 +380,10 @@ dependencies = [ "cranelift-module", "cranelift-native", "cranelift-object", - "gimli", - "indexmap 2.0.0", + "gimli 0.28.0", + "indexmap 1.9.3", "libloading", - "object", + "object 0.32.0", "smallvec", "target-lexicon", ] diff --git a/Cargo.toml b/Cargo.toml index 8ded81d7399b5..2c87d2600065a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ cranelift-native = { version = "0.98" } cranelift-jit = { version = "0.98", optional = true } cranelift-object = { version = "0.98" } target-lexicon = "0.12.0" -gimli = { version = "0.27.2", default-features = false, features = ["write"]} -object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.28.0", default-features = false, features = ["write"]} +object = { version = "0.32.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.7.3", optional = true } From 9ef3a4ff0e94e4e877a87b3497e582c89941deb1 Mon Sep 17 00:00:00 2001 From: dirreke Date: Mon, 14 Aug 2023 23:22:19 +0800 Subject: [PATCH 016/217] Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7d18679c68165..64ee5207b0184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,7 +381,7 @@ dependencies = [ "cranelift-native", "cranelift-object", "gimli 0.28.0", - "indexmap 1.9.3", + "indexmap 2.0.0", "libloading", "object 0.32.0", "smallvec", From 0b283557e73f89c52b4a6965506f23379fd6e834 Mon Sep 17 00:00:00 2001 From: dirreke Date: Tue, 15 Aug 2023 00:03:27 +0800 Subject: [PATCH 017/217] reverse change in rustc_codegen_cranelift --- Cargo.lock | 36 ++++++------------------------------ Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64ee5207b0184..af8e43da4eafe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli 0.27.2", + "gimli", "hashbrown 0.13.2", "log", "regalloc2", @@ -180,7 +180,7 @@ dependencies = [ "cranelift-control", "cranelift-module", "log", - "object 0.30.4", + "object", "target-lexicon", ] @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" [[package]] name = "fallible-iterator" @@ -216,15 +216,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" -dependencies = [ - "indexmap 2.0.0", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -245,9 +236,6 @@ name = "hashbrown" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" -dependencies = [ - "ahash", -] [[package]] name = "indexmap" @@ -321,18 +309,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "object" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" -dependencies = [ - "crc32fast", - "hashbrown 0.14.0", - "indexmap 2.0.0", - "memchr", -] - [[package]] name = "once_cell" version = "1.16.0" @@ -380,10 +356,10 @@ dependencies = [ "cranelift-module", "cranelift-native", "cranelift-object", - "gimli 0.28.0", + "gimli", "indexmap 2.0.0", "libloading", - "object 0.32.0", + "object", "smallvec", "target-lexicon", ] diff --git a/Cargo.toml b/Cargo.toml index 2c87d2600065a..768d9df165242 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ cranelift-native = { version = "0.98" } cranelift-jit = { version = "0.98", optional = true } cranelift-object = { version = "0.98" } target-lexicon = "0.12.0" -gimli = { version = "0.28.0", default-features = false, features = ["write"]} -object = { version = "0.32.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.27.2", default-features = false, features = ["write"]} +object = { version = "0.30.4", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.7.3", optional = true } From 8c6590a99b7def859208644da23238fdc7a8d9f3 Mon Sep 17 00:00:00 2001 From: dirreke Date: Tue, 15 Aug 2023 00:09:20 +0800 Subject: [PATCH 018/217] reverse change in rustc_codegen_cranelift --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 768d9df165242..8ded81d7399b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ cranelift-jit = { version = "0.98", optional = true } cranelift-object = { version = "0.98" } target-lexicon = "0.12.0" gimli = { version = "0.27.2", default-features = false, features = ["write"]} -object = { version = "0.30.4", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.7.3", optional = true } From 9aa5fbf79c39867f144e5a38c53a8edd2e2069ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 18 Aug 2023 13:15:36 +0200 Subject: [PATCH 019/217] Fix shell helpers in usage docs --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index c6210f958d6c1..135a51ce392b5 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic } function jit() { From f58b2548dc702ebc64a1b6e63f0eb1f99dc7851b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 18 Aug 2023 14:47:12 +0200 Subject: [PATCH 020/217] QNX: pass a truncated thread name to the OS The maximum length the thread name can have is `_NTO_THREAD_NAME_MAX` --- library/std/src/sys/unix/thread.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 4f2d9cf36553f..7c242d4d33453 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -182,6 +182,9 @@ impl Thread { } if let Some(f) = pthread_setname_np.get() { + #[cfg(target_os = "nto")] + let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name); + let res = unsafe { f(libc::pthread_self(), name.as_ptr()) }; debug_assert_eq!(res, 0); } @@ -290,6 +293,7 @@ impl Drop for Thread { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "nto", ))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; From 18658cb0c9320d5a028246562ed40663ea72371b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 13:10:25 +0200 Subject: [PATCH 021/217] give some unwind-related terminators a more clear name --- src/base.rs | 4 ++-- src/constant.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/base.rs b/src/base.rs index 522dd7189fe63..ed371a04c5370 100644 --- a/src/base.rs +++ b/src/base.rs @@ -474,10 +474,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { *destination, ); } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate => { codegen_panic_cannot_unwind(fx, source_info); } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { // FIXME implement unwinding fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } diff --git a/src/constant.rs b/src/constant.rs index c31535742957c..7db5f79eead9e 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -550,8 +550,8 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match &bb_data.terminator().kind { TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } From 1f107b1ef3af6f297473c98867a94a62e329dd17 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 5 Aug 2023 19:07:42 +0800 Subject: [PATCH 022/217] Remove the unhelpful let binding diag comes from FormatArguments --- .../src/diagnostics/conflict_errors.rs | 50 ++++++++++++++----- .../issue-114374-invalid-help-fmt-args.rs | 16 ++++++ .../issue-114374-invalid-help-fmt-args.stderr | 33 ++++++++++++ 3 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs create mode 100644 tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fe4a45b38989a..48d09f2c2b2a4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. /// We could expand the analysis to suggest hoising all of the relevant parts of /// the users' code to make the code compile, but that could be too much. - struct NestedStatementVisitor { + /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`, + /// which is a special case since it's generated by the compiler. + struct NestedStatementVisitor<'tcx> { span: Span, current: usize, found: usize, + prop_expr: Option<&'tcx hir::Expr<'tcx>>, } - impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { - fn visit_block(&mut self, block: &hir::Block<'tcx>) { + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.current += 1; walk_block(self, block); self.current -= 1; } - fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self.span == expr.span.source_callsite() { self.found = self.current; + if self.prop_expr.is_none() { + self.prop_expr = Some(expr); + } } walk_expr(self, expr); } @@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: proper_span, current: 0, found: 0, + prop_expr: None, }; visitor.visit_stmt(stmt); + + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let expr_ty: Option> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); + + let is_format_arguments_item = + if let Some(expr_ty) = expr_ty + && let ty::Adt(adt, _) = expr_ty.kind() { + self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) + } else { + false + }; + if visitor.found == 0 && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if !is_format_arguments_item { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); + err.note("to learn more, visit "); + } suggested = true; break; } diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs new file mode 100644 index 0000000000000..4a6c2f9ed0653 --- /dev/null +++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] + +fn bar<'a>(_: std::fmt::Arguments<'a>) {} +fn main() { + let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); + //~^ ERROR temporary value dropped while borrowed + + bar(x); + + let foo = format_args!("{}", "hi"); + //~^ ERROR temporary value dropped while borrowed + bar(foo); + + let foo = format_args!("hi"); // no placeholder in arguments, so no error + bar(foo); +} diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr new file mode 100644 index 0000000000000..8221505b100e9 --- /dev/null +++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr @@ -0,0 +1,33 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13 + | +LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | bar(x); + | - borrow later used here + | + = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: to learn more, visit + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15 + | +LL | let foo = format_args!("{}", "hi"); + | ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | bar(foo); + | --- borrow later used here + | + = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: to learn more, visit + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. From ac76882bf3ea97bc32f0381ab962782f5740074c Mon Sep 17 00:00:00 2001 From: Georgii Rylov Date: Wed, 23 Aug 2023 14:49:35 +0100 Subject: [PATCH 023/217] MCP661: Move wasm32-wasi-preview1-threads to Tier2 --- .../build-wasi-threads-toolchain.sh | 2 +- .../dist-various-2/build-wasi-toolchain.sh | 2 +- src/doc/rustc/src/platform-support.md | 2 +- .../wasm32-wasi-preview1-threads.md | 33 ++++++++++++------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh index 7dae90f4403bb..689fe52863e07 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 45174e708dcf1..4b0d360686f12 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7cc17e11bdb86..9684060498a16 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -179,6 +179,7 @@ target | std | notes `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI +[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` @@ -321,7 +322,6 @@ target | std | host | notes `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL -[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md index b3eb34de63817..23b9992489973 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md @@ -1,6 +1,6 @@ # `wasm32-wasi-preview1-threads` -**Tier: 3** +**Tier: 2** The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an experimental target. This target is an extension to `wasm32-wasi-preview1` target, @@ -70,12 +70,6 @@ compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can reliably interoperate with C code in this mode (yet). -This target is not a stable target. This means that there are not many engines -which implement the `wasi-threads` feature and if they do they're likely behind a -flag, for example: - -* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` - Also note that at this time the `wasm32-wasi-preview1-threads` target assumes the presence of other merged wasm proposals such as (with their LLVM feature flags): @@ -94,6 +88,17 @@ The target intends to match the corresponding Clang target for its `"C"` ABI. > found it's recommended to open an issue either with rust-lang/rust or ideally > with LLVM itself. +## Platform requirements + +The runtime should support the same set of APIs as any other supported wasi target for interacting with the host environment through the WASI standard. The runtime also should have implemetation of [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads). + +This target is not a stable target. This means that there are a few engines +which implement the `wasi-threads` feature and if they do they're likely behind a +flag, for example: + +* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` +* [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1 + ## Building the target Users need to install or built wasi-sdk since release 20.0 @@ -110,12 +115,16 @@ After that users can build this by adding it to the `target` list in ## Building Rust programs -Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target. +From Rust Nightly 1.71.1 (2023-08-03) on the artifacts are shipped pre-compiled: + +```text +rustup target add wasm32-wasi-preview1-threads --toolchain nightly +``` + +Rust programs can be built for that target: -Specify `wasi-root` as explained in the previous section and then use the `build-std` -nightly cargo feature to build the standard library: -```shell -cargo +nightly build --target=wasm32-wasi-preview1-threads -Zbuild-std +```text +rustc --target wasm32-wasi-preview1-threads your-code.rs ``` ## Cross-compilation From 08cdb40219cc8ac2c60e24f1242ac5157c1436ee Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 16 Aug 2023 12:58:58 +0200 Subject: [PATCH 024/217] rustdoc: extract logic for printing enum fields and struct variants --- src/librustdoc/html/render/print_item.rs | 326 ++++++++++++++--------- 1 file changed, 195 insertions(+), 131 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462c1..007c1cf1ef91f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1332,7 +1332,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let tcx = cx.tcx(); let count_variants = e.variants().count(); - wrap_item(w, |mut w| { + wrap_item(w, |w| { render_attributes_in_code(w, it, tcx); write!( w, @@ -1341,148 +1341,179 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: it.name.unwrap(), e.generics.print(cx), ); - if !print_where_clause_and_check(w, &e.generics, cx) { - // If there wasn't a `where` clause, we add a whitespace. - w.write_str(" "); - } + render_enum_fields( + w, + cx, + Some(&e.generics), + e.variants(), + count_variants, + e.has_stripped_entries(), + it.is_non_exhaustive(), + ); + }); - let variants_stripped = e.has_stripped_entries(); - if count_variants == 0 && !variants_stripped { - w.write_str("{}"); - } else { - w.write_str("{\n"); - let toggle = should_hide_fields(count_variants); - if toggle { - toggle_open(&mut w, format_args!("{count_variants} variants")); - } - for v in e.variants() { - w.write_str(" "); - let name = v.name.unwrap(); - match *v.kind { - // FIXME(#101337): Show discriminant - clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => w.write_str(name.as_str()), - clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); - } - clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, None, &s.fields, " ", false, cx); - } - }, - _ => unreachable!(), - } - w.write_str(",\n"); - } + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if variants_stripped && !it.is_non_exhaustive() { - w.write_str(" // some variants omitted\n"); - } - if toggle { - toggle_close(&mut w); + if count_variants != 0 { + item_variants(w, cx, it, e.variants()); + } + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn render_enum_fields<'a>( + mut w: &mut Buffer, + cx: &mut Context<'_>, + g: Option<&clean::Generics>, + variants: impl Iterator, + count_variants: usize, + has_stripped_entries: bool, + is_non_exhaustive: bool, +) { + if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { + // If there wasn't a `where` clause, we add a whitespace. + w.write_str(" "); + } + + let variants_stripped = has_stripped_entries; + if count_variants == 0 && !variants_stripped { + w.write_str("{}"); + } else { + w.write_str("{\n"); + let toggle = should_hide_fields(count_variants); + if toggle { + toggle_open(&mut w, format_args!("{count_variants} variants")); + } + const TAB: &str = " "; + for v in variants { + w.write_str(TAB); + let name = v.name.unwrap(); + match *v.kind { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => w.write_str(name.as_str()), + clean::VariantKind::Tuple(ref s) => { + write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); + } + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, TAB, false, cx); + } + }, + _ => unreachable!(), } - w.write_str("}"); + w.write_str(",\n"); } - }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if variants_stripped && !is_non_exhaustive { + w.write_str(" // some variants omitted\n"); + } + if toggle { + toggle_close(&mut w); + } + w.write_str("}"); + } +} - if count_variants != 0 { +fn item_variants<'a>( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + variants: impl Iterator, +) { + let tcx = cx.tcx(); + write!( + w, + "

\ + Variants{}§\ +

\ + {}\ +
", + document_non_exhaustive_header(it), + document_non_exhaustive(it) + ); + for variant in variants { + let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( w, - "

\ - Variants{}§\ -

\ - {}\ -
", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + "
\ + §", ); - for variant in e.variants() { - let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "
\ - §", - ); - render_stability_since_raw_with_extra( - w, - variant.stable_since(tcx), - variant.const_stability(tcx), - it.stable_since(tcx), - it.const_stable_since(tcx), - " rightside", - ); - write!(w, "

{name}", name = variant.name.unwrap()); + render_stability_since_raw_with_extra( + w, + variant.stable_since(tcx), + variant.const_stability(tcx), + it.stable_since(tcx), + it.const_stable_since(tcx), + " rightside", + ); + write!(w, "

{name}", name = variant.name.unwrap()); - let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; - if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write!(w, "({})", print_tuple_struct_fields(cx, s)); - } - w.write_str("

"); - - let heading_and_fields = match &variant_data.kind { - clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), - clean::VariantKind::Tuple(fields) => { - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - if fields.iter().any(|f| !f.doc_value().is_empty()) { - Some(("Tuple Fields", fields)) - } else { - None - } + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { + write!(w, "({})", print_tuple_struct_fields(cx, s)); + } + w.write_str("
"); + + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| !f.doc_value().is_empty()) { + Some(("Tuple Fields", fields)) + } else { + None } - clean::VariantKind::CLike => None, - }; + } + clean::VariantKind::CLike => None, + }; - if let Some((heading, fields)) = heading_and_fields { - let variant_id = - cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "
\ -

{heading}

\ - {}", - document_non_exhaustive(variant) - ); - for field in fields { - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => {} - clean::StructFieldItem(ref ty) => { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.unwrap(), - field.name.unwrap() - )); - write!( - w, - "
\ + if let Some((heading, fields)) = heading_and_fields { + let variant_id = + cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); + write!( + w, + "
\ +

{heading}

\ + {}", + document_non_exhaustive(variant) + ); + for field in fields { + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.unwrap(), + field.name.unwrap() + )); + write!( + w, + "
\ \ §\ {f}: {t}\ ", - f = field.name.unwrap(), - t = ty.print(cx), - ); - write!( - w, - "{}
", - document(cx, field, Some(variant), HeadingOffset::H5) - ); - } - _ => unreachable!(), + f = field.name.unwrap(), + t = ty.print(cx), + ); + write!( + w, + "{}
", + document(cx, field, Some(variant), HeadingOffset::H5) + ); } + _ => unreachable!(), } - w.write_str("
"); } - - write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); + w.write_str("
"); } - write!(w, "
"); + + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); + write!(w, "
"); } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { @@ -1593,15 +1624,28 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - let mut fields = s - .fields + item_fields(w, cx, it, &s.fields, s.ctor_kind); + + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn item_fields( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + fields: &Vec, + ctor_kind: Option, +) { + let mut fields = fields .iter() .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) .peekable(); - if let None | Some(CtorKind::Fn) = s.ctor_kind { + if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { write!( w, @@ -1609,7 +1653,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean {}{}§\ \ {}", - if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), document_non_exhaustive(it) ); @@ -1630,9 +1674,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } } } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1871,7 +1912,7 @@ fn render_union<'a, 'cx: 'a>( } fn render_struct( - mut w: &mut Buffer, + w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: Option, @@ -1891,6 +1932,29 @@ fn render_struct( if let Some(g) = g { write!(w, "{}", g.print(cx)) } + render_struct_fields( + w, + g, + ty, + fields, + tab, + structhead, + it.has_stripped_entries().unwrap_or(false), + cx, + ) +} + +fn render_struct_fields( + mut w: &mut Buffer, + g: Option<&clean::Generics>, + ty: Option, + fields: &[clean::Item], + tab: &str, + structhead: bool, + has_stripped_entries: bool, + cx: &Context<'_>, +) { + let tcx = cx.tcx(); match ty { None => { let where_displayed = @@ -1922,11 +1986,11 @@ fn render_struct( } if has_visible_fields { - if it.has_stripped_entries().unwrap() { + if has_stripped_entries { write!(w, "\n{tab} /* private fields */"); } write!(w, "\n{tab}"); - } else if it.has_stripped_entries().unwrap() { + } else if has_stripped_entries { write!(w, " /* private fields */ "); } if toggle { From 3f4145e169f73392c3f5d0d8acf8840b2e8fc189 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Aug 2023 09:57:10 +0200 Subject: [PATCH 025/217] when terminating during unwinding, show the reason why --- src/base.rs | 9 +++++---- src/constant.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/base.rs b/src/base.rs index ed371a04c5370..9159bc3698755 100644 --- a/src/base.rs +++ b/src/base.rs @@ -474,8 +474,8 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { *destination, ); } - TerminatorKind::UnwindTerminate => { - codegen_panic_cannot_unwind(fx, source_info); + TerminatorKind::UnwindTerminate(reason) => { + codegen_unwind_terminate(fx, source_info, *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -971,13 +971,14 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span); } -pub(crate) fn codegen_panic_cannot_unwind<'tcx>( +pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, source_info: mir::SourceInfo, + reason: UnwindTerminateReason, ) { let args = []; - codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span); + codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span); } fn codegen_panic_inner<'tcx>( diff --git a/src/constant.rs b/src/constant.rs index 7db5f79eead9e..a934b0767f174 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -551,7 +551,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate + | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } From 89800a27fcbcd15641e06fb870b51c320a78668f Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 24 Aug 2023 12:04:40 +0200 Subject: [PATCH 026/217] Lint on invalid UnsafeCell::raw_get with invalid_reference_casting lint --- compiler/rustc_lint/src/reference_casting.rs | 44 +++++++++++-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cell.rs | 1 + tests/ui/lint/reference_casting.rs | 28 ++++++++ tests/ui/lint/reference_casting.stderr | 68 ++++++++++++++------ 5 files changed, 117 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 883f6242b564d..d540f473ae8f1 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -128,7 +128,11 @@ fn is_operation_we_care_about<'tcx>( fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { let e = e.peel_blocks(); - fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + fn from_casts<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'tcx>, + need_check_freeze: &mut bool, + ) -> Option<&'tcx Expr<'tcx>> { // as *mut ... let mut e = if let ExprKind::Cast(e, t) = e.kind && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() { @@ -138,6 +142,14 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) { expr + // UnsafeCell::raw_get() + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) + { + *need_check_freeze = true; + arg } else { return None; }; @@ -160,11 +172,18 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) { had_at_least_one_cast = true; expr - // ptr::from_ref() + // ptr::from_ref() or UnsafeCell::raw_get() } else if let ExprKind::Call(path, [arg]) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) { + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get) + ) + { + if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) { + *need_check_freeze = true; + } return Some(arg); } else if had_at_least_one_cast { return Some(e); @@ -190,10 +209,25 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) } } - let Some(e) = from_casts(cx, e).or_else(|| from_transmute(cx, e)) else { + let mut need_check_freeze = false; + let Some(e) = from_casts(cx, e, &mut need_check_freeze).or_else(|| from_transmute(cx, e)) + else { return false; }; let e = e.peel_blocks(); - matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not)) + let node_type = cx.typeck_results().node_type(e.hir_id); + if let ty::Ref(_, inner_ty, Mutability::Not) = node_type.kind() { + // If an UnsafeCell method is involved we need to additionaly check the + // inner type for the presence of the Freeze trait (ie does NOT contain + // an UnsafeCell), since in that case we would incorrectly lint on valid casts. + // + // We also consider non concrete skeleton types (ie generics) + // to be an issue since there is no way to make it safe for abitrary types. + !need_check_freeze + || inner_ty.is_freeze(cx.tcx, cx.param_env) + || !inner_ty.has_concrete_skeleton() + } else { + false + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8aec12f128ec6..53ade8da6d04f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1630,6 +1630,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_from_mut, + unsafe_cell_raw_get, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index bf4c682d33e5a..5bbe2f22efb7e 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2131,6 +2131,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] + #[rustc_diagnostic_item = "unsafe_cell_raw_get"] pub const fn raw_get(this: *const Self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index 92d985948ec30..7745d4ef4c3a2 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -36,6 +36,10 @@ unsafe fn ref_to_mut() { //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *std::mem::transmute::<_, *mut i32>(num); //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *std::cell::UnsafeCell::raw_get( + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + num as *const i32 as *const std::cell::UnsafeCell + ); let deferred = num as *const i32 as *mut i32; let _num = &mut *deferred; @@ -50,6 +54,16 @@ unsafe fn ref_to_mut() { &mut *((this as *const _) as *mut _) //~^ ERROR casting `&T` to `&mut T` is undefined behavior } + + fn as_mut(x: &T) -> &mut T { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + } + + fn as_mut_i32(x: &i32) -> &mut i32 { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + } } unsafe fn assign_to_ref() { @@ -111,6 +125,20 @@ unsafe fn no_warn() { let mut value = 3; let value: *const i32 = &mut value; *(value as *const i16 as *mut i16) = 42; + + fn safe_as_mut(x: &std::cell::UnsafeCell) -> &mut T { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } + + fn cell_as_mut(x: &std::cell::Cell) -> &mut i32 { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } + + #[repr(transparent)] + struct DoesContainUnsafeCell(std::cell::UnsafeCell); + fn safe_as_mut2(x: &DoesContainUnsafeCell) -> &mut DoesContainUnsafeCell { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } } fn main() {} diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr index 47b95460ec380..1189942c809dd 100644 --- a/tests/ui/lint/reference_casting.stderr +++ b/tests/ui/lint/reference_casting.stderr @@ -80,7 +80,19 @@ LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num); = note: for more information, visit error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:41:16 + --> $DIR/reference_casting.rs:39:16 + | +LL | let _num = &mut *std::cell::UnsafeCell::raw_get( + | ________________^ +LL | | +LL | | num as *const i32 as *const std::cell::UnsafeCell +LL | | ); + | |_____^ + | + = note: for more information, visit + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:45:16 | LL | let deferred = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -90,7 +102,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:44:16 + --> $DIR/reference_casting.rs:48:16 | LL | let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; | ---------------------------------------------------------------------------- casting happend here @@ -100,7 +112,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:46:16 + --> $DIR/reference_casting.rs:50:16 | LL | let _num = &mut *(num as *const _ as usize as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,15 +120,31 @@ LL | let _num = &mut *(num as *const _ as usize as *mut i32); = note: for more information, visit error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:50:9 + --> $DIR/reference_casting.rs:54:9 | LL | &mut *((this as *const _) as *mut _) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:59:18 + | +LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, visit + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:64:18 + | +LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, visit + error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:60:5 + --> $DIR/reference_casting.rs:74:5 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +152,7 @@ LL | *(a as *const _ as *mut _) = String::from("Replaced"); = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:62:5 + --> $DIR/reference_casting.rs:76:5 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +160,7 @@ LL | *(a as *const _ as *mut String) += " world"; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:64:5 + --> $DIR/reference_casting.rs:78:5 | LL | *std::ptr::from_ref(num).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +168,7 @@ LL | *std::ptr::from_ref(num).cast_mut() += 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:66:5 + --> $DIR/reference_casting.rs:80:5 | LL | *std::ptr::from_ref({ num }).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +176,7 @@ LL | *std::ptr::from_ref({ num }).cast_mut() += 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:68:5 + --> $DIR/reference_casting.rs:82:5 | LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,7 +184,7 @@ LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:70:5 + --> $DIR/reference_casting.rs:84:5 | LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +192,7 @@ LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:72:5 + --> $DIR/reference_casting.rs:86:5 | LL | *std::mem::transmute::<_, *mut i32>(num) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +200,7 @@ LL | *std::mem::transmute::<_, *mut i32>(num) += 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:74:5 + --> $DIR/reference_casting.rs:88:5 | LL | / std::ptr::write( LL | | @@ -184,7 +212,7 @@ LL | | ); = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:81:5 + --> $DIR/reference_casting.rs:95:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -194,7 +222,7 @@ LL | *value = 1; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:83:5 + --> $DIR/reference_casting.rs:97:5 | LL | *(num as *const i32).cast::().cast_mut() = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -202,7 +230,7 @@ LL | *(num as *const i32).cast::().cast_mut() = 2; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:85:5 + --> $DIR/reference_casting.rs:99:5 | LL | *(num as *const _ as usize as *mut i32) = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +238,7 @@ LL | *(num as *const _ as usize as *mut i32) = 2; = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:87:5 + --> $DIR/reference_casting.rs:101:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -221,7 +249,7 @@ LL | std::ptr::write(value, 2); = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:89:5 + --> $DIR/reference_casting.rs:103:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -232,7 +260,7 @@ LL | std::ptr::write_unaligned(value, 2); = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:91:5 + --> $DIR/reference_casting.rs:105:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -243,12 +271,12 @@ LL | std::ptr::write_volatile(value, 2); = note: for more information, visit error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:95:9 + --> $DIR/reference_casting.rs:109:9 | LL | *(this as *const _ as *mut _) = a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit -error: aborting due to 29 previous errors +error: aborting due to 32 previous errors From 19edb3ce808ee2b1190026b9d56cc6187e1ad9b1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 24 Aug 2023 20:44:32 -0700 Subject: [PATCH 027/217] rustdoc: list matching impls on type aliases Remake of "List matching impls on type aliases" * 4b1d13d9841c815915433ca2a3088a8e3e97ad96 * 6f552c800b38b3e71c5e33a295e8b490d2018c71 * 2ce7cd906bde70d8cbd9b07b31c6a7bf1131c345 Partially reverts "Fix infinite loop when retrieving impls for type alias", but keeps the test case. This version of the PR avoids the infinite loop by structurally matching types instead of using full unification. This version does not support type alias trait bounds, but the compiler does not enforce those anyway (https://github.com/rust-lang/rust/issues/21903). --- src/librustdoc/html/render/mod.rs | 47 +++++++++++++-- tests/rustdoc/issue-32077-type-alias-impls.rs | 59 +++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc/issue-32077-type-alias-impls.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index aef8f1a74fb5a..1d77ce74c80ea 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -54,6 +54,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TyCtxt; use rustc_span::{ symbol::{sym, Symbol}, @@ -62,6 +63,7 @@ use rustc_span::{ use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; +use crate::clean::types::TypeAliasItem; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; use crate::error::Error; use crate::formats::cache::Cache; @@ -1139,8 +1141,40 @@ fn render_assoc_items_inner( info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); let cache = &shared.cache; - let Some(v) = cache.impls.get(&it) else { return }; - let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let tcx = cx.tcx(); + let av = if let TypeAliasItem(ait) = &*containing_item.kind && + let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) && + let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) && + let Some(mut av) = cache.impls.get(&aliased_type_defid).cloned() && + let Some(alias_def_id) = containing_item.item_id.as_def_id() + { + // This branch of the compiler compares types structually, but does + // not check trait bounds. That's probably fine, since type aliases + // don't normally constrain on them anyway. + // https://github.com/rust-lang/rust/issues/21903 + // + // If that changes, then this will need to check them with type + // unification. + let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); + let reject_cx = DeepRejectCtxt { + treat_obligation_params: TreatParams::AsCandidateKey, + }; + av.retain(|impl_| { + if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() { + reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder()) + } else { + false + } + }); + av + } else { + Vec::new() + }; + let blank = Vec::new(); + let v = cache.impls.get(&it).unwrap_or(&blank); + let (non_trait, traits): (Vec<_>, _) = + v.iter().chain(&av[..]).partition(|i| i.inner_impl().trait_.is_none()); + let mut saw_impls = FxHashSet::default(); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1169,6 +1203,9 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { + if !saw_impls.insert(i.def_id()) { + continue; + } render_impl( &mut impls_buf, cx, @@ -1214,8 +1251,10 @@ fn render_assoc_items_inner( let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = - concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete + .into_iter() + .filter(|t| saw_impls.insert(t.def_id())) + .partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs new file mode 100644 index 0000000000000..555d0579bee79 --- /dev/null +++ b/tests/rustdoc/issue-32077-type-alias-impls.rs @@ -0,0 +1,59 @@ +// Regression test for . + +#![crate_name = "foo"] + +pub struct GenericStruct(T); + +impl GenericStruct { + pub fn on_gen(arg: T) {} +} + +impl GenericStruct { + pub fn on_u32(arg: u32) {} +} + +pub trait Foo {} +pub trait Bar {} + +impl Foo for GenericStruct {} +impl Bar for GenericStruct {} + +// @has 'foo/type.TypedefStruct.html' +// We check that we have the implementation of the type alias itself. +// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' +// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' +// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl GenericStruct' +// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' +// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl Foo for GenericStruct' +// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. +// @!has - '//h3' 'impl Bar for GenericStruct {}' +// Same goes for the `Deref` impl. +// @!has - '//h2' 'Methods from Deref' +pub type TypedefStruct = GenericStruct; + +impl TypedefStruct { + pub fn on_alias() {} +} + +impl std::ops::Deref for GenericStruct { + type Target = u32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct Wrap(GenericStruct); + +// @has 'foo/type.Alias.html' +// @has - '//h2' 'Methods from Deref' +// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl Deref for Wrap' +pub type Alias = Wrap; + +impl std::ops::Deref for Wrap { + type Target = GenericStruct; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} From 20768b270e9b56368051f6f9b2be29dd0a1acb36 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jun 2023 22:48:29 +0200 Subject: [PATCH 028/217] Fix intra-doc links from pointer appearing in windows HANDLE type alias --- library/core/src/ptr/mut_ptr.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9dbb3f9d322c0..6d623b82c1cfe 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -109,7 +109,7 @@ impl *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: #method.cast_mut + /// [`cast_mut`]: pointer::cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_diagnostic_item = "ptr_cast_const"] @@ -121,7 +121,7 @@ impl *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](#method.from_bits-1). + /// The inverse method is [`from_bits`](pointer#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -157,7 +157,7 @@ impl *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](#method.to_bits-1). + /// The inverse method is [`to_bits`](pointer#method.to_bits-1). /// /// # Examples /// @@ -307,7 +307,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -373,7 +373,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -628,7 +628,7 @@ impl *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// /// # Safety /// @@ -693,7 +693,7 @@ impl *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// /// # Safety /// @@ -783,7 +783,7 @@ impl *mut T { /// /// This function is the inverse of [`offset`]. /// - /// [`offset`]: #method.offset-1 + /// [`offset`]: pointer#method.offset-1 /// /// # Safety /// @@ -2064,7 +2064,7 @@ impl *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety From 2c35abe37c1e8fb51fa15892f59aaa248a768960 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 15 Aug 2023 14:13:17 +0200 Subject: [PATCH 029/217] rustdoc: show inner enum and struct in type definition for concrete type --- src/librustdoc/clean/inline.rs | 3 + src/librustdoc/clean/mod.rs | 116 ++++++++++++++++++++++- src/librustdoc/clean/types.rs | 21 ++++ src/librustdoc/html/render/print_item.rs | 94 ++++++++++++++++++ src/librustdoc/json/conversions.rs | 2 +- tests/rustdoc/typedef-inner-variants.rs | 80 ++++++++++++++++ 6 files changed, 311 insertions(+), 5 deletions(-) create mode 100644 tests/rustdoc/typedef-inner-variants.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc86a3d747571..25f303d8a52e7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -299,6 +299,9 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box( } } +fn clean_ty_alias_inner_type<'tcx>( + ty: Ty<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + let ty::Adt(adt_def, args) = ty.kind() else { + return None; + }; + + Some(if adt_def.is_enum() { + let variants: rustc_index::IndexVec<_, _> = adt_def + .variants() + .iter() + .map(|variant| clean_variant_def_with_args(variant, args, cx)) + .collect(); + + let has_stripped_variants = adt_def.variants().len() != variants.len(); + TypeAliasInnerType::Enum { + variants, + has_stripped_variants, + is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), + } + } else { + let variant = adt_def + .variants() + .iter() + .next() + .unwrap_or_else(|| bug!("a struct or union should always have one variant def")); + + let fields: Vec<_> = + clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); + + let has_stripped_fields = variant.fields.len() != fields.len(); + if adt_def.is_struct() { + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields, has_stripped_fields } + } else { + TypeAliasInnerType::Union { fields, has_stripped_fields } + } + }) +} + fn clean_proc_macro<'tcx>( item: &hir::Item<'tcx>, name: &mut Symbol, @@ -1222,6 +1263,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext Box::new(TypeAlias { type_: clean_ty(default, cx), generics, + inner_type: None, item_type: Some(item_type), }), bounds, @@ -1264,7 +1306,12 @@ pub(crate) fn clean_impl_item<'tcx>( None, ); AssocTypeItem( - Box::new(TypeAlias { type_, generics, item_type: Some(item_type) }), + Box::new(TypeAlias { + type_, + generics, + inner_type: None, + item_type: Some(item_type), + }), Vec::new(), ) } @@ -1471,6 +1518,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), bounds, @@ -1490,6 +1538,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), // Associated types inside trait or inherent impls are not allowed to have @@ -2350,6 +2399,60 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont ) } +pub(crate) fn clean_variant_def_with_args<'tcx>( + variant: &ty::VariantDef, + args: &GenericArgsRef<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let discriminant = match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), + ty::VariantDiscr::Relative(_) => None, + }; + + let kind = match variant.ctor_kind() { + Some(CtorKind::Const) => VariantKind::CLike, + Some(CtorKind::Fn) => VariantKind::Tuple( + variant + .fields + .iter() + .filter(|field| field.vis.is_public()) + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + ), + None => VariantKind::Struct(VariantStruct { + fields: variant + .fields + .iter() + .filter(|field| field.vis.is_public()) + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + }), + }; + + Item::from_def_id_and_parts( + variant.def_id, + Some(variant.name), + VariantItem(Variant { kind, discriminant }), + cx, + ) +} + fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, disr_expr: &Option, @@ -2604,7 +2707,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); - let ty = clean_middle_ty( + let type_ = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None, @@ -2617,10 +2720,15 @@ fn clean_maybe_renamed_item<'tcx>( cx.current_type_aliases.remove(&def_id); } } + + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + let inner_type = clean_ty_alias_inner_type(ty, cx); + TypeAliasItem(Box::new(TypeAlias { - type_: rustdoc_ty, generics, - item_type: Some(ty), + inner_type, + type_: rustdoc_ty, + item_type: Some(type_), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9cf3c068b602d..6efe417970716 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2229,10 +2229,31 @@ pub(crate) struct PathSegment { pub(crate) args: GenericArgs, } +#[derive(Clone, Debug)] +pub(crate) enum TypeAliasInnerType { + Enum { + variants: IndexVec, + has_stripped_variants: bool, + is_non_exhaustive: bool, + }, + Union { + fields: Vec, + has_stripped_fields: bool, + }, + Struct { + ctor_kind: Option, + fields: Vec, + has_stripped_fields: bool, + }, +} + #[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, pub(crate) generics: Generics, + /// Inner `AdtDef` type, ie `type TyKind = IrTyKind`, + /// to be shown directly on the typedef page. + pub(crate) inner_type: Option, /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type /// alias instead of the final type. This will always have the final type, regardless of whether /// `type_` came from HIR or from metadata. diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 007c1cf1ef91f..09be756f26d22 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,6 +1237,100 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + // Only show inner variants if: + // - the typealias does NOT have any generics (modulo lifetimes) + // - AND the aliased type has some generics + // + // Otherwise, showing a non-generic type is rendurant with its own page, or + // if it still has some generics, it's not as useful. + let should_print_inner_type = t + .generics + .params + .iter() + .all(|param| matches!(param.kind, clean::GenericParamDefKind::Lifetime { .. })) + && t.generics.where_predicates.is_empty() + && t.type_.generics().is_some_and(|generics| !generics.is_empty()); + + if should_print_inner_type { + fn toggle(w: &mut W, f: F) + where + W: fmt::Write, + F: FnOnce(&mut W), + { + write!( + w, + "
\ + \ + Show Aliased Type\ + ", + ) + .unwrap(); + f(w); + write!(w, "
").unwrap(); + } + + match &t.inner_type { + Some(clean::TypeAliasInnerType::Enum { + variants, + has_stripped_variants: has_stripped_entries, + is_non_exhaustive, + }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + None, + variants.iter(), + variants.len(), + *has_stripped_entries, + *is_non_exhaustive, + ) + }); + item_variants(w, cx, it, variants.iter()); + }); + } + Some(clean::TypeAliasInnerType::Union { fields, has_stripped_fields }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + None, + fields, + "", + true, + *has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + }); + } + Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields, has_stripped_fields }) => { + toggle(w, |w| { + wrap_item(w, |w| { + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + *ctor_kind, + fields, + "", + true, + *has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + }); + } + None => {} + } + } + let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 66b5798797f61..406c7218f98c0 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -789,7 +789,7 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind impl FromWithTcx> for TypeAlias { fn from_tcx(type_alias: Box, tcx: TyCtxt<'_>) -> Self { - let clean::TypeAlias { type_, generics, item_type: _ } = *type_alias; + let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } } } diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs new file mode 100644 index 0000000000000..e0c5b7dd98ff8 --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -0,0 +1,80 @@ +#![crate_name = "inner_variants"] + +pub struct Adt; +pub struct Ty; + +// @has 'inner_variants/type.AliasTy.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type AliasTy = Ty; + +// @has 'inner_variants/enum.IrTyKind.html' +pub enum IrTyKind { + /// Doc comment for AdtKind + AdtKind(A), + /// and another one for TyKind + TyKind(A, B), + // no comment + StructKind { a: A, }, +} + +// @has 'inner_variants/type.NearlyTyKind.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type NearlyTyKind = IrTyKind; + +// @has 'inner_variants/type.TyKind.html' +// @count - '//*[@id="variants"]' 1 +// @count - '//*[@id="fields"]' 0 +// @count - '//*[@class="variant"]' 3 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" +pub type TyKind = IrTyKind; + +// @has 'inner_variants/union.OneOr.html' +pub union OneOr { + pub one: i64, + pub or: A, +} + +// @has 'inner_variants/type.OneOrF64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 2 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "union OneOrF64" +pub type OneOrF64 = OneOr; + +// @has 'inner_variants/struct.One.html' +pub struct One { + pub val: T, + __hidden: T, +} + +// @has 'inner_variants/type.OneU64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 1 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct OneU64" +pub type OneU64 = One; + +// @has 'inner_variants/struct.OnceA.html' +pub struct OnceA<'a, A> { + a: &'a A, // private +} + +// @has 'inner_variants/type.Once.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" +pub type Once<'a> = OnceA<'a, i64>; + +// @has 'inner_variants/struct.HighlyGenericStruct.html' +pub struct HighlyGenericStruct { + pub z: (A, B, C, D) +} + +// VERIFY that we NOT show the Aliased Type +// @has 'inner_variants/type.HighlyGenericAABB.html' +// @count - '//details[@class="toggle"]' 0 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type HighlyGenericAABB = HighlyGenericStruct; From 6b3bba8c3e60e08805a5b4b556c5ec128d350382 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 16 Aug 2023 17:12:04 +0200 Subject: [PATCH 030/217] rustdoc: handle typedef inner type when doing cross-crate inlining --- src/librustdoc/clean/inline.rs | 16 ++++++---------- .../auxiliary/cross_crate_generic_typedef.rs | 5 +++++ tests/rustdoc/typedef-inner-variants.rs | 11 +++++++++++ 3 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 25f303d8a52e7..dd43ee0338322 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, - clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, + clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes, + AttributesExt, ImplKind, ItemId, Type, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -289,19 +290,14 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), - cx, - Some(did), - None, - ); + let ty = cx.tcx.type_of(did).instantiate_identity(); + let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); + let inner_type = clean_ty_alias_inner_type(ty, cx); Box::new(clean::TypeAlias { type_, generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), - // FIXME: Figure-out how to handle inner_type with - // clean_ty_typedef_inner_type - inner_type: None, + inner_type, item_type: None, }) } diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs new file mode 100644 index 0000000000000..f4e020b3b9599 --- /dev/null +++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs @@ -0,0 +1,5 @@ +pub struct InlineOne { + pub inline: A +} + +pub type InlineU64 = InlineOne; diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index e0c5b7dd98ff8..46acd86e12fce 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -1,5 +1,11 @@ +// This test checks different combinations of structs, enums, and unions +// for the "Show Aliased Type" feature on type definition. + #![crate_name = "inner_variants"] +// aux-build:cross_crate_generic_typedef.rs +extern crate cross_crate_generic_typedef; + pub struct Adt; pub struct Ty; @@ -78,3 +84,8 @@ pub struct HighlyGenericStruct { // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 pub type HighlyGenericAABB = HighlyGenericStruct; + +// @has 'inner_variants/type.InlineU64.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +pub use cross_crate_generic_typedef::InlineU64; From af6889c28c5ad72433562caf75d2dc97bf494424 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 18 Aug 2023 17:57:20 +0200 Subject: [PATCH 031/217] rustdoc: bind typedef inner type items to the folding system This let's us handle a multitude of things for free: - #[doc(hidden)] - private fields/variants - --document-private-items - --document-hidden-items And correct in the process the determination of "has stripped items" by doing the same logic done by other ones. --- src/librustdoc/clean/mod.rs | 9 ++----- src/librustdoc/clean/types.rs | 17 +++--------- src/librustdoc/fold.rs | 23 ++++++++++++++++- src/librustdoc/formats/cache.rs | 1 + src/librustdoc/html/render/print_item.rs | 33 ++++++++++++++---------- tests/rustdoc/typedef-inner-variants.rs | 6 ++++- 6 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d0d92a1116fc3..892dfe4240b43 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -971,10 +971,8 @@ fn clean_ty_alias_inner_type<'tcx>( .map(|variant| clean_variant_def_with_args(variant, args, cx)) .collect(); - let has_stripped_variants = adt_def.variants().len() != variants.len(); TypeAliasInnerType::Enum { variants, - has_stripped_variants, is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), } } else { @@ -987,11 +985,10 @@ fn clean_ty_alias_inner_type<'tcx>( let fields: Vec<_> = clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); - let has_stripped_fields = variant.fields.len() != fields.len(); if adt_def.is_struct() { - TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields, has_stripped_fields } + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields } } else { - TypeAliasInnerType::Union { fields, has_stripped_fields } + TypeAliasInnerType::Union { fields } } }) } @@ -2415,7 +2412,6 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( variant .fields .iter() - .filter(|field| field.vis.is_public()) .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); clean_field_with_def_id( @@ -2431,7 +2427,6 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( fields: variant .fields .iter() - .filter(|field| field.vis.is_public()) .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); clean_field_with_def_id( diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6efe417970716..9cc5d7c2911f2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2231,20 +2231,9 @@ pub(crate) struct PathSegment { #[derive(Clone, Debug)] pub(crate) enum TypeAliasInnerType { - Enum { - variants: IndexVec, - has_stripped_variants: bool, - is_non_exhaustive: bool, - }, - Union { - fields: Vec, - has_stripped_fields: bool, - }, - Struct { - ctor_kind: Option, - fields: Vec, - has_stripped_fields: bool, - }, + Enum { variants: IndexVec, is_non_exhaustive: bool }, + Union { fields: Vec }, + Struct { ctor_kind: Option, fields: Vec }, } #[derive(Clone, Debug)] diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ceba643ed5f0c..cf11e2d7899e0 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -52,10 +52,31 @@ pub(crate) trait DocFolder: Sized { VariantItem(Variant { kind, discriminant }) } + TypeAliasItem(mut typealias) => { + typealias.inner_type = typealias.inner_type.map(|inner_type| match inner_type { + TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants = variants + .into_iter_enumerated() + .filter_map(|(_, x)| self.fold_item(x)) + .collect(); + + TypeAliasInnerType::Enum { variants, is_non_exhaustive } + } + TypeAliasInnerType::Union { fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Union { fields } + } + TypeAliasInnerType::Struct { ctor_kind, fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Struct { ctor_kind, fields } + } + }); + + TypeAliasItem(typealias) + } ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9a34e7cce8ad1..4c6e7dfb9873b 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -457,6 +457,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::StructItem(..) | clean::UnionItem(..) | clean::VariantItem(..) + | clean::TypeAliasItem(..) | clean::ImplItem(..) => { self.cache.parent_stack.push(ParentStackItem::new(&item)); (self.fold_item_recur(item), true) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 09be756f26d22..4f3a792fd7fed 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1270,30 +1270,34 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c } match &t.inner_type { - Some(clean::TypeAliasInnerType::Enum { - variants, - has_stripped_variants: has_stripped_entries, - is_non_exhaustive, - }) => { + Some(clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive }) => { toggle(w, |w| { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); render_enum_fields( w, cx, None, - variants.iter(), - variants.len(), - *has_stripped_entries, + variants_iter(), + variants_count, + has_stripped_entries, *is_non_exhaustive, ) }); - item_variants(w, cx, it, variants.iter()); + item_variants(w, cx, it, variants_iter()); }); } - Some(clean::TypeAliasInnerType::Union { fields, has_stripped_fields }) => { + Some(clean::TypeAliasInnerType::Union { fields }) => { toggle(w, |w| { wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, @@ -1302,16 +1306,19 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c fields, "", true, - *has_stripped_fields, + has_stripped_fields, cx, ); }); item_fields(w, cx, it, fields, None); }); } - Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields, has_stripped_fields }) => { + Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields }) => { toggle(w, |w| { wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, @@ -1320,7 +1327,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c fields, "", true, - *has_stripped_fields, + has_stripped_fields, cx, ); }); diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index 46acd86e12fce..cb9c1248c46c5 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -22,6 +22,8 @@ pub enum IrTyKind { TyKind(A, B), // no comment StructKind { a: A, }, + #[doc(hidden)] + Unspecified, } // @has 'inner_variants/type.NearlyTyKind.html' @@ -52,7 +54,9 @@ pub type OneOrF64 = OneOr; // @has 'inner_variants/struct.One.html' pub struct One { pub val: T, - __hidden: T, + #[doc(hidden)] + pub __hidden: T, + __private: T, } // @has 'inner_variants/type.OneU64.html' From 9443f8474548842f15d099f11856fde11bf87bd2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 18 Aug 2023 19:02:45 +0200 Subject: [PATCH 032/217] rustdoc: normalize all typedef inner types --- src/librustdoc/clean/mod.rs | 25 +++++++++++++++++++++ tests/rustdoc/typedef-inner-variants.rs | 30 +++++++++++++++++++------ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 892dfe4240b43..0ebec2d9ba23d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2406,6 +2406,11 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( ty::VariantDiscr::Relative(_) => None, }; + use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + + let infcx = cx.tcx.infer_ctxt().build(); let kind = match variant.ctor_kind() { Some(CtorKind::Const) => VariantKind::CLike, Some(CtorKind::Fn) => VariantKind::Tuple( @@ -2414,6 +2419,16 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( .iter() .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + clean_field_with_def_id( field.did, field.name, @@ -2429,6 +2444,16 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( .iter() .map(|field| { let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + clean_field_with_def_id( field.did, field.name, diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index cb9c1248c46c5..f3ba097ee0878 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -8,6 +8,17 @@ extern crate cross_crate_generic_typedef; pub struct Adt; pub struct Ty; +pub struct TyCtxt; + +pub trait Interner { + type Adt; + type Ty; +} + +impl Interner for TyCtxt { + type Adt = Adt; + type Ty = Ty; +} // @has 'inner_variants/type.AliasTy.html' // @count - '//*[@id="variants"]' 0 @@ -15,11 +26,11 @@ pub struct Ty; pub type AliasTy = Ty; // @has 'inner_variants/enum.IrTyKind.html' -pub enum IrTyKind { +pub enum IrTyKind { /// Doc comment for AdtKind - AdtKind(A), + AdtKind(I::Adt), /// and another one for TyKind - TyKind(A, B), + TyKind(I::Adt, ::Ty), // no comment StructKind { a: A, }, #[doc(hidden)] @@ -29,14 +40,18 @@ pub enum IrTyKind { // @has 'inner_variants/type.NearlyTyKind.html' // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 -pub type NearlyTyKind = IrTyKind; +pub type NearlyTyKind = IrTyKind; // @has 'inner_variants/type.TyKind.html' // @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 // @count - '//*[@class="variant"]' 3 // @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" -pub type TyKind = IrTyKind; +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[1]' "Adt" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[2]' "Adt" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[3]' "Ty" +// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[4]' "i64" +pub type TyKind = IrTyKind; // @has 'inner_variants/union.OneOr.html' pub union OneOr { @@ -68,13 +83,14 @@ pub type OneU64 = One; // @has 'inner_variants/struct.OnceA.html' pub struct OnceA<'a, A> { - a: &'a A, // private + pub a: &'a A, } // @has 'inner_variants/type.Once.html' // @count - '//*[@id="variants"]' 0 -// @count - '//*[@id="fields"]' 0 +// @count - '//*[@id="fields"]' 1 // @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" +// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "&'a" pub type Once<'a> = OnceA<'a, i64>; // @has 'inner_variants/struct.HighlyGenericStruct.html' From 282acb93c91371bfcb9256c274a932d45207fa03 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 25 Aug 2023 22:36:58 +0200 Subject: [PATCH 033/217] rustdoc: remove details for type alias inner type and fix sidebar --- src/librustdoc/clean/types.rs | 17 +++ src/librustdoc/html/render/print_item.rs | 143 ++++++++--------------- src/librustdoc/html/render/sidebar.rs | 28 ++++- tests/rustdoc/typedef-inner-variants.rs | 26 +++-- 4 files changed, 110 insertions(+), 104 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9cc5d7c2911f2..ce3f1bcf215a8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2252,6 +2252,23 @@ pub(crate) struct TypeAlias { pub(crate) item_type: Option, } +impl TypeAlias { + pub(crate) fn should_display_inner_type(&self) -> bool { + // Only show inner variants if: + // - the typealias does NOT have any generics (modulo lifetimes) + // - AND the aliased type has some generics + // + // Otherwise, showing a non-generic type is rendurant with its own page, or + // if it still has some generics, it's not as useful. + self.generics + .params + .iter() + .all(|param| matches!(param.kind, GenericParamDefKind::Lifetime { .. })) + && self.generics.where_predicates.is_empty() + && self.type_.generics().is_some_and(|generics| !generics.is_empty()) + } +} + #[derive(Clone, Debug)] pub(crate) struct OpaqueTy { pub(crate) bounds: Vec, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4f3a792fd7fed..fc0549c3f64d1 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,104 +1237,63 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - // Only show inner variants if: - // - the typealias does NOT have any generics (modulo lifetimes) - // - AND the aliased type has some generics - // - // Otherwise, showing a non-generic type is rendurant with its own page, or - // if it still has some generics, it's not as useful. - let should_print_inner_type = t - .generics - .params - .iter() - .all(|param| matches!(param.kind, clean::GenericParamDefKind::Lifetime { .. })) - && t.generics.where_predicates.is_empty() - && t.type_.generics().is_some_and(|generics| !generics.is_empty()); - - if should_print_inner_type { - fn toggle(w: &mut W, f: F) - where - W: fmt::Write, - F: FnOnce(&mut W), - { - write!( - w, - "
\ - \ - Show Aliased Type\ - ", - ) - .unwrap(); - f(w); - write!(w, "
").unwrap(); - } - - match &t.inner_type { - Some(clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive }) => { - toggle(w, |w| { - let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); - wrap_item(w, |w| { - let variants_len = variants.len(); - let variants_count = variants_iter().count(); - let has_stripped_entries = variants_len != variants_count; - - write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); - render_enum_fields( - w, - cx, - None, - variants_iter(), - variants_count, - has_stripped_entries, - *is_non_exhaustive, - ) - }); - item_variants(w, cx, it, variants_iter()); + if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + write!( + w, + "

\ + Aliased Type§

" + ); + + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + None, + variants_iter(), + variants_count, + has_stripped_entries, + *is_non_exhaustive, + ) }); + item_variants(w, cx, it, variants_iter()); } - Some(clean::TypeAliasInnerType::Union { fields }) => { - toggle(w, |w| { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields( - w, - None, - None, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); + clean::TypeAliasInnerType::Union { fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields(w, None, None, fields, "", true, has_stripped_fields, cx); }); + item_fields(w, cx, it, fields, None); } - Some(clean::TypeAliasInnerType::Struct { ctor_kind, fields }) => { - toggle(w, |w| { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields( - w, - None, - *ctor_kind, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); + clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + None, + *ctor_kind, + fields, + "", + true, + has_stripped_fields, + cx, + ); }); + item_fields(w, cx, it, fields, None); } - None => {} } } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index b96b1536156c6..c82a45303a49e 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -82,7 +82,7 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::PrimitiveItem(_) => sidebar_primitive(cx, it), clean::UnionItem(ref u) => sidebar_union(cx, it, u), clean::EnumItem(ref e) => sidebar_enum(cx, it, e), - clean::TypeAliasItem(_) => sidebar_type_alias(cx, it), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t), clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)], clean::ForeignTypeItem => sidebar_foreign_type(cx, it), _ => vec![], @@ -230,8 +230,32 @@ fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec> { +fn sidebar_type_alias<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + t: &'a clean::TypeAlias, +) -> Vec> { let mut items = vec![]; + if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { + let mut variants = variants + .iter() + .filter(|i| !i.is_stripped()) + .filter_map(|v| v.name) + .map(|name| Link::new(format!("variant.{name}"), name.to_string())) + .collect::>(); + variants.sort_unstable(); + + items.push(LinkBlock::new(Link::new("variants", "Variants"), variants)); + } + clean::TypeAliasInnerType::Union { fields } + | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => { + let fields = get_struct_fields_name(fields); + items.push(LinkBlock::new(Link::new("fields", "Fields"), fields)); + } + } + } sidebar_assoc_items(cx, it, &mut items); items } diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index f3ba097ee0878..31edb0a8706ac 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -43,14 +43,15 @@ pub enum IrTyKind { pub type NearlyTyKind = IrTyKind; // @has 'inner_variants/type.TyKind.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 // @count - '//*[@class="variant"]' 3 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "enum TyKind" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[1]' "Adt" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[2]' "Adt" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[3]' "Ty" -// @has - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code/a[4]' "i64" +// @matches - '//pre[@class="rust item-decl"]//code' "enum TyKind" +// @has - '//pre[@class="rust item-decl"]//code/a[1]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[2]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[3]' "Ty" +// @has - '//pre[@class="rust item-decl"]//code/a[4]' "i64" pub type TyKind = IrTyKind; // @has 'inner_variants/union.OneOr.html' @@ -60,10 +61,11 @@ pub union OneOr { } // @has 'inner_variants/type.OneOrF64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 // @count - '//*[@class="structfield small-section-header"]' 2 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "union OneOrF64" +// @matches - '//pre[@class="rust item-decl"]//code' "union OneOrF64" pub type OneOrF64 = OneOr; // @has 'inner_variants/struct.One.html' @@ -75,10 +77,12 @@ pub struct One { } // @has 'inner_variants/type.OneU64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 // @count - '//*[@class="structfield small-section-header"]' 1 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct OneU64" +// @matches - '//pre[@class="rust item-decl"]//code' "struct OneU64" +// @matches - '//pre[@class="rust item-decl"]//code' "pub val" pub type OneU64 = One; // @has 'inner_variants/struct.OnceA.html' @@ -87,10 +91,11 @@ pub struct OnceA<'a, A> { } // @has 'inner_variants/type.Once.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "struct Once<'a>" -// @matches - '//details[@class="toggle"]//pre[@class="rust item-decl"]//code' "&'a" +// @matches - '//pre[@class="rust item-decl"]//code' "struct Once<'a>" +// @matches - '//pre[@class="rust item-decl"]//code' "&'a" pub type Once<'a> = OnceA<'a, i64>; // @has 'inner_variants/struct.HighlyGenericStruct.html' @@ -100,12 +105,13 @@ pub struct HighlyGenericStruct { // VERIFY that we NOT show the Aliased Type // @has 'inner_variants/type.HighlyGenericAABB.html' -// @count - '//details[@class="toggle"]' 0 +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 0 pub type HighlyGenericAABB = HighlyGenericStruct; // @has 'inner_variants/type.InlineU64.html' +// @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 pub use cross_crate_generic_typedef::InlineU64; From b3686c2fd6ad57912e1b0e778bedb0b9a05c73fa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 25 Aug 2023 07:32:54 -0700 Subject: [PATCH 034/217] Add note about lazy_type_alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: León Orell Valerian Liehr --- src/librustdoc/html/render/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1d77ce74c80ea..a85e8356c2f21 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1153,8 +1153,8 @@ fn render_assoc_items_inner( // don't normally constrain on them anyway. // https://github.com/rust-lang/rust/issues/21903 // - // If that changes, then this will need to check them with type - // unification. + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification. + // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress. let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); let reject_cx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey, From 25a2ba2ee4febf9c22f7add7e14a0a50b3fd984d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 26 Aug 2023 17:42:59 -0700 Subject: [PATCH 035/217] Use `preserve_mostcc` for `extern "rust-cold"` As experimentation in 115242 has shown looks better than `coldcc`. And *don't* use a different convention for cold on Windows, because that actually ends up making things worse. cc tracking issue 97544 --- src/abi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index b7f56a2986cfc..5d775b9b53229 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -39,7 +39,7 @@ fn clif_sig_from_fn_abi<'tcx>( pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { match c { Conv::Rust | Conv::C => default_call_conv, - Conv::RustCold => CallConv::Cold, + Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64Win64 => CallConv::WindowsFastcall, From 706d010c8b590f40cc2fb3de7b744d9a59a93ac9 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 25 Aug 2023 23:07:03 +0200 Subject: [PATCH 036/217] rustdoc: always print type alias inner type (with it's where clauses) --- src/librustdoc/clean/types.rs | 17 ---------- src/librustdoc/html/render/print_item.rs | 17 +++++++--- src/librustdoc/html/render/sidebar.rs | 2 +- .../typedef-inner-variants-lazy_type_alias.rs | 34 +++++++++++++++++++ tests/rustdoc/typedef-inner-variants.rs | 8 +++-- 5 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ce3f1bcf215a8..9cc5d7c2911f2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2252,23 +2252,6 @@ pub(crate) struct TypeAlias { pub(crate) item_type: Option, } -impl TypeAlias { - pub(crate) fn should_display_inner_type(&self) -> bool { - // Only show inner variants if: - // - the typealias does NOT have any generics (modulo lifetimes) - // - AND the aliased type has some generics - // - // Otherwise, showing a non-generic type is rendurant with its own page, or - // if it still has some generics, it's not as useful. - self.generics - .params - .iter() - .all(|param| matches!(param.kind, GenericParamDefKind::Lifetime { .. })) - && self.generics.where_predicates.is_empty() - && self.type_.generics().is_some_and(|generics| !generics.is_empty()) - } -} - #[derive(Clone, Debug)] pub(crate) struct OpaqueTy { pub(crate) bounds: Vec, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fc0549c3f64d1..2da7cb01c9016 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,7 +1237,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + if let Some(inner_type) = &t.inner_type { write!( w, "

\ @@ -1256,7 +1256,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c render_enum_fields( w, cx, - None, + Some(&t.generics), variants_iter(), variants_count, has_stripped_entries, @@ -1271,7 +1271,16 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c let has_stripped_fields = fields.len() != fields_count; write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); - render_struct_fields(w, None, None, fields, "", true, has_stripped_fields, cx); + render_struct_fields( + w, + Some(&t.generics), + None, + fields, + "", + true, + has_stripped_fields, + cx, + ); }); item_fields(w, cx, it, fields, None); } @@ -1283,7 +1292,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); render_struct_fields( w, - None, + Some(&t.generics), *ctor_kind, fields, "", diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index c82a45303a49e..fce31a8423d16 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -236,7 +236,7 @@ fn sidebar_type_alias<'a>( t: &'a clean::TypeAlias, ) -> Vec> { let mut items = vec![]; - if let Some(inner_type) = &t.inner_type && t.should_display_inner_type() { + if let Some(inner_type) = &t.inner_type { match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { let mut variants = variants diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs new file mode 100644 index 0000000000000..ff84352d7169f --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs @@ -0,0 +1,34 @@ +#![crate_name = "inner_types_lazy"] + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +// @has 'inner_types_lazy/struct.Pair.html' +pub struct Pair { + pub first: A, + pub second: B, +} + +// @has 'inner_types_lazy/type.ReversedTypesPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type ReversedTypesPair = Pair; + +// @has 'inner_types_lazy/type.ReadWrite.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 2 +pub type ReadWrite = Pair +where + R: std::io::Read, + W: std::io::Write; + +// @has 'inner_types_lazy/type.VecPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type VecPair = Pair, Vec>; diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs index 31edb0a8706ac..b734714fd6432 100644 --- a/tests/rustdoc/typedef-inner-variants.rs +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -38,7 +38,8 @@ pub enum IrTyKind { } // @has 'inner_variants/type.NearlyTyKind.html' -// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 1 // @count - '//*[@id="fields"]' 0 pub type NearlyTyKind = IrTyKind; @@ -103,11 +104,12 @@ pub struct HighlyGenericStruct { pub z: (A, B, C, D) } -// VERIFY that we NOT show the Aliased Type // @has 'inner_variants/type.HighlyGenericAABB.html' // @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 -// @count - '//*[@id="fields"]' 0 +// @count - '//*[@id="fields"]' 1 +// @matches - '//pre[@class="rust item-decl"]//code' "struct HighlyGenericAABB" +// @matches - '//pre[@class="rust item-decl"]//code' "pub z" pub type HighlyGenericAABB = HighlyGenericStruct; // @has 'inner_variants/type.InlineU64.html' From 85e4b89cf615c112c72243a2d8f4a55010ecbd4b Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 28 Aug 2023 10:00:26 +0200 Subject: [PATCH 037/217] rustdoc: start new "Sections" section in the book with Aliased Type --- src/doc/rustdoc/src/how-to-read-rustdoc.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 9deb7009cfe00..cd6e29ffd6637 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -38,6 +38,22 @@ followed by a list of fields or variants for Rust types. Finally, the page lists associated functions and trait implementations, including automatic and blanket implementations that `rustdoc` knows about. +### Sections + + + + + + +#### Aliased Type + +A type alias is expanded at compile time to its +[aliased type](https://doc.rust-lang.org/reference/items/type-aliases.html). +That may involve substituting some or all of the type parameters in the target +type with types provided by the type alias definition. The Aliased Type section +shows the result of this expansion, including the types of public fields or +variants, which may depend on those substitutions. + ### Navigation Subheadings, variants, fields, and many other things in this documentation From b88dfcfcd50d6260130c1c719cda9bef990715eb Mon Sep 17 00:00:00 2001 From: Katherine Philip Date: Mon, 28 Aug 2023 12:40:39 -0700 Subject: [PATCH 038/217] Don't ICE on layout computation failure --- src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index 3081dcfa2b7a3..ec2da39398b2d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -480,7 +480,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { self.0.sess.span_fatal(span, err.to_string()) } else { - span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + self.0.sess.span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err)) } } } From 833592766f9e317e7166ffff1444ff70c6fdeda4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Aug 2023 18:12:34 +0200 Subject: [PATCH 039/217] const_eval and codegen: audit uses of is_zst --- src/unsize.rs | 4 +++- src/vtable.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/unsize.rs b/src/unsize.rs index 6aeba13f63949..c6133f2b35cf0 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -88,7 +88,8 @@ fn unsize_ptr<'tcx>( let src_f = src_layout.field(fx, i); assert_eq!(src_layout.fields.offset(i).bytes(), 0); assert_eq!(dst_layout.fields.offset(i).bytes(), 0); - if src_f.is_zst() { + if src_f.is_1zst() { + // We are looking for the one non-1-ZST field; this is not it. continue; } assert_eq!(src_layout.size, src_f.size); @@ -151,6 +152,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( let dst_f = dst.place_field(fx, FieldIdx::new(i)); if dst_f.layout().is_zst() { + // No data here, nothing to copy/coerce. continue; } diff --git a/src/vtable.rs b/src/vtable.rs index b309695c190f8..7598c6eee03ff 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -51,8 +51,8 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { for i in 0..arg.layout().fields.count() { let field = arg.value_field(fx, FieldIdx::new(i)); - if !field.layout().is_zst() { - // we found the one non-zero-sized field that is allowed + if !field.layout().is_1zst() { + // we found the one non-1-ZST field that is allowed // now find *its* non-zero-sized field, or stop if it's a // pointer arg = field; From e6dddbda35399c08c7940477c363002ab1d276da Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Tue, 8 Aug 2023 19:47:36 +0000 Subject: [PATCH 040/217] Preserve `___asan_globals_registered` symbol during LTO. Fixes https://github.com/rust-lang/rust/issues/113404 --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +++ .../address-sanitizer-globals-tracking.rs | 43 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 6af5c24c458a6..308c935edf9e2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1058,6 +1058,13 @@ extern "C" void LLVMRustPrintPasses() { extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, size_t Len) { auto PreserveFunctions = [=](const GlobalValue &GV) { + // Preserve LLVM-injected, ASAN-related symbols. + // See also https://github.com/rust-lang/rust/issues/113404. + if (GV.getName() == "___asan_globals_registered") { + return true; + } + + // Preserve symbols exported from Rust modules. for (size_t I = 0; I < Len; I++) { if (GV.getName() == Symbols[I]) { return true; diff --git a/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs new file mode 100644 index 0000000000000..a70ef7751b669 --- /dev/null +++ b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs @@ -0,0 +1,43 @@ +// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`. +// This is a regression test for https://github.com/rust-lang/rust/issues/113404 +// +// Notes about the `compile-flags` below: +// +// * The original issue only reproed with LTO - this is why this angle has +// extra test coverage via different `revisions` +// * To observe the failure/repro at LLVM-IR level we need to use `staticlib` +// which necessitates `-C prefer-dynamic=false` - without the latter flag, +// we would have run into "cannot prefer dynamic linking when performing LTO". +// +// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target +// specific. In particular, `___asan_globals_registered` is only used in the +// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths. The `only-linux` filter is +// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a +// linux-only regression test should be sufficient here. +// +// needs-sanitizer-address +// only-linux +// +// revisions:ASAN ASAN-FAT-LTO +//[ASAN] compile-flags: -Zsanitizer=address +//[ASAN-FAT-LTO] compile-flags: -Zsanitizer=address -Cprefer-dynamic=false -Clto=fat + +#![crate_type="staticlib"] + +// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which +// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly +// reported as an ODR violation in https://crbug.com/1459233#c1. Before this bug was fixed, +// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden +// global i64`. (The test expectations ignore the exact type because on `arm-android` the type +// is `i32` rather than `i64`.) +// +// CHECK: @___asan_globals_registered = common hidden global +// CHECK: @__start_asan_globals = extern_weak hidden global +// CHECK: @__stop_asan_globals = extern_weak hidden global +#[no_mangle] +pub static CACHED_POW10: [(u64, i16, i16); 4] = [ + (0xe61acf033d1a45df, -1087, -308), + (0xab70fe17c79ac6ca, -1060, -300), + (0xff77b1fcbebcdc4f, -1034, -292), + (0xbe5691ef416bd60c, -1007, -284), +]; From ecff1c012e9e78a0a85ece64a0823ef69fc56363 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 30 Aug 2023 14:19:53 +0100 Subject: [PATCH 041/217] test(ui/lint): demonstrate the current cmdline lint behavior This demonstrates the current behavior of adding lint form the command line. generally the lint levels are ignored as the current implementation unconditionally emit errors for those lints. --- tests/ui/lint/lint-removed-cmdline-deny.rs | 12 +++++++++ .../ui/lint/lint-removed-cmdline-deny.stderr | 27 +++++++++++++++++++ tests/ui/lint/lint-renamed-cmdline-deny.rs | 8 ++++++ .../ui/lint/lint-renamed-cmdline-deny.stderr | 27 +++++++++++++++++++ .../lint/lint-unknown-lint-cmdline-allow.rs | 3 +++ .../lint-unknown-lint-cmdline-allow.stderr | 21 +++++++++++++++ .../ui/lint/lint-unknown-lint-cmdline-deny.rs | 8 ++++++ .../lint-unknown-lint-cmdline-deny.stderr | 21 +++++++++++++++ 8 files changed, 127 insertions(+) create mode 100644 tests/ui/lint/lint-removed-cmdline-deny.rs create mode 100644 tests/ui/lint/lint-removed-cmdline-deny.stderr create mode 100644 tests/ui/lint/lint-renamed-cmdline-deny.rs create mode 100644 tests/ui/lint/lint-renamed-cmdline-deny.stderr create mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-allow.rs create mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr create mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-deny.rs create mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs new file mode 100644 index 0000000000000..82dce61869ba5 --- /dev/null +++ b/tests/ui/lint/lint-removed-cmdline-deny.rs @@ -0,0 +1,12 @@ +// The raw_pointer_derived lint warns about its removal +// cc #30346 + +// compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive + +// error-pattern:lint `raw_pointer_derive` has been removed +// error-pattern:requested on the command line with `-D raw_pointer_derive` + +#![warn(unused)] + +#[deny(warnings)] +fn main() { let unused = (); } diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr new file mode 100644 index 0000000000000..61bf9890d4925 --- /dev/null +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -0,0 +1,27 @@ +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + +error: unused variable: `unused` + --> $DIR/lint-removed-cmdline-deny.rs:12:17 + | +LL | fn main() { let unused = (); } + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` + | +note: the lint level is defined here + --> $DIR/lint-removed-cmdline-deny.rs:11:8 + | +LL | #[deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to previous error; 3 warnings emitted + diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs new file mode 100644 index 0000000000000..f313ffd425441 --- /dev/null +++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs @@ -0,0 +1,8 @@ +// compile-flags:-D renamed-and-removed-lints -D bare_trait_object + +// error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects` +// error-pattern:requested on the command line with `-D bare_trait_object` +// error-pattern:unused + +#[deny(unused)] +fn main() { let unused = (); } diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr new file mode 100644 index 0000000000000..2b360e5f3d8eb --- /dev/null +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -0,0 +1,27 @@ +warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = note: requested on the command line with `-D bare_trait_object` + +warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = note: requested on the command line with `-D bare_trait_object` + +warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = note: requested on the command line with `-D bare_trait_object` + +error: unused variable: `unused` + --> $DIR/lint-renamed-cmdline-deny.rs:8:17 + | +LL | fn main() { let unused = (); } + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` + | +note: the lint level is defined here + --> $DIR/lint-renamed-cmdline-deny.rs:7:8 + | +LL | #[deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: aborting due to previous error; 3 warnings emitted + diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs new file mode 100644 index 0000000000000..7549d076710da --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs @@ -0,0 +1,3 @@ +// compile-flags:-A unknown-lints -D bogus -D dead_cod + +fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr new file mode 100644 index 0000000000000..3855d55279291 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr @@ -0,0 +1,21 @@ +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs new file mode 100644 index 0000000000000..461984239a8b3 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs @@ -0,0 +1,8 @@ +// compile-flags:-D unknown-lints -D bogus -D dead_cod + +// error-pattern:unknown lint: `bogus` +// error-pattern:requested on the command line with `-D bogus` +// error-pattern:requested on the command line with `-D dead_cod` +// error-pattern:did you mean: `dead_code` + +fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr new file mode 100644 index 0000000000000..3855d55279291 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr @@ -0,0 +1,21 @@ +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0602`. From cdbad43aba4805ca67de043dd74f617ce5f982a4 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 28 Aug 2023 19:16:54 +0100 Subject: [PATCH 042/217] refactor(rustc_lint): inline `check_lint_name_cmdline` --- compiler/rustc_lint/src/context.rs | 67 ------------------------------ compiler/rustc_lint/src/levels.rs | 63 +++++++++++++++++++++++++++- compiler/rustc_lint/src/tests.rs | 2 +- 3 files changed, 62 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 9dfde84b55263..7a336a8f69474 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,10 +16,6 @@ use self::TargetLint::*; -use crate::errors::{ - CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown, - CheckNameUnknownTool, RequestedLevel, UnsupportedGroup, -}; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; @@ -330,58 +326,6 @@ impl LintStore { } } - /// Checks the validity of lint names derived from the command line. - pub fn check_lint_name_cmdline( - &self, - sess: &Session, - lint_name: &str, - level: Level, - registered_tools: &RegisteredTools, - ) { - let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); - if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { - sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); - return; - } - match self.check_lint_name(lint_name_only, tool_name, registered_tools) { - CheckLintNameResult::Renamed(replace) => { - sess.emit_warning(CheckNameRenamed { - lint_name, - replace: &replace, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::Removed(reason) => { - sess.emit_warning(CheckNameRemoved { - lint_name, - reason: &reason, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::NoLint(suggestion) => { - sess.emit_err(CheckNameUnknown { - lint_name, - suggestion, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::Tool(Err((Some(_), new_name))) => { - sess.emit_warning(CheckNameDeprecated { - lint_name, - new_name: &new_name, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::NoTool => { - sess.emit_err(CheckNameUnknownTool { - tool_name: tool_name.unwrap(), - sub: RequestedLevel { level, lint_name }, - }); - } - _ => {} - }; - } - /// True if this symbol represents a lint group name. pub fn is_lint_group(&self, lint_name: Symbol) -> bool { debug!( @@ -1402,14 +1346,3 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> { err } } - -pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option, &str) { - match lint_name.split_once("::") { - Some((tool_name, lint_name)) => { - let tool_name = Symbol::intern(tool_name); - - (Some(tool_name), lint_name) - } - None => (None, lint_name), - } -} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f58782c0f2244..13419ae05da90 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,3 +1,7 @@ +use crate::errors::{ + CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown, + CheckNameUnknownTool, RequestedLevel, UnsupportedGroup, +}; use crate::{ builtin::MISSING_DOCS, context::{CheckLintNameResult, LintStore}, @@ -552,12 +556,56 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { fn add_command_line(&mut self) { for &(ref lint_name, level) in &self.sess.opts.lint_opts { - self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools); + // Checks the validity of lint names derived from the command line. + let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); + if lint_name_only == crate::WARNINGS.name_lower() + && matches!(level, Level::ForceWarn(_)) + { + self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); + } + match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) { + CheckLintNameResult::Renamed(replace) => { + self.sess.emit_warning(CheckNameRenamed { + lint_name, + replace: &replace, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::Removed(reason) => { + self.sess.emit_warning(CheckNameRemoved { + lint_name, + reason: &reason, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::NoLint(suggestion) => { + self.sess.emit_err(CheckNameUnknown { + lint_name, + suggestion, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::Tool(Err((Some(_), new_name))) => { + self.sess.emit_warning(CheckNameDeprecated { + lint_name, + new_name: &new_name, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::NoTool => { + self.sess.emit_err(CheckNameUnknownTool { + tool_name: tool_name.unwrap(), + sub: RequestedLevel { level, lint_name }, + }); + } + _ => {} + }; + let orig_level = level; let lint_flag_val = Symbol::intern(lint_name); let Ok(ids) = self.store.find_lints(&lint_name) else { - // errors handled in check_lint_name_cmdline above + // errors already handled above continue; }; for id in ids { @@ -1092,3 +1140,14 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers }; } + +pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option, &str) { + match lint_name.split_once("::") { + Some((tool_name, lint_name)) => { + let tool_name = Symbol::intern(tool_name); + + (Some(tool_name), lint_name) + } + None => (None, lint_name), + } +} diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs index fc9d6f636b214..4fd054cb7179f 100644 --- a/compiler/rustc_lint/src/tests.rs +++ b/compiler/rustc_lint/src/tests.rs @@ -1,4 +1,4 @@ -use crate::context::parse_lint_and_tool_name; +use crate::levels::parse_lint_and_tool_name; use rustc_span::{create_default_session_globals_then, Symbol}; #[test] From a11805ae46b23d1cc80f7332417cb809ff1c6d64 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 28 Aug 2023 20:28:51 +0100 Subject: [PATCH 043/217] feat(rustc_lint): make `CheckLintName` respect lint level --- compiler/rustc_lint/messages.ftl | 11 +-- compiler/rustc_lint/src/errors.rs | 54 +----------- compiler/rustc_lint/src/levels.rs | 84 +++++++++---------- compiler/rustc_lint/src/lints.rs | 68 ++++++++++++--- .../plugin/lint-tool-cmdline-allow.stderr | 10 ++- tests/ui/error-codes/E0602.rs | 2 + tests/ui/error-codes/E0602.stderr | 11 ++- tests/ui/lint/cli-unknown-force-warn.rs | 6 +- tests/ui/lint/cli-unknown-force-warn.stderr | 11 ++- tests/ui/lint/lint-removed-cmdline-deny.rs | 1 + .../ui/lint/lint-removed-cmdline-deny.stderr | 13 +-- tests/ui/lint/lint-removed-cmdline.rs | 1 + tests/ui/lint/lint-removed-cmdline.stderr | 5 +- tests/ui/lint/lint-renamed-cmdline-deny.rs | 2 + .../ui/lint/lint-renamed-cmdline-deny.stderr | 16 ++-- tests/ui/lint/lint-renamed-cmdline.rs | 1 + tests/ui/lint/lint-renamed-cmdline.stderr | 8 +- .../ui/lint/lint-unexported-no-mangle.stderr | 1 + .../lint/lint-unknown-lint-cmdline-allow.rs | 1 + .../lint-unknown-lint-cmdline-allow.stderr | 21 ----- .../ui/lint/lint-unknown-lint-cmdline-deny.rs | 1 + .../lint-unknown-lint-cmdline-deny.stderr | 12 ++- tests/ui/lint/lint-unknown-lint-cmdline.rs | 2 + .../ui/lint/lint-unknown-lint-cmdline.stderr | 20 +++-- 24 files changed, 191 insertions(+), 171 deletions(-) delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7f7f36ca170dd..ba50c9e00e3f8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -156,15 +156,6 @@ lint_builtin_unused_doc_comment = unused doc comment lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` -lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} - -lint_check_name_removed = lint `{$lint_name}` has been removed: {$reason} - -lint_check_name_renamed = lint `{$lint_name}` has been renamed to `{$replace}` - -lint_check_name_unknown = unknown lint: `{$lint_name}` - .help = did you mean: `{$suggestion}` - lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` lint_command_line_source = `forbid` lint level was set on command line @@ -187,6 +178,7 @@ lint_default_source = `forbid` lint level is the default for {$id} lint_deprecated_lint_name = lint name `{$name}` is deprecated and may not have an effect in the future. .suggestion = change it to + .help = change it to {$replace} lint_diag_out_of_impl = diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls @@ -528,6 +520,7 @@ lint_unknown_gated_lint = lint_unknown_lint = unknown lint: `{$name}` .suggestion = did you mean + .help = did you mean: `{$replace}` lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` .help = add `#![register_tool({$tool_name})]` to the crate root diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 607875b3faa2f..eccea35c702e0 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,7 +1,5 @@ use crate::fluent_generated as fluent; -use rustc_errors::{ - AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage, -}; +use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -102,29 +100,6 @@ pub struct UnsupportedGroup { pub lint_group: String, } -pub struct CheckNameUnknown<'a> { - pub lint_name: &'a str, - pub suggestion: Option, - pub sub: RequestedLevel<'a>, -} - -impl IntoDiagnostic<'_> for CheckNameUnknown<'_> { - fn into_diagnostic( - self, - handler: &Handler, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::lint_check_name_unknown); - diag.code(rustc_errors::error_code!(E0602)); - if let Some(suggestion) = self.suggestion { - diag.help(fluent::lint_help); - diag.set_arg("suggestion", suggestion); - } - diag.set_arg("lint_name", self.lint_name); - diag.subdiagnostic(self.sub); - diag - } -} - #[derive(Diagnostic)] #[diag(lint_check_name_unknown_tool, code = "E0602")] pub struct CheckNameUnknownTool<'a> { @@ -132,30 +107,3 @@ pub struct CheckNameUnknownTool<'a> { #[subdiagnostic] pub sub: RequestedLevel<'a>, } - -#[derive(Diagnostic)] -#[diag(lint_check_name_renamed)] -pub struct CheckNameRenamed<'a> { - pub lint_name: &'a str, - pub replace: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} - -#[derive(Diagnostic)] -#[diag(lint_check_name_removed)] -pub struct CheckNameRemoved<'a> { - pub lint_name: &'a str, - pub reason: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} - -#[derive(Diagnostic)] -#[diag(lint_check_name_deprecated)] -pub struct CheckNameDeprecated<'a> { - pub lint_name: &'a str, - pub new_name: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 13419ae05da90..df67cf5d12ff9 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,6 +1,7 @@ -use crate::errors::{ - CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown, - CheckNameUnknownTool, RequestedLevel, UnsupportedGroup, +use crate::errors::{CheckNameUnknownTool, RequestedLevel, UnsupportedGroup}; +use crate::lints::{ + DeprecatedLintNameFromCommandLine, RemovedLintFromCommandLine, RenamedLintFromCommandLine, + UnknownLintFromCommandLine, }; use crate::{ builtin::MISSING_DOCS, @@ -564,33 +565,32 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); } match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) { - CheckLintNameResult::Renamed(replace) => { - self.sess.emit_warning(CheckNameRenamed { - lint_name, - replace: &replace, - sub: RequestedLevel { level, lint_name }, - }); + CheckLintNameResult::Renamed(ref replace) => { + let name = lint_name.as_str(); + let suggestion = RenamedLintSuggestion::WithoutSpan { replace }; + let requested_level = RequestedLevel { level, lint_name }; + let lint = RenamedLintFromCommandLine { name, suggestion, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); } - CheckLintNameResult::Removed(reason) => { - self.sess.emit_warning(CheckNameRemoved { - lint_name, - reason: &reason, - sub: RequestedLevel { level, lint_name }, - }); + CheckLintNameResult::Removed(ref reason) => { + let name = lint_name.as_str(); + let requested_level = RequestedLevel { level, lint_name }; + let lint = RemovedLintFromCommandLine { name, reason, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); } CheckLintNameResult::NoLint(suggestion) => { - self.sess.emit_err(CheckNameUnknown { - lint_name, - suggestion, - sub: RequestedLevel { level, lint_name }, - }); + let name = lint_name.clone(); + let suggestion = + suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace }); + let requested_level = RequestedLevel { level, lint_name }; + let lint = UnknownLintFromCommandLine { name, suggestion, requested_level }; + self.emit_lint(UNKNOWN_LINTS, lint); } - CheckLintNameResult::Tool(Err((Some(_), new_name))) => { - self.sess.emit_warning(CheckNameDeprecated { - lint_name, - new_name: &new_name, - sub: RequestedLevel { level, lint_name }, - }); + CheckLintNameResult::Tool(Err((Some(_), ref replace))) => { + let name = lint_name.clone(); + let requested_level = RequestedLevel { level, lint_name }; + let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); } CheckLintNameResult::NoTool => { self.sess.emit_err(CheckNameUnknownTool { @@ -963,24 +963,18 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { _ if !self.warn_about_weird_lints => {} - CheckLintNameResult::Renamed(new_name) => { + CheckLintNameResult::Renamed(ref replace) => { let suggestion = - RenamedLintSuggestion { suggestion: sp, replace: new_name.as_str() }; + RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - self.emit_spanned_lint( - RENAMED_AND_REMOVED_LINTS, - sp.into(), - RenamedLint { name: name.as_str(), suggestion }, - ); + let lint = RenamedLint { name: name.as_str(), suggestion }; + self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } - CheckLintNameResult::Removed(reason) => { + CheckLintNameResult::Removed(ref reason) => { let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - self.emit_spanned_lint( - RENAMED_AND_REMOVED_LINTS, - sp.into(), - RemovedLint { name: name.as_str(), reason: reason.as_str() }, - ); + let lint = RemovedLint { name: name.as_str(), reason }; + self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } CheckLintNameResult::NoLint(suggestion) => { @@ -989,13 +983,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } else { name.to_string() }; - let suggestion = suggestion - .map(|replace| UnknownLintSuggestion { suggestion: sp, replace }); - self.emit_spanned_lint( - UNKNOWN_LINTS, - sp.into(), - UnknownLint { name, suggestion }, - ); + let suggestion = suggestion.map(|replace| { + UnknownLintSuggestion::WithSpan { suggestion: sp, replace } + }); + let lint = UnknownLint { name, suggestion }; + self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint); } } // If this lint was renamed, apply the new lint instead of ignoring the attribute. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0e942d774a7fe..3e26d6dc32d40 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,6 +2,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] use std::num::NonZeroU32; +use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString, @@ -1012,6 +1013,16 @@ pub struct DeprecatedLintName<'a> { pub replace: &'a str, } +#[derive(LintDiagnostic)] +#[diag(lint_deprecated_lint_name)] +#[help] +pub struct DeprecatedLintNameFromCommandLine<'a> { + pub name: String, + pub replace: &'a str, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, +} + #[derive(LintDiagnostic)] #[diag(lint_renamed_lint)] pub struct RenamedLint<'a> { @@ -1021,11 +1032,25 @@ pub struct RenamedLint<'a> { } #[derive(Subdiagnostic)] -#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] -pub struct RenamedLintSuggestion<'a> { - #[primary_span] - pub suggestion: Span, - pub replace: &'a str, +pub enum RenamedLintSuggestion<'a> { + #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] + WithSpan { + #[primary_span] + suggestion: Span, + replace: &'a str, + }, + #[help(lint_help)] + WithoutSpan { replace: &'a str }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_renamed_lint)] +pub struct RenamedLintFromCommandLine<'a> { + pub name: &'a str, + #[subdiagnostic] + pub suggestion: RenamedLintSuggestion<'a>, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, } #[derive(LintDiagnostic)] @@ -1035,6 +1060,15 @@ pub struct RemovedLint<'a> { pub reason: &'a str, } +#[derive(LintDiagnostic)] +#[diag(lint_removed_lint)] +pub struct RemovedLintFromCommandLine<'a> { + pub name: &'a str, + pub reason: &'a str, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, +} + #[derive(LintDiagnostic)] #[diag(lint_unknown_lint)] pub struct UnknownLint { @@ -1044,11 +1078,25 @@ pub struct UnknownLint { } #[derive(Subdiagnostic)] -#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] -pub struct UnknownLintSuggestion { - #[primary_span] - pub suggestion: Span, - pub replace: Symbol, +pub enum UnknownLintSuggestion { + #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] + WithSpan { + #[primary_span] + suggestion: Span, + replace: Symbol, + }, + #[help(lint_help)] + WithoutSpan { replace: Symbol }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unknown_lint, code = "E0602")] +pub struct UnknownLintFromCommandLine<'a> { + pub name: String, + #[subdiagnostic] + pub suggestion: Option, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, } #[derive(LintDiagnostic)] diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr index b060e3a3e38b4..0e66179599989 100644 --- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr +++ b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr @@ -1,9 +1,12 @@ -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` + = note: `#[warn(renamed_and_removed_lints)]` on by default -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` warning: item is named 'lintme' @@ -22,8 +25,9 @@ LL | #![plugin(lint_tool_test)] | = note: `#[warn(deprecated)]` on by default -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` warning: 5 warnings emitted diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs index 8fadce526d9aa..77d28838a10c2 100644 --- a/tests/ui/error-codes/E0602.rs +++ b/tests/ui/error-codes/E0602.rs @@ -1,6 +1,8 @@ // compile-flags:-D bogus +// check-pass // error-pattern:E0602 // error-pattern:requested on the command line with `-D bogus` +// error-pattern:`#[warn(unknown_lints)]` on by default fn main() {} diff --git a/tests/ui/error-codes/E0602.stderr b/tests/ui/error-codes/E0602.stderr index 2b37226334586..60ecec7cdd7c5 100644 --- a/tests/ui/error-codes/E0602.stderr +++ b/tests/ui/error-codes/E0602.stderr @@ -1,11 +1,16 @@ -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` -error: aborting due to 2 previous errors +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +warning: 3 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs index f3dea87a6b69a..a9e4e4a60179e 100644 --- a/tests/ui/lint/cli-unknown-force-warn.rs +++ b/tests/ui/lint/cli-unknown-force-warn.rs @@ -1,7 +1,11 @@ // Checks that rustc correctly errors when passed an invalid lint with // `--force-warn`. This is a regression test for issue #86958. -// + +// check-pass // compile-flags: --force-warn foo-qux + // error-pattern: unknown lint: `foo_qux` +// error-pattern: requested on the command line with `--force-warn foo_qux` +// error-pattern: `#[warn(unknown_lints)]` on by default fn main() {} diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/cli-unknown-force-warn.stderr index 9ce9f405aee69..2ee718a8c8e11 100644 --- a/tests/ui/lint/cli-unknown-force-warn.stderr +++ b/tests/ui/lint/cli-unknown-force-warn.stderr @@ -1,11 +1,16 @@ -error[E0602]: unknown lint: `foo_qux` +warning[E0602]: unknown lint: `foo_qux` | = note: requested on the command line with `--force-warn foo_qux` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `foo_qux` +warning[E0602]: unknown lint: `foo_qux` | = note: requested on the command line with `--force-warn foo_qux` -error: aborting due to 2 previous errors +warning[E0602]: unknown lint: `foo_qux` + | + = note: requested on the command line with `--force-warn foo_qux` + +warning: 3 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs index 82dce61869ba5..8cf91cf60eb1d 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.rs +++ b/tests/ui/lint/lint-removed-cmdline-deny.rs @@ -5,6 +5,7 @@ // error-pattern:lint `raw_pointer_derive` has been removed // error-pattern:requested on the command line with `-D raw_pointer_derive` +// error-pattern:requested on the command line with `-D renamed-and-removed-lints` #![warn(unused)] diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr index 61bf9890d4925..80c85d01e53c0 100644 --- a/tests/ui/lint/lint-removed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -1,27 +1,28 @@ -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | = note: requested on the command line with `-D raw_pointer_derive` + = note: requested on the command line with `-D renamed-and-removed-lints` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | = note: requested on the command line with `-D raw_pointer_derive` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | = note: requested on the command line with `-D raw_pointer_derive` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline-deny.rs:12:17 + --> $DIR/lint-removed-cmdline-deny.rs:13:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline-deny.rs:11:8 + --> $DIR/lint-removed-cmdline-deny.rs:12:8 | LL | #[deny(warnings)] | ^^^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` -error: aborting due to previous error; 3 warnings emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs index 462beabb9451c..34373df3a9c62 100644 --- a/tests/ui/lint/lint-removed-cmdline.rs +++ b/tests/ui/lint/lint-removed-cmdline.rs @@ -4,6 +4,7 @@ // compile-flags:-D raw_pointer_derive // error-pattern:lint `raw_pointer_derive` has been removed +// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default // error-pattern:requested on the command line with `-D raw_pointer_derive` #![warn(unused)] diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr index 9be532ef234d1..ebfae34ade92f 100644 --- a/tests/ui/lint/lint-removed-cmdline.stderr +++ b/tests/ui/lint/lint-removed-cmdline.stderr @@ -1,6 +1,7 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | = note: requested on the command line with `-D raw_pointer_derive` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | @@ -11,13 +12,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point = note: requested on the command line with `-D raw_pointer_derive` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline.rs:12:17 + --> $DIR/lint-removed-cmdline.rs:13:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline.rs:11:8 + --> $DIR/lint-removed-cmdline.rs:12:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs index f313ffd425441..01629aaca80d4 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.rs +++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs @@ -1,7 +1,9 @@ // compile-flags:-D renamed-and-removed-lints -D bare_trait_object // error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects` +// error-pattern:use the new name `bare_trait_objects` // error-pattern:requested on the command line with `-D bare_trait_object` +// error-pattern:requested on the command line with `-D renamed-and-removed-lints` // error-pattern:unused #[deny(unused)] diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr index 2b360e5f3d8eb..df22ef60daf13 100644 --- a/tests/ui/lint/lint-renamed-cmdline-deny.stderr +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -1,27 +1,31 @@ -warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` + = note: requested on the command line with `-D renamed-and-removed-lints` -warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` -warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline-deny.rs:8:17 + --> $DIR/lint-renamed-cmdline-deny.rs:10:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline-deny.rs:7:8 + --> $DIR/lint-renamed-cmdline-deny.rs:9:8 | LL | #[deny(unused)] | ^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` -error: aborting due to previous error; 3 warnings emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs index c873771e3081c..fba7c33311df4 100644 --- a/tests/ui/lint/lint-renamed-cmdline.rs +++ b/tests/ui/lint/lint-renamed-cmdline.rs @@ -2,6 +2,7 @@ // error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects` // error-pattern:requested on the command line with `-D bare_trait_object` +// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default // error-pattern:unused #[deny(unused)] diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr index 8dfd61ac927a9..a41284003ed64 100644 --- a/tests/ui/lint/lint-renamed-cmdline.stderr +++ b/tests/ui/lint/lint-renamed-cmdline.stderr @@ -1,23 +1,27 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline.rs:8:17 + --> $DIR/lint-renamed-cmdline.rs:9:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline.rs:7:8 + --> $DIR/lint-renamed-cmdline.rs:8:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr index a11ee769c7c18..858527822220a 100644 --- a/tests/ui/lint/lint-unexported-no-mangle.stderr +++ b/tests/ui/lint/lint-unexported-no-mangle.stderr @@ -1,6 +1,7 @@ warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported | = note: requested on the command line with `-F private_no_mangle_fns` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported | diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs index 7549d076710da..c7f8d434c0401 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs @@ -1,3 +1,4 @@ +// check-pass // compile-flags:-A unknown-lints -D bogus -D dead_cod fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr deleted file mode 100644 index 3855d55279291..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline-allow.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs index 461984239a8b3..31bc204735664 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs @@ -3,6 +3,7 @@ // error-pattern:unknown lint: `bogus` // error-pattern:requested on the command line with `-D bogus` // error-pattern:requested on the command line with `-D dead_cod` +// error-pattern:requested on the command line with `-D unknown-lints` // error-pattern:did you mean: `dead_code` fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr index 3855d55279291..677b5edc894b3 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr @@ -1,6 +1,7 @@ error[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` + = note: requested on the command line with `-D unknown-lints` error[E0602]: unknown lint: `dead_cod` | @@ -16,6 +17,15 @@ error[E0602]: unknown lint: `dead_cod` = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error: aborting due to 4 previous errors +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs index 7f3f55fbad0f4..81539cb6dc15a 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs @@ -1,7 +1,9 @@ +// check-pass // compile-flags:-D bogus -D dead_cod // error-pattern:unknown lint: `bogus` // error-pattern:requested on the command line with `-D bogus` +// error-pattern:`#[warn(unknown_lints)]` on by default // error-pattern:unknown lint: `dead_cod` // error-pattern:requested on the command line with `-D dead_cod` // error-pattern:did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr index 3855d55279291..10db76ac4f16b 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr +++ b/tests/ui/lint/lint-unknown-lint-cmdline.stderr @@ -1,21 +1,31 @@ -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `dead_cod` +warning[E0602]: unknown lint: `dead_cod` | = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` -error[E0602]: unknown lint: `dead_cod` +warning[E0602]: unknown lint: `dead_cod` | = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error: aborting due to 4 previous errors +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +warning[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +warning: 6 warnings emitted For more information about this error, try `rustc --explain E0602`. From a756bae8cae1a5eb3da9d956f162f7b040260203 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:55:18 +0000 Subject: [PATCH 044/217] Rustup to rustc 1.74.0-nightly (2f5df8a94 2023-08-31) --- patches/stdlib-lock.toml | 12 ++++++------ rust-toolchain | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/patches/stdlib-lock.toml b/patches/stdlib-lock.toml index fa175edcae60f..5b79d6569bb01 100644 --- a/patches/stdlib-lock.toml +++ b/patches/stdlib-lock.toml @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "compiler_builtins", "gimli", @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "compiler_builtins", "memchr", diff --git a/rust-toolchain b/rust-toolchain index 5689bdee64d26..39e348f37f3cf 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-08-08" +channel = "nightly-2023-09-01" components = ["rust-src", "rustc-dev", "llvm-tools"] From 0559de65672243a97d6cd6e6ee6a8e8c291ef4ce Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 1 Sep 2023 13:08:16 +0000 Subject: [PATCH 045/217] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index c163b8543848d..3fc462a39cc21 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -45,6 +45,7 @@ rm tests/ui/proc-macro/quote-debug.rs rm tests/ui/proc-macro/no-missing-docs.rs rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs rm tests/ui/proc-macro/allowed-signatures.rs +rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs # vendor intrinsics rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected @@ -114,6 +115,7 @@ rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/layout/valid_range_oob.rs # different ICE message +rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif rm tests/ui/consts/issue-miri-1910.rs # different error message rm tests/ui/consts/offset_ub.rs # same From b8e0e797e701f60bd975b3f8a295e1cb1a1de58c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Sep 2023 17:04:44 +0200 Subject: [PATCH 046/217] bootstrap/format: remove unnecessary paths.push --- src/bootstrap/format.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index d658be0b8eb1c..11f2762f76663 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -127,8 +127,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { Err(_) => false, }; - let mut paths = paths.to_vec(); - if git_available { let in_working_tree = match build .config @@ -201,8 +199,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { "WARN: Something went wrong when running git commands:\n{err}\n\ Falling back to formatting all files." ); - // Something went wrong when getting the version. Just format all the files. - paths.push(".".into()); } } } From 7abfc57ea19ebb2dd322655f6bdda1ce9f60af78 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Fri, 1 Sep 2023 16:04:41 -0400 Subject: [PATCH 047/217] stabilize `io_error_other` feature --- library/std/src/io/error.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index d6fce4ee78f5e..1c5c60494f351 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -527,8 +527,6 @@ impl Error { /// # Examples /// /// ``` - /// #![feature(io_error_other)] - /// /// use std::io::Error; /// /// // errors can be created from strings @@ -537,7 +535,7 @@ impl Error { /// // errors can also be created from other errors /// let custom_error2 = Error::other(custom_error); /// ``` - #[unstable(feature = "io_error_other", issue = "91946")] + #[stable(feature = "io_error_other", since = "CURRENT_RUSTC_VERSION")] pub fn other(error: E) -> Error where E: Into>, From 4160337c8553e1083b12632eed7a94e51d57ea91 Mon Sep 17 00:00:00 2001 From: David Mo Date: Fri, 1 Sep 2023 10:53:50 -0700 Subject: [PATCH 048/217] Tests crash from inappropriate use of common linkage Normally, variables with common linkage must be zero-initialized. In Rust, common linkage variables that are not zero-initialized causes a crash in the compiler backend. This commit adds a test case to confirm this behavior, which will inform us if it changes in the future. --- .../linkage-attr/common-linkage-non-zero-init.rs | 14 ++++++++++++++ .../common-linkage-non-zero-init.stderr | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 tests/ui/linkage-attr/common-linkage-non-zero-init.rs create mode 100644 tests/ui/linkage-attr/common-linkage-non-zero-init.stderr diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs new file mode 100644 index 0000000000000..ce8d9848e4250 --- /dev/null +++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs @@ -0,0 +1,14 @@ +// build-fail +// failure-status: 101 +// known-bug: #109681 + +// This test verifies that we continue to hit the LLVM error for common linkage with non-zero +// initializers, since it generates invalid LLVM IR. +// Linkages are internal features marked as perma-unstable, so we don't need to fix the issue +// for now. +#![crate_type="lib"] +#![feature(linkage)] + +#[linkage = "common"] +#[no_mangle] +pub static TEST: bool = true; diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr new file mode 100644 index 0000000000000..667bb3ec130ed --- /dev/null +++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr @@ -0,0 +1,3 @@ +'common' global must have a zero initializer! +ptr @TEST +LLVM ERROR: Broken module found, compilation aborted! From 06890774ab4f4f494be55fd6fe1097636fbea7c1 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Fri, 1 Sep 2023 14:27:21 -0700 Subject: [PATCH 049/217] Deduplicate inlined function debug info, but create a new lexical scope to child subsequent scopes and variables from colliding --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 2 +- .../src/debuginfo/create_scope_map.rs | 32 +++++++++++-------- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 8 +++-- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 9 ++++-- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 2 +- .../debuginfo-inline-callsite-location.rs | 28 ++++++++++++++++ 7 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 tests/codegen/debuginfo-inline-callsite-location.rs diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index a81585d412846..d1bfd833cd87f 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>, - ) -> Option> { + ) -> Option> { // TODO(antoyo) None } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index d174a3593b999..09131a7159c5d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, - debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, ) { // Find all scopes with variables defined in them. let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { @@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>( instance: Instance<'tcx>, mir: &Body<'tcx>, variables: &Option>, - debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, instantiated: &mut BitSet, scope: SourceScope, ) { @@ -86,7 +86,7 @@ fn make_mir_scope<'ll, 'tcx>( let loc = cx.lookup_debug_loc(scope_data.span.lo()); let file_metadata = file_metadata(cx, &loc.file); - let dbg_scope = match scope_data.inlined { + let parent_dbg_scope = match scope_data.inlined { Some((callee, _)) => { // FIXME(eddyb) this would be `self.monomorphize(&callee)` // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. @@ -95,18 +95,22 @@ fn make_mir_scope<'ll, 'tcx>( ty::ParamEnv::reveal_all(), ty::EarlyBinder::bind(callee), ); - let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); - cx.dbg_scope_fn(callee, callee_fn_abi, None) + debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { + let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); + cx.dbg_scope_fn(callee, callee_fn_abi, None) + }) } - None => unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.dbg_scope, - file_metadata, - loc.line, - loc.col, - ) - }, + None => parent_scope.dbg_scope, + }; + + let dbg_scope = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_dbg_scope, + file_metadata, + loc.line, + loc.col, + ) }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 40714a0afe91c..82235521f80b8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -292,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: &'ll Value, mir: &mir::Body<'tcx>, - ) -> Option> { + ) -> Option> { if self.sess().opts.debuginfo == DebugInfo::None { return None; } @@ -304,8 +304,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_start_pos: BytePos(0), file_end_pos: BytePos(0), }; - let mut fn_debug_context = - FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) }; + let mut fn_debug_context = FunctionDebugContext { + scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), + inlined_function_scopes: Default::default(), + }; // Fill in all the scopes, with the information from the MIR body. compute_mir_scopes(self, instance, mir, &mut fn_debug_context); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 526c16a59ded0..68050bc7a12bc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,10 +1,12 @@ use crate::traits::*; +use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::Instance; use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; @@ -17,10 +19,13 @@ use super::{FunctionCx, LocalRef}; use std::ops::Range; -pub struct FunctionDebugContext { +pub struct FunctionDebugContext<'tcx, S, L> { + /// Maps from source code to the corresponding debug info scope. pub scopes: IndexVec>, -} + /// Maps from an inlined function to its debug info declaration. + pub inlined_function_scopes: FxHashMap, S>, +} #[derive(Copy, Clone)] pub enum VariableKind { ArgumentVariable(usize /*index*/), diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index bf937c2fc7c81..c4408f2db4ced 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { mir: &'tcx mir::Body<'tcx>, - debug_context: Option>, + debug_context: Option>, llfn: Bx::Function, diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 63fecaf34fd5b..4acc0ea076c13 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Function, mir: &mir::Body<'tcx>, - ) -> Option>; + ) -> Option>; // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs new file mode 100644 index 0000000000000..b1475ee793160 --- /dev/null +++ b/tests/codegen/debuginfo-inline-callsite-location.rs @@ -0,0 +1,28 @@ +// compile-flags: -g -O + +// Check that each inline call site for the same function uses the same "sub-program" so that LLVM +// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail +// calls to panic. + +// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK-SAME: !dbg ![[#first_dbg:]] +// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK-SAME: !dbg ![[#second_dbg:]] + +// CHECK-DAG: ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap" +// CHECK-DAG: ![[#first_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]], +// CHECK: ![[#second_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]], +// CHECK: ![[#first_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#first_scope]], inlinedAt: ![[#]]) +// CHECK: ![[#second_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#second_scope]], inlinedAt: ![[#]]) + +#![crate_type = "lib"] + +#[no_mangle] +extern "C" fn add_numbers(x: &Option, y: &Option) -> i32 { + let x1 = x.unwrap(); + let y1 = y.unwrap(); + + x1 + y1 +} From 0c96a9260b75b97e5ce87d77b68d222ae4a3d988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 31 Aug 2023 09:16:33 +0200 Subject: [PATCH 050/217] Add `Freeze` type and use it to store `Definitions` --- compiler/rustc_data_structures/src/sync.rs | 3 + .../rustc_data_structures/src/sync/freeze.rs | 104 ++++++++++++++++++ compiler/rustc_interface/src/queries.rs | 4 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 20 ++-- compiler/rustc_session/src/cstore.rs | 4 +- 6 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 compiler/rustc_data_structures/src/sync/freeze.rs diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index e82b0f6d49673..a8f42e0ed0e25 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -61,6 +61,9 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; +mod freeze; +pub use freeze::{Freeze, FreezeReadGuard, FreezeWriteGuard}; + mod mode { use super::Ordering; use std::sync::atomic::AtomicU8; diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs new file mode 100644 index 0000000000000..77b37af526940 --- /dev/null +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -0,0 +1,104 @@ +use crate::sync::{AtomicBool, Lock, LockGuard}; +#[cfg(parallel_compiler)] +use crate::sync::{DynSend, DynSync}; +use std::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, + sync::atomic::Ordering, +}; + +/// A type which allows mutation using a lock until +/// the value is frozen and can be accessed lock-free. +#[derive(Default)] +pub struct Freeze { + data: UnsafeCell, + frozen: AtomicBool, + lock: Lock<()>, +} + +#[cfg(parallel_compiler)] +unsafe impl DynSync for Freeze {} + +impl Freeze { + #[inline] + pub fn new(value: T) -> Self { + Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: Lock::new(()) } + } + + #[inline] + pub fn read(&self) -> FreezeReadGuard<'_, T> { + FreezeReadGuard { + _lock_guard: if self.frozen.load(Ordering::Acquire) { + None + } else { + Some(self.lock.lock()) + }, + // SAFETY: If this is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so + // this has shared access until the `FreezeReadGuard` is dropped. If this is frozen, + // the data cannot be modified and shared access is sound. + data: unsafe { &*self.data.get() }, + } + } + + #[inline] + #[track_caller] + pub fn write(&self) -> FreezeWriteGuard<'_, T> { + let _lock_guard = self.lock.lock(); + assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); + FreezeWriteGuard { + _lock_guard, + // SAFETY: `_lock_guard` holds the lock to the `UnsafeCell` so this has mutable access + // until the `FreezeWriteGuard` is dropped. + data: unsafe { &mut *self.data.get() }, + } + } + + #[inline] + pub fn freeze(&self) -> &T { + if !self.frozen.load(Ordering::Acquire) { + // Get the lock to ensure no concurrent writes. + let _lock = self.lock.lock(); + self.frozen.store(true, Ordering::Release); + } + + // SAFETY: This is frozen so the data cannot be modified and shared access is sound. + unsafe { &*self.data.get() } + } +} + +/// A guard holding shared access to a `Freeze` which is in a locked state or frozen. +#[must_use = "if unused the Freeze may immediately unlock"] +pub struct FreezeReadGuard<'a, T> { + _lock_guard: Option>, + data: &'a T, +} + +impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + self.data + } +} + +/// A guard holding mutable access to a `Freeze` which is in a locked state or frozen. +#[must_use = "if unused the Freeze may immediately unlock"] +pub struct FreezeWriteGuard<'a, T> { + _lock_guard: LockGuard<'a, ()>, + data: &'a mut T, +} + +impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + self.data + } +} + +impl<'a, T: 'a> DerefMut for FreezeWriteGuard<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + self.data + } +} diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 2db7aa0e36710..a7c6368074713 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceLock, RwLock, WorkerLocal}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, Freeze, Lrc, OnceLock, RwLock, WorkerLocal}; use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::DepGraphFuture; @@ -197,7 +197,7 @@ impl<'tcx> Queries<'tcx> { self.codegen_backend().metadata_loader(), stable_crate_id, )) as _); - let definitions = RwLock::new(Definitions::new(stable_crate_id)); + let definitions = Freeze::new(Definitions::new(stable_crate_id)); let source_span = AppendOnlyIndexVec::new(); let _id = source_span.push(krate.spans.inner_span); debug_assert_eq!(_id, CRATE_DEF_ID); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3e8f07ed233a2..e20a202561ff0 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1207,7 +1207,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { source_file_names.hash_stable(&mut hcx, &mut stable_hasher); debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); if tcx.sess.opts.incremental_relative_spans() { - let definitions = tcx.definitions_untracked(); + let definitions = tcx.untracked().definitions.freeze(); let mut owner_spans: Vec<_> = krate .owners .iter_enumerated() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e2f9e299566ae..90d847804f0e5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -39,7 +39,9 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal}; +use rustc_data_structures::sync::{ + self, FreezeReadGuard, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal, +}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, @@ -964,8 +966,8 @@ impl<'tcx> TyCtxt<'tcx> { i += 1; } - // Leak a read lock once we finish iterating on definitions, to prevent adding new ones. - definitions.leak(); + // Freeze definitions once we finish iterating on them, to prevent adding new ones. + definitions.freeze(); }) } @@ -974,10 +976,9 @@ impl<'tcx> TyCtxt<'tcx> { // definitions change. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); - // Leak a read lock once we start iterating on definitions, to prevent adding new ones + // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. - let definitions = self.untracked.definitions.leak(); - definitions.def_path_table() + self.untracked.definitions.freeze().def_path_table() } pub fn def_path_hash_to_def_index_map( @@ -986,10 +987,9 @@ impl<'tcx> TyCtxt<'tcx> { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new ones + // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. - let definitions = self.untracked.definitions.leak(); - definitions.def_path_hash_to_def_index_map() + self.untracked.definitions.freeze().def_path_hash_to_def_index_map() } /// Note that this is *untracked* and should only be used within the query @@ -1006,7 +1006,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries #[inline] - pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> { + pub fn definitions_untracked(self) -> FreezeReadGuard<'tcx, Definitions> { self.untracked.definitions.read() } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index c53a355b533ea..a86363b9cae9b 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -7,7 +7,7 @@ use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; use rustc_data_structures::owned_slice::OwnedSlice; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock}; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, Freeze, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -261,5 +261,5 @@ pub struct Untracked { pub cstore: RwLock>, /// Reference span for definitions. pub source_span: AppendOnlyIndexVec, - pub definitions: RwLock, + pub definitions: Freeze, } From 6881eed8f686964e83d5b915fcc1445f23aa60ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 31 Aug 2023 23:14:47 +0200 Subject: [PATCH 051/217] Don't hold the definitions' lock across `index_hir` --- compiler/rustc_ast_lowering/src/index.rs | 30 ++++++++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 3 +-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index ce847906fb99a..eff362f3ff0cd 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -2,19 +2,17 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::definitions; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; use rustc_index::{Idx, IndexVec}; use rustc_middle::span_bug; -use rustc_session::Session; -use rustc_span::source_map::SourceMap; +use rustc_middle::ty::TyCtxt; use rustc_span::{Span, DUMMY_SP}; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { - /// Source map - source_map: &'a SourceMap, + tcx: TyCtxt<'hir>, + bodies: &'a SortedMap>, /// Outputs @@ -25,14 +23,11 @@ pub(super) struct NodeCollector<'a, 'hir> { parent_node: hir::ItemLocalId, owner: OwnerId, - - definitions: &'a definitions::Definitions, } -#[instrument(level = "debug", skip(sess, definitions, bodies))] +#[instrument(level = "debug", skip(tcx, bodies))] pub(super) fn index_hir<'hir>( - sess: &Session, - definitions: &definitions::Definitions, + tcx: TyCtxt<'hir>, item: hir::OwnerNode<'hir>, bodies: &SortedMap>, ) -> (IndexVec>>, FxHashMap) { @@ -42,8 +37,7 @@ pub(super) fn index_hir<'hir>( // used. nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() })); let mut collector = NodeCollector { - source_map: sess.source_map(), - definitions, + tcx, owner: item.def_id(), parent_node: ItemLocalId::new(0), nodes, @@ -79,11 +73,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { span, "inconsistent HirId at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.source_map.span_to_diagnostic_string(span), + self.tcx.sess.source_map().span_to_diagnostic_string(span), node, - self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(), + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), self.owner, - self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(), + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), hir_id.owner, ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a6d1ef33f4069..41db61d391a13 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -671,8 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { (None, None) }; - let (nodes, parenting) = - index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); + let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; From ac54d4957268b684ef36dbda8ab9d17aa09e3333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 2 Sep 2023 00:25:54 +0200 Subject: [PATCH 052/217] Freeze `Definitions` earlier --- compiler/rustc_hir_analysis/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4f95174f869e7..b0f333b79cafe 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -237,6 +237,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries From 25884ec9be2115c729ac114fd6c62e4037584b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 2 Sep 2023 00:46:15 +0200 Subject: [PATCH 053/217] Use `RwLock` for `Freeze` --- .../rustc_data_structures/src/sync/freeze.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 77b37af526940..21bbc35e317dd 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -1,4 +1,4 @@ -use crate::sync::{AtomicBool, Lock, LockGuard}; +use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; #[cfg(parallel_compiler)] use crate::sync::{DynSend, DynSync}; use std::{ @@ -13,7 +13,9 @@ use std::{ pub struct Freeze { data: UnsafeCell, frozen: AtomicBool, - lock: Lock<()>, + + /// This lock protects writes to the `data` and `frozen` fields. + lock: RwLock<()>, } #[cfg(parallel_compiler)] @@ -22,7 +24,7 @@ unsafe impl DynSync for Freeze {} impl Freeze { #[inline] pub fn new(value: T) -> Self { - Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: Lock::new(()) } + Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: RwLock::new(()) } } #[inline] @@ -31,7 +33,7 @@ impl Freeze { _lock_guard: if self.frozen.load(Ordering::Acquire) { None } else { - Some(self.lock.lock()) + Some(self.lock.read()) }, // SAFETY: If this is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so // this has shared access until the `FreezeReadGuard` is dropped. If this is frozen, @@ -43,7 +45,7 @@ impl Freeze { #[inline] #[track_caller] pub fn write(&self) -> FreezeWriteGuard<'_, T> { - let _lock_guard = self.lock.lock(); + let _lock_guard = self.lock.write(); assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); FreezeWriteGuard { _lock_guard, @@ -57,7 +59,7 @@ impl Freeze { pub fn freeze(&self) -> &T { if !self.frozen.load(Ordering::Acquire) { // Get the lock to ensure no concurrent writes. - let _lock = self.lock.lock(); + let _lock = self.lock.write(); self.frozen.store(true, Ordering::Release); } @@ -69,7 +71,7 @@ impl Freeze { /// A guard holding shared access to a `Freeze` which is in a locked state or frozen. #[must_use = "if unused the Freeze may immediately unlock"] pub struct FreezeReadGuard<'a, T> { - _lock_guard: Option>, + _lock_guard: Option>, data: &'a T, } @@ -84,7 +86,7 @@ impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> { /// A guard holding mutable access to a `Freeze` which is in a locked state or frozen. #[must_use = "if unused the Freeze may immediately unlock"] pub struct FreezeWriteGuard<'a, T> { - _lock_guard: LockGuard<'a, ()>, + _lock_guard: WriteGuard<'a, ()>, data: &'a mut T, } From 50f0d666d3308f0b0a45842cbe725fcb5b3c3861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 2 Sep 2023 01:22:22 +0200 Subject: [PATCH 054/217] Add some comments --- compiler/rustc_data_structures/src/sync/freeze.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 21bbc35e317dd..e9ad6ee8394d0 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -9,6 +9,8 @@ use std::{ /// A type which allows mutation using a lock until /// the value is frozen and can be accessed lock-free. +/// +/// Unlike `RwLock`, it can be used to prevent mutation past a point. #[derive(Default)] pub struct Freeze { data: UnsafeCell, @@ -46,6 +48,7 @@ impl Freeze { #[track_caller] pub fn write(&self) -> FreezeWriteGuard<'_, T> { let _lock_guard = self.lock.write(); + // Use relaxed ordering since we're in the write lock. assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); FreezeWriteGuard { _lock_guard, @@ -58,7 +61,7 @@ impl Freeze { #[inline] pub fn freeze(&self) -> &T { if !self.frozen.load(Ordering::Acquire) { - // Get the lock to ensure no concurrent writes. + // Get the lock to ensure no concurrent writes and that we release the latest write. let _lock = self.lock.write(); self.frozen.store(true, Ordering::Release); } From a3ad045ea49b0613505e02bb0036575d1fc0c99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 2 Sep 2023 01:28:04 +0200 Subject: [PATCH 055/217] Rename `Freeze` to `FreezeLock` --- compiler/rustc_data_structures/src/sync.rs | 2 +- compiler/rustc_data_structures/src/sync/freeze.rs | 14 +++++++------- compiler/rustc_interface/src/queries.rs | 6 ++++-- compiler/rustc_session/src/cstore.rs | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index a8f42e0ed0e25..8eda9043e358b 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -62,7 +62,7 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; mod freeze; -pub use freeze::{Freeze, FreezeReadGuard, FreezeWriteGuard}; +pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; mod mode { use super::Ordering; diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index e9ad6ee8394d0..ea75dcc4151da 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -12,7 +12,7 @@ use std::{ /// /// Unlike `RwLock`, it can be used to prevent mutation past a point. #[derive(Default)] -pub struct Freeze { +pub struct FreezeLock { data: UnsafeCell, frozen: AtomicBool, @@ -21,9 +21,9 @@ pub struct Freeze { } #[cfg(parallel_compiler)] -unsafe impl DynSync for Freeze {} +unsafe impl DynSync for FreezeLock {} -impl Freeze { +impl FreezeLock { #[inline] pub fn new(value: T) -> Self { Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: RwLock::new(()) } @@ -71,8 +71,8 @@ impl Freeze { } } -/// A guard holding shared access to a `Freeze` which is in a locked state or frozen. -#[must_use = "if unused the Freeze may immediately unlock"] +/// A guard holding shared access to a `FreezeLock` which is in a locked state or frozen. +#[must_use = "if unused the FreezeLock may immediately unlock"] pub struct FreezeReadGuard<'a, T> { _lock_guard: Option>, data: &'a T, @@ -86,8 +86,8 @@ impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> { } } -/// A guard holding mutable access to a `Freeze` which is in a locked state or frozen. -#[must_use = "if unused the Freeze may immediately unlock"] +/// A guard holding mutable access to a `FreezeLock` which is in a locked state or frozen. +#[must_use = "if unused the FreezeLock may immediately unlock"] pub struct FreezeWriteGuard<'a, T> { _lock_guard: WriteGuard<'a, ()>, data: &'a mut T, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index a7c6368074713..e0d9998d919b1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -7,7 +7,9 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyIndexVec, Freeze, Lrc, OnceLock, RwLock, WorkerLocal}; +use rustc_data_structures::sync::{ + AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, RwLock, WorkerLocal, +}; use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::DepGraphFuture; @@ -197,7 +199,7 @@ impl<'tcx> Queries<'tcx> { self.codegen_backend().metadata_loader(), stable_crate_id, )) as _); - let definitions = Freeze::new(Definitions::new(stable_crate_id)); + let definitions = FreezeLock::new(Definitions::new(stable_crate_id)); let source_span = AppendOnlyIndexVec::new(); let _id = source_span.push(krate.spans.inner_span); debug_assert_eq!(_id, CRATE_DEF_ID); diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index a86363b9cae9b..90f57be9324ab 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -7,7 +7,7 @@ use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; use rustc_data_structures::owned_slice::OwnedSlice; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, Freeze, RwLock}; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -261,5 +261,5 @@ pub struct Untracked { pub cstore: RwLock>, /// Reference span for definitions. pub source_span: AppendOnlyIndexVec, - pub definitions: Freeze, + pub definitions: FreezeLock, } From 61a0b77e17531e6d65d8fad80588237ee5e14529 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Sep 2023 10:15:35 +0000 Subject: [PATCH 056/217] Use relative positions inside a SourceFile. --- src/debuginfo/line_info.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index 50bc7a127af09..998263de584fc 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -82,12 +82,9 @@ impl DebugContext { match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines(|lines| lines[line]); + let col = file.relative_position(span.lo()) - line_pos; - ( - file, - u64::try_from(line).unwrap() + 1, - u64::from((span.lo() - line_pos).to_u32()) + 1, - ) + (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) } Err(file) => (file, 0, 0), } From 7bad066f82f65781864804f674ee9c31c1ad68a7 Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 4 Sep 2023 00:52:17 +0800 Subject: [PATCH 057/217] resolve: derive diag for undetermined macro resolution --- compiler/rustc_resolve/messages.ftl | 4 ++++ compiler/rustc_resolve/src/errors.rs | 10 ++++++++++ compiler/rustc_resolve/src/macros.rs | 15 +++++++-------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index f98918cba8800..33fde28552445 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -58,6 +58,10 @@ resolve_cannot_determine_import_resolution = cannot determine resolution for the import .note = import resolution is stuck, try simplifying other imports +resolve_cannot_determine_macro_resolution = + cannot determine resolution for the {$kind} `{$path}` + .note = import resolution is stuck, try simplifying macro imports + resolve_cannot_find_ident_in_this_scope = cannot find {$expected} `{$ident}` in this scope diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e4b89c65853d0..85c9171e78abb 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -654,6 +654,16 @@ pub(crate) struct CannotDetermineImportResolution { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(resolve_cannot_determine_macro_resolution)] +#[note] +pub(crate) struct CannotDetermineMacroResolution { + #[primary_span] + pub(crate) span: Span, + pub(crate) kind: &'static str, + pub(crate) path: String, +} + #[derive(Diagnostic)] #[diag(resolve_cannot_be_reexported_private, code = "E0364")] pub(crate) struct CannotBeReexportedPrivate { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1199290a4d1c6..8206071657577 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -2,7 +2,8 @@ //! interface provided by `Resolver` to macro expander. use crate::errors::{ - self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive, + self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope, + MacroExpectedFound, RemoveSurroundingDerive, }; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; @@ -719,13 +720,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // even if speculative `resolve_path` returned nothing previously, so we skip this // less informative error if the privacy error is reported elsewhere. if this.privacy_errors.is_empty() { - let msg = format!( - "cannot determine resolution for the {} `{}`", - kind.descr(), - Segment::names_to_string(path) - ); - let msg_note = "import resolution is stuck, try simplifying macro imports"; - this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit(); + this.tcx.sess.emit_err(CannotDetermineMacroResolution { + span, + kind: kind.descr(), + path: Segment::names_to_string(path), + }); } } }; From 94fe18f84be026b8e56e81e02545dafc6cfe7378 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 29 Apr 2023 21:51:32 -0400 Subject: [PATCH 058/217] Use a specialized varint + bitpacking scheme for DepGraph encoding --- .../rustc_middle/src/dep_graph/dep_node.rs | 2 +- compiler/rustc_middle/src/dep_graph/mod.rs | 16 + .../rustc_query_system/src/dep_graph/edges.rs | 60 ++++ .../rustc_query_system/src/dep_graph/graph.rs | 31 +- .../rustc_query_system/src/dep_graph/mod.rs | 8 + .../src/dep_graph/serialized.rs | 284 ++++++++++++++++-- compiler/rustc_query_system/src/lib.rs | 1 + compiler/rustc_serialize/src/opaque.rs | 2 +- 8 files changed, 358 insertions(+), 46 deletions(-) create mode 100644 compiler/rustc_query_system/src/dep_graph/edges.rs diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index afcf08395bb2b..78a0f82db132a 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -97,7 +97,7 @@ macro_rules! define_dep_nodes { // discriminants of the variants have been assigned consecutively from 0 // so that just the one comparison suffices to check that the u16 can be // transmuted to a DepKind. - const VARIANTS: u16 = { + pub const VARIANTS: u16 = { let deps: &[DepKind] = &[$(DepKind::$variant,)*]; let mut i = 0; while i < deps.len() { diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index f79ce08b8aed4..87436f9eeed86 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -26,6 +26,7 @@ pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct) -> std::fmt::Result { write!(f, "{:?}(", node.kind)?; @@ -68,6 +69,21 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { op(icx.task_deps) }) } + + #[track_caller] + #[inline] + fn from_u16(u: u16) -> Self { + if u > Self::MAX { + panic!("Invalid DepKind {u}"); + } + // SAFETY: See comment on DepKind::VARIANTS + unsafe { std::mem::transmute(u) } + } + + #[inline] + fn to_u16(self) -> u16 { + self as u16 + } } impl<'tcx> DepContext for TyCtxt<'tcx> { diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs new file mode 100644 index 0000000000000..ab161e9b5b56e --- /dev/null +++ b/compiler/rustc_query_system/src/dep_graph/edges.rs @@ -0,0 +1,60 @@ +use crate::dep_graph::DepNodeIndex; +use smallvec::SmallVec; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; + +#[derive(Default, Debug)] +pub struct EdgesVec { + max: u32, + edges: SmallVec<[DepNodeIndex; EdgesVec::INLINE_CAPACITY]>, +} + +impl Hash for EdgesVec { + #[inline] + fn hash(&self, hasher: &mut H) { + Hash::hash(&self.edges, hasher) + } +} + +impl EdgesVec { + pub const INLINE_CAPACITY: usize = 8; + + #[inline] + pub fn new() -> Self { + Self::default() + } + + #[inline] + pub fn push(&mut self, edge: DepNodeIndex) { + self.max = self.max.max(edge.as_u32()); + self.edges.push(edge); + } + + #[inline] + pub fn max_index(&self) -> u32 { + self.max + } +} + +impl Deref for EdgesVec { + type Target = [DepNodeIndex]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.edges.as_slice() + } +} + +impl FromIterator for EdgesVec { + #[inline] + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + let mut vec = EdgesVec::new(); + for index in iter { + vec.push(index) + } + vec + } +} diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0d4d13ac20d46..c83b69d7f6389 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -8,7 +8,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; -use smallvec::{smallvec, SmallVec}; use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use std::fmt::Debug; @@ -19,6 +18,7 @@ use std::sync::atomic::Ordering::Relaxed; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use crate::dep_graph::EdgesVec; use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; @@ -137,7 +137,7 @@ impl DepGraph { let _green_node_index = current.intern_new_node( profiler, DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, - smallvec![], + EdgesVec::new(), Fingerprint::ZERO, ); assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); @@ -147,7 +147,7 @@ impl DepGraph { profiler, &prev_graph, DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, - smallvec![], + EdgesVec::new(), None, false, ); @@ -356,12 +356,12 @@ impl DepGraphData { let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg)); let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { - (with_deps(TaskDepsRef::EvalAlways), smallvec![]) + (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new()) } else { let task_deps = Lock::new(TaskDeps { #[cfg(debug_assertions)] node: Some(key), - reads: SmallVec::new(), + reads: EdgesVec::new(), read_set: Default::default(), phantom_data: PhantomData, }); @@ -486,14 +486,14 @@ impl DepGraph { // As long as we only have a low number of reads we can avoid doing a hash // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + let new_read = if task_deps.reads.len() < EdgesVec::INLINE_CAPACITY { task_deps.reads.iter().all(|other| *other != dep_node_index) } else { task_deps.read_set.insert(dep_node_index) }; if new_read { task_deps.reads.push(dep_node_index); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { + if task_deps.reads.len() == EdgesVec::INLINE_CAPACITY { // Fill `read_set` with what we have so far so we can use the hashset // next time task_deps.read_set.extend(task_deps.reads.iter().copied()); @@ -572,9 +572,13 @@ impl DepGraph { } } - let mut edges = SmallVec::new(); + let mut edges = EdgesVec::new(); K::read_deps(|task_deps| match task_deps { - TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), + TaskDepsRef::Allow(deps) => { + for index in deps.lock().reads.iter().copied() { + edges.push(index); + } + } TaskDepsRef::EvalAlways => { edges.push(DepNodeIndex::FOREVER_RED_NODE); } @@ -872,7 +876,7 @@ impl DepGraphData { let prev_deps = self.previous.edge_targets_from(prev_dep_node_index); - for &dep_dep_node_index in prev_deps { + for dep_dep_node_index in prev_deps { self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?; } @@ -1308,8 +1312,7 @@ impl CurrentDepGraph { let key = prev_graph.index_to_node(prev_index); let edges = prev_graph .edge_targets_from(prev_index) - .iter() - .map(|i| prev_index_to_index[*i].unwrap()) + .map(|i| prev_index_to_index[i].unwrap()) .collect(); let fingerprint = prev_graph.fingerprint_by_index(prev_index); let dep_node_index = self.encoder.borrow().send(profiler, key, fingerprint, edges); @@ -1335,10 +1338,6 @@ impl CurrentDepGraph { } } -/// The capacity of the `reads` field `SmallVec` -const TASK_DEPS_READS_CAP: usize = 8; -type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; - #[derive(Debug, Clone, Copy)] pub enum TaskDepsRef<'a, K: DepKind> { /// New dependencies can be added to the diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 0fd9e35d6dc8d..272028d35bf7e 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,10 +1,12 @@ pub mod debug; mod dep_node; +mod edges; mod graph; mod query; mod serialized; pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId}; +pub use edges::EdgesVec; pub use graph::{ hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductMap, @@ -157,4 +159,10 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable fn read_deps(op: OP) where OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); + + fn from_u16(u: u16) -> Self; + + fn to_u16(self) -> u16; + + const MAX: u16; } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index edddfda624242..91460fa039955 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -1,6 +1,6 @@ //! The data that we will serialize and deserialize. //! -//! The dep-graph is serialized as a sequence of NodeInfo, with the dependencies +//! Notionally, the dep-graph is a sequence of NodeInfo with the dependencies //! specified inline. The total number of nodes and edges are stored as the last //! 16 bytes of the file, so we can find them easily at decoding time. //! @@ -14,14 +14,16 @@ use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex}; +use crate::dep_graph::EdgesVec; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fingerprint::PackedFingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_index::{Idx, IndexVec}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; -use rustc_serialize::{Decodable, Decoder, Encodable}; -use smallvec::SmallVec; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::marker::PhantomData; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits // unused so that we can store multiple index types in `CompressedHybridIndex`, @@ -31,6 +33,16 @@ rustc_index::newtype_index! { pub struct SerializedDepNodeIndex {} } +const DEP_NODE_SIZE: usize = std::mem::size_of::(); +/// Amount of padding we need to add to the edge list data so that we can retrieve every +/// SerializedDepNodeIndex with a fixed-size read then mask. +const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; +/// Amount of bits we need to store the number of used bytes in a SerializedDepNodeIndex. +/// Note that wherever we encode byte widths like this we actually store the number of bytes used +/// minus 1; for a 4-byte value we technically would have 5 widths to store, but using one byte to +/// store zeroes (which are relatively rare) is a decent tradeoff to save a bit in our bitfields. +const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; + /// Data for use when recompiling the **current crate**. #[derive(Debug)] pub struct SerializedDepGraph { @@ -42,10 +54,10 @@ pub struct SerializedDepGraph { /// For each DepNode, stores the list of edges originating from that /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// which holds the actual DepNodeIndices of the target nodes. - edge_list_indices: IndexVec, - /// A flattened list of all edge targets in the graph. Edge sources are - /// implicit in edge_list_indices. - edge_list_data: Vec, + edge_list_indices: IndexVec, + /// A flattened list of all edge targets in the graph, stored in the same + /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices. + edge_list_data: Vec, /// Reciprocal map to `nodes`. index: FxHashMap, SerializedDepNodeIndex>, } @@ -64,9 +76,35 @@ impl Default for SerializedDepGraph { impl SerializedDepGraph { #[inline] - pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { - let targets = self.edge_list_indices[source]; - &self.edge_list_data[targets.0 as usize..targets.1 as usize] + pub fn edge_targets_from( + &self, + source: SerializedDepNodeIndex, + ) -> impl Iterator + '_ { + let header = self.edge_list_indices[source]; + let mut raw = &self.edge_list_data[header.start()..]; + // Figure out where the edge list for `source` ends by getting the start index of the next + // edge list, or the end of the array if this is the last edge. + let end = self + .edge_list_indices + .get(source + 1) + .map(|h| h.start()) + .unwrap_or_else(|| self.edge_list_data.len() - DEP_NODE_PAD); + + // The number of edges for this node is implicitly stored in the combination of the byte + // width and the length. + let bytes_per_index = header.bytes_per_index(); + let len = (end - header.start()) / bytes_per_index; + + // LLVM doesn't hoist EdgeHeader::mask so we do it ourselves. + let mask = header.mask(); + (0..len).map(move |_| { + // Doing this slicing in this order ensures that the first bounds check suffices for + // all the others. + let index = &raw[..DEP_NODE_SIZE]; + raw = &raw[bytes_per_index..]; + let index = u32::from_le_bytes(index.try_into().unwrap()) & mask; + SerializedDepNodeIndex::from_u32(index) + }) } #[inline] @@ -84,11 +122,42 @@ impl SerializedDepGraph { self.fingerprints[dep_node_index] } + #[inline] pub fn node_count(&self) -> usize { self.index.len() } } +/// A packed representation of an edge's start index and byte width. +/// +/// This is packed by stealing 2 bits from the start index, which means we only accomodate edge +/// data arrays up to a quarter of our address space. Which seems fine. +#[derive(Debug, Clone, Copy)] +struct EdgeHeader { + repr: usize, +} + +impl EdgeHeader { + #[inline] + fn start(self) -> usize { + self.repr >> DEP_NODE_WIDTH_BITS + } + + #[inline] + fn bytes_per_index(self) -> usize { + (self.repr & mask(DEP_NODE_WIDTH_BITS)) + 1 + } + + #[inline] + fn mask(self) -> u32 { + mask(self.bytes_per_index() * 8) as u32 + } +} + +fn mask(bits: usize) -> usize { + usize::MAX >> ((std::mem::size_of::() * 8) - bits) +} + impl<'a, K: DepKind + Decodable>> Decodable> for SerializedDepGraph { @@ -107,32 +176,51 @@ impl<'a, K: DepKind + Decodable>> Decodable> debug!(?node_count, ?edge_count); + let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); + let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); - let mut edge_list_data = Vec::with_capacity(edge_count); + // This slightly over-estimates the amount of bytes used for all the edge data but never by + // more than ~6%, because over-estimation only occurs for large nodes. + let mut edge_list_data = Vec::with_capacity( + graph_bytes - node_count * std::mem::size_of::>(), + ); for _index in 0..node_count { - let dep_node: DepNode = Decodable::decode(d); - let _i: SerializedDepNodeIndex = nodes.push(dep_node); + // Decode the header for this edge; the header packs together as many of the fixed-size + // fields as possible to limit the number of times we update decoder state. + let node_header = SerializedNodeHeader { bytes: d.read_array(), _marker: PhantomData }; + + let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); debug_assert_eq!(_i.index(), _index); - let fingerprint: Fingerprint = Decodable::decode(d); - let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint); + let _i: SerializedDepNodeIndex = fingerprints.push(node_header.fingerprint()); debug_assert_eq!(_i.index(), _index); - // Deserialize edges -- sequence of DepNodeIndex - let len = d.read_usize(); - let start = edge_list_data.len().try_into().unwrap(); - for _ in 0..len { - let edge = Decodable::decode(d); - edge_list_data.push(edge); - } - let end = edge_list_data.len().try_into().unwrap(); - let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end)); + // If the length of this node's edge list is small, the length is stored in the header. + // If it is not, we fall back to another decoder call. + let num_edges = node_header.len().unwrap_or_else(|| d.read_usize()); + + // The edges index list uses the same varint strategy as rmeta tables; we select the + // number of byte elements per-array not per-element. This lets us read the whole edge + // list for a node with one decoder call and also use the on-disk format in memory. + let edges_len_bytes = node_header.bytes_per_index() * num_edges; + // The in-memory structure for the edges list stores the byte width of the edges on + // this node with the offset into the global edge data array. + let edges_header = node_header.edges_header(&edge_list_data); + + edge_list_data.extend(d.read_raw_bytes(edges_len_bytes)); + + let _i: SerializedDepNodeIndex = edge_list_indices.push(edges_header); debug_assert_eq!(_i.index(), _index); } + // When we access the edge list data, we do a fixed-size read from the edge list data then + // mask off the bytes that aren't for that edge index, so the last read may dangle off the + // end of the array. This padding ensure it doesn't. + edge_list_data.extend(&[0u8; DEP_NODE_PAD]); + let index: FxHashMap<_, _> = nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); @@ -140,11 +228,151 @@ impl<'a, K: DepKind + Decodable>> Decodable> } } -#[derive(Debug, Encodable, Decodable)] -pub struct NodeInfo { +/// A packed representation of all the fixed-size fields in a `NodeInfo`. +/// +/// This stores in one byte array: +/// * The `Fingerprint` in the `NodeInfo` +/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo` +/// * The `DepKind`'s discriminant (a u16, but not all bits are used...) +/// * The byte width of the encoded edges for this node +/// * In whatever bits remain, the length of the edge list for this node, if it fits +struct SerializedNodeHeader { + // 2 bytes for the DepNode + // 16 for Fingerprint in DepNode + // 16 for Fingerprint in NodeInfo + bytes: [u8; 34], + _marker: PhantomData, +} + +// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only +// to make the implementation of `SerializedNodeHeader` simpler. +struct Unpacked { + len: Option, + bytes_per_index: usize, + kind: K, + hash: PackedFingerprint, + fingerprint: Fingerprint, +} + +// Bit fields are +// 0..? length of the edge +// ?..?+2 bytes per index +// ?+2..16 kind +impl SerializedNodeHeader { + const TOTAL_BITS: usize = std::mem::size_of::() * 8; + const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; + const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; + const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize; + const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1; + + #[inline] + fn new(node_info: &NodeInfo) -> Self { + debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS); + + let NodeInfo { node, fingerprint, edges } = node_info; + + let mut head = node.kind.to_u16(); + + let free_bytes = edges.max_index().leading_zeros() as usize / 8; + let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1); + head |= (bytes_per_index as u16) << Self::KIND_BITS; + + // Encode number of edges + 1 so that we can reserve 0 to indicate that the len doesn't fit + // in this bitfield. + if edges.len() <= Self::MAX_INLINE_LEN { + head |= (edges.len() as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS); + } + + let hash: Fingerprint = node.hash.into(); + + // Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong. + let mut bytes = [0u8; 34]; + bytes[..2].copy_from_slice(&head.to_le_bytes()); + bytes[2..18].copy_from_slice(&hash.to_le_bytes()); + bytes[18..].copy_from_slice(&fingerprint.to_le_bytes()); + + #[cfg(debug_assertions)] + { + let res = Self { bytes, _marker: PhantomData }; + assert_eq!(node_info.fingerprint, res.fingerprint()); + assert_eq!(node_info.node, res.node()); + if let Some(len) = res.len() { + assert_eq!(node_info.edges.len(), len); + } + } + Self { bytes, _marker: PhantomData } + } + + #[inline] + fn unpack(&self) -> Unpacked { + let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); + let hash = self.bytes[2..18].try_into().unwrap(); + let fingerprint = self.bytes[18..].try_into().unwrap(); + + let kind = head & mask(Self::KIND_BITS) as u16; + let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; + let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS); + + Unpacked { + len: len.checked_sub(1), + bytes_per_index: bytes_per_index as usize + 1, + kind: DepKind::from_u16(kind), + hash: Fingerprint::from_le_bytes(hash).into(), + fingerprint: Fingerprint::from_le_bytes(fingerprint), + } + } + + #[inline] + fn len(&self) -> Option { + self.unpack().len + } + + #[inline] + fn bytes_per_index(&self) -> usize { + self.unpack().bytes_per_index + } + + #[inline] + fn fingerprint(&self) -> Fingerprint { + self.unpack().fingerprint + } + + #[inline] + fn node(&self) -> DepNode { + let Unpacked { kind, hash, .. } = self.unpack(); + DepNode { kind, hash } + } + + #[inline] + fn edges_header(&self, edge_list_data: &[u8]) -> EdgeHeader { + EdgeHeader { + repr: (edge_list_data.len() << DEP_NODE_WIDTH_BITS) | (self.bytes_per_index() - 1), + } + } +} + +#[derive(Debug)] +struct NodeInfo { node: DepNode, fingerprint: Fingerprint, - edges: SmallVec<[DepNodeIndex; 8]>, + edges: EdgesVec, +} + +impl Encodable for NodeInfo { + fn encode(&self, e: &mut FileEncoder) { + let header = SerializedNodeHeader::new(self); + e.emit_raw_bytes(&header.bytes); + + if header.len().is_none() { + e.emit_usize(self.edges.len()); + } + + let bytes_per_index = header.bytes_per_index(); + for node_index in self.edges.iter() { + let bytes = node_index.as_u32().to_le_bytes(); + e.emit_raw_bytes(&bytes[..bytes_per_index]); + } + } } struct Stat { @@ -303,7 +531,7 @@ impl> GraphEncoder { profiler: &SelfProfilerRef, node: DepNode, fingerprint: Fingerprint, - edges: SmallVec<[DepNodeIndex; 8]>, + edges: EdgesVec, ) -> DepNodeIndex { let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 8c9e9cfad6024..1944ac443eaed 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -4,6 +4,7 @@ #![feature(min_specialization)] #![feature(extern_types)] #![feature(let_chains)] +#![feature(inline_const)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 0ffc537eee02a..f1b7e8d9ae095 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -353,7 +353,7 @@ impl<'a> MemDecoder<'a> { } #[inline] - fn read_array(&mut self) -> [u8; N] { + pub fn read_array(&mut self) -> [u8; N] { self.read_raw_bytes(N).try_into().unwrap() } From 6672b862c456f0dad14f7cab0d4cae6f7dab89c0 Mon Sep 17 00:00:00 2001 From: reez12g Date: Tue, 29 Aug 2023 16:02:18 +0900 Subject: [PATCH 059/217] fix overflow in array length computation --- compiler/rustc_hir_typeck/src/generator_interior/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 6a8171224913b..38d7d5be97eda 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -643,15 +643,15 @@ fn check_must_not_suspend_ty<'tcx>( } ty::Array(ty, len) => { let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + let target_usize = len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize; + let plural_len = target_usize.saturating_add(1); check_must_not_suspend_ty( fcx, ty, hir_id, SuspendCheckData { descr_pre, - plural_len: len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) - as usize - + 1, + plural_len, ..data }, ) From 429a9258f10936c3b36b8b265175efbcbdfba1d5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 31 Aug 2023 18:56:34 +0000 Subject: [PATCH 060/217] Refactor projection debug. --- compiler/rustc_middle/src/mir/mod.rs | 124 +++++++++++++++------------ 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6484c30167cb3..18ae6bbc7a155 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1575,7 +1575,7 @@ impl ProjectionElem { /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct PlaceRef<'tcx> { pub local: Local, pub projection: &'tcx [PlaceElem<'tcx>], @@ -1753,67 +1753,81 @@ impl<'tcx> PlaceRef<'tcx> { impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - for elem in self.projection.iter().rev() { - match elem { - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Field(_, _) => { - write!(fmt, "(").unwrap(); - } - ProjectionElem::Deref => { - write!(fmt, "(*").unwrap(); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => {} - } - } + self.as_ref().fmt(fmt) + } +} +impl Debug for PlaceRef<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + pre_fmt_projection(self.projection, fmt)?; write!(fmt, "{:?}", self.local)?; + post_fmt_projection(self.projection, fmt) + } +} - for elem in self.projection.iter() { - match elem { - ProjectionElem::OpaqueCast(ty) => { - write!(fmt, " as {ty})")?; - } - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, " as {name})")?; - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, " as variant#{index:?})")?; - } - ProjectionElem::Deref => { - write!(fmt, ")")?; - } - ProjectionElem::Field(field, ty) => { - write!(fmt, ".{:?}: {:?})", field.index(), ty)?; - } - ProjectionElem::Index(ref index) => { - write!(fmt, "[{index:?}]")?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { - write!(fmt, "[{offset:?} of {min_length:?}]")?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { - write!(fmt, "[-{offset:?} of {min_length:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { - write!(fmt, "[{from:?}:]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { - write!(fmt, "[:-{to:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } => { - write!(fmt, "[{from:?}:-{to:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: false } => { - write!(fmt, "[{from:?}..{to:?}]")?; - } +fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result { + for &elem in projection.iter().rev() { + match elem { + ProjectionElem::OpaqueCast(_) + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => {} } + } - Ok(()) + Ok(()) +} + +fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result { + for &elem in projection.iter() { + match elem { + ProjectionElem::OpaqueCast(ty) => { + write!(fmt, " as {ty})")?; + } + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {name})")?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{index:?})")?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + write!(fmt, ".{:?}: {:?})", field.index(), ty)?; + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{index:?}]")?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { + write!(fmt, "[{offset:?} of {min_length:?}]")?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { + write!(fmt, "[-{offset:?} of {min_length:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { + write!(fmt, "[{from:?}:]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { + write!(fmt, "[:-{to:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } => { + write!(fmt, "[{from:?}:-{to:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: false } => { + write!(fmt, "[{from:?}..{to:?}]")?; + } + } } + + Ok(()) } /////////////////////////////////////////////////////////////////////////// From 2bba056187220659e3e64f7183494273e3c72e62 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 5 Sep 2023 19:11:50 +0200 Subject: [PATCH 061/217] Replace data_structures dependency with index in rustc_parse_format --- Cargo.lock | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84a668b5188ce..cc9b6e8324bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4157,7 +4157,7 @@ dependencies = [ name = "rustc_parse_format" version = "0.0.0" dependencies = [ - "rustc_data_structures", + "rustc_index", "rustc_lexer", ] diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 72da398d3fc19..1433035323924 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] rustc_lexer = { path = "../rustc_lexer" } -rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index", default-features = false } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 88452ccdf052e..a6c7eb8d91233 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -1011,7 +1011,7 @@ fn unescape_string(string: &str) -> Option { // Assert a reasonable size for `Piece` #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Piece<'_>, 16); +rustc_index::static_assert_size!(Piece<'_>, 16); #[cfg(test)] mod tests; From 26c48e6f95c4075951a21d54cf1e61af68cbb5e0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Aug 2023 16:58:42 +0000 Subject: [PATCH 062/217] Refactor how MIR represents composite debuginfo. --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 155 +++++++++--------- .../src/transform/validate.rs | 58 +++---- compiler/rustc_middle/src/mir/mod.rs | 70 ++++---- compiler/rustc_middle/src/mir/pretty.rs | 5 +- compiler/rustc_middle/src/mir/visit.rs | 19 +-- .../rustc_mir_build/src/build/custom/parse.rs | 1 + .../rustc_mir_build/src/build/matches/mod.rs | 2 + compiler/rustc_mir_build/src/build/mod.rs | 2 + .../rustc_mir_transform/src/remove_zsts.rs | 5 - compiler/rustc_mir_transform/src/sroa.rs | 93 ++++------- .../const_debuginfo.main.ConstDebugInfo.diff | 12 +- ...mut_range.PreCodegen.after.panic-abort.mir | 12 +- ...ut_range.PreCodegen.after.panic-unwind.mir | 12 +- ...mes.foo.ScalarReplacementOfAggregates.diff | 3 +- ...onstant.ScalarReplacementOfAggregates.diff | 3 +- ....copies.ScalarReplacementOfAggregates.diff | 10 +- ..._copies.ScalarReplacementOfAggregates.diff | 5 +- 17 files changed, 223 insertions(+), 244 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 526c16a59ded0..7cd9efe3ee2d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -484,54 +484,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None }; - let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let var_ty = if let Some(ref fragment) = var.composite { + self.monomorphize(fragment.ty) + } else { + match var.value { mir::VarDebugInfoContents::Place(place) => { - let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if let Some(arg_index) = var.argument_index - && place.projection.is_empty() - { - let arg_index = arg_index as usize; - if target_is_msvc { - // ScalarPair parameters are spilled to the stack so they need to - // be marked as a `LocalVariable` for MSVC debuggers to visualize - // their data correctly. (See #81894 & #88625) - let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { - VariableKind::LocalVariable - } else { - VariableKind::ArgumentVariable(arg_index) - } - } else { - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - VariableKind::ArgumentVariable(arg_index) - } - } else { - VariableKind::LocalVariable - }; - (var_ty, var_kind) + self.monomorphized_place_ty(place.as_ref()) } - mir::VarDebugInfoContents::Const(c) => { - let ty = self.monomorphize(c.ty()); - (ty, VariableKind::LocalVariable) - } - mir::VarDebugInfoContents::Composite { ty, fragments: _ } => { - let ty = self.monomorphize(ty); - (ty, VariableKind::LocalVariable) + mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()), + } + }; + + let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { + let var_kind = if let Some(arg_index) = var.argument_index + && var.composite.is_none() + && let mir::VarDebugInfoContents::Place(place) = var.value + && place.projection.is_empty() + { + let arg_index = arg_index as usize; + if target_is_msvc { + // ScalarPair parameters are spilled to the stack so they need to + // be marked as a `LocalVariable` for MSVC debuggers to visualize + // their data correctly. (See #81894 & #88625) + let var_ty_layout = self.cx.layout_of(var_ty); + if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + VariableKind::LocalVariable + } else { + VariableKind::ArgumentVariable(arg_index) + } + } else { + // FIXME(eddyb) shouldn't `ArgumentVariable` indices be + // offset in closures to account for the hidden environment? + VariableKind::ArgumentVariable(arg_index) } + } else { + VariableKind::LocalVariable }; self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); + let fragment = if let Some(ref fragment) = var.composite { + let var_layout = self.cx.layout_of(var_ty); + + let mut fragment_start = Size::ZERO; + let mut fragment_layout = var_layout; + + for elem in &fragment.projection { + match *elem { + mir::ProjectionElem::Field(field, _) => { + let i = field.index(); + fragment_start += fragment_layout.fields.offset(i); + fragment_layout = fragment_layout.field(self.cx, i); + } + _ => span_bug!( + var.source_info.span, + "unsupported fragment projection `{:?}`", + elem, + ), + } + } + + if fragment_layout.size == Size::ZERO { + // Fragment is a ZST, so does not represent anything. Avoid generating anything + // as this may conflict with a fragment that covers the entire variable. + continue; + } else if fragment_layout.size == var_layout.size { + // Fragment covers entire variable, so as far as + // DWARF is concerned, it's not really a fragment. + None + } else { + Some(fragment_start..fragment_start + fragment_layout.size) + } + } else { + None + }; + match var.value { mir::VarDebugInfoContents::Place(place) => { per_local[place.local].push(PerLocalVarDebugInfo { name: var.name, source_info: var.source_info, dbg_var, - fragment: None, + fragment, projection: place.projection, }); } @@ -547,51 +582,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, ); - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None); - } - } - } - mir::VarDebugInfoContents::Composite { ty, ref fragments } => { - let var_ty = self.monomorphize(ty); - let var_layout = self.cx.layout_of(var_ty); - for fragment in fragments { - let mut fragment_start = Size::ZERO; - let mut fragment_layout = var_layout; - - for elem in &fragment.projection { - match *elem { - mir::ProjectionElem::Field(field, _) => { - let i = field.index(); - fragment_start += fragment_layout.fields.offset(i); - fragment_layout = fragment_layout.field(self.cx, i); - } - _ => span_bug!( - var.source_info.span, - "unsupported fragment projection `{:?}`", - elem, - ), - } + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.llval, + Size::ZERO, + &[], + fragment, + ); } - - let place = fragment.contents; - let fragment = if fragment_layout.size == Size::ZERO { - // Fragment is a ZST, so does not represent anything. - continue; - } else if fragment_layout.size == var_layout.size { - // Fragment covers entire variable, so as far as - // DWARF is concerned, it's not really a fragment. - None - } else { - Some(fragment_start..fragment_start + fragment_layout.size) - }; - - per_local[place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - fragment, - projection: place.projection, - }); } } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 770c3f7f02c01..2f5f2ad6534ad 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -6,13 +6,7 @@ use rustc_index::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{ - traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, - MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef, - ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, - Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo, - VarDebugInfoContents, START_BLOCK, -}; +use rustc_middle::mir::*; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -757,37 +751,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { - let check_place = |this: &mut Self, place: Place<'_>| { - if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { - this.fail( + if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite { + if ty.is_union() || ty.is_enum() { + self.fail( START_BLOCK.start_location(), - format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name), ); } - }; + if projection.is_empty() { + self.fail( + START_BLOCK.start_location(), + format!("invalid empty projection in debuginfo for {:?}", debuginfo.name), + ); + } + if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { + self.fail( + START_BLOCK.start_location(), + format!( + "illegal projection {:?} in debuginfo for {:?}", + projection, debuginfo.name + ), + ); + } + } match debuginfo.value { VarDebugInfoContents::Const(_) => {} VarDebugInfoContents::Place(place) => { - check_place(self, place); - } - VarDebugInfoContents::Composite { ty, ref fragments } => { - for f in fragments { - check_place(self, f.contents); - if ty.is_union() || ty.is_enum() { - self.fail( - START_BLOCK.start_location(), - format!("invalid type {ty:?} for composite debuginfo"), - ); - } - if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { - self.fail( - START_BLOCK.start_location(), - format!( - "illegal projection {:?} in debuginfo for {:?}", - f.projection, debuginfo.name - ), - ); - } + if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { + self.fail( + START_BLOCK.start_location(), + format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + ); } } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 18ae6bbc7a155..239d20ae1b09c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1028,19 +1028,6 @@ pub enum VarDebugInfoContents<'tcx> { /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), Const(Constant<'tcx>), - /// The user variable's data is split across several fragments, - /// each described by a `VarDebugInfoFragment`. - /// See DWARF 5's "2.6.1.2 Composite Location Descriptions" - /// and LLVM's `DW_OP_LLVM_fragment` for more details on - /// the underlying debuginfo feature this relies on. - Composite { - /// Type of the original user variable. - /// This cannot contain a union or an enum. - ty: Ty<'tcx>, - /// All the parts of the original user variable, which ended - /// up in disjoint places, due to optimizations. - fragments: Vec>, - }, } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { @@ -1048,19 +1035,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> { match self { VarDebugInfoContents::Const(c) => write!(fmt, "{c}"), VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"), - VarDebugInfoContents::Composite { ty, fragments } => { - write!(fmt, "{ty:?}{{ ")?; - for f in fragments.iter() { - write!(fmt, "{f:?}, ")?; - } - write!(fmt, "}}") - } } } } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarDebugInfoFragment<'tcx> { + /// Type of the original user variable. + /// This cannot contain a union or an enum. + pub ty: Ty<'tcx>, + /// Where in the composite user variable this fragment is, /// represented as a "projection" into the composite variable. /// At lower levels, this corresponds to a byte/bit range. @@ -1071,29 +1055,10 @@ pub struct VarDebugInfoFragment<'tcx> { // to match on the discriminant, or by using custom type debuginfo // with non-overlapping variants for the composite variable. pub projection: Vec>, - - /// Where the data for this fragment can be found. - /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. - pub contents: Place<'tcx>, -} - -impl Debug for VarDebugInfoFragment<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - for elem in self.projection.iter() { - match elem { - ProjectionElem::Field(field, _) => { - write!(fmt, ".{:?}", field.index())?; - } - _ => bug!("unsupported fragment projection `{:?}`", elem), - } - } - - write!(fmt, " => {:?}", self.contents) - } } /// Debug information pertaining to a user variable. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarDebugInfo<'tcx> { pub name: Symbol, @@ -1102,6 +1067,13 @@ pub struct VarDebugInfo<'tcx> { /// (see `LocalDecl`'s `source_info` field for more details). pub source_info: SourceInfo, + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. + /// See DWARF 5's "2.6.1.2 Composite Location Descriptions" + /// and LLVM's `DW_OP_LLVM_fragment` for more details on + /// the underlying debuginfo feature this relies on. + pub composite: Option>>, + /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents<'tcx>, @@ -1111,6 +1083,20 @@ pub struct VarDebugInfo<'tcx> { pub argument_index: Option, } +impl Debug for VarDebugInfo<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite { + pre_fmt_projection(&projection[..], fmt)?; + write!(fmt, "({}: {})", self.name, ty)?; + post_fmt_projection(&projection[..], fmt)?; + } else { + write!(fmt, "{}", self.name)?; + } + + write!(fmt, " => {:?}", self.value) + } +} + /////////////////////////////////////////////////////////////////////////// // BasicBlock @@ -3070,6 +3056,6 @@ mod size_asserts { static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 104); static_assert_size!(TerminatorKind<'_>, 88); - static_assert_size!(VarDebugInfo<'_>, 80); + static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 773056e8a1799..488526edb430d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -554,10 +554,7 @@ fn write_scope_tree( continue; } - let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, - ); + let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info); if tcx.sess.opts.unstable_opts.mir_include_spans { writeln!( diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 87b04aabe6a39..61244b942893e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -838,12 +838,20 @@ macro_rules! make_mir_visitor { let VarDebugInfo { name: _, source_info, + composite, value, argument_index: _, } = var_debug_info; self.visit_source_info(source_info); let location = Location::START; + if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + for elem in projection { + let ProjectionElem::Field(_, ty) = elem else { bug!() }; + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } + } match value { VarDebugInfoContents::Const(c) => self.visit_constant(c, location), VarDebugInfoContents::Place(place) => @@ -852,17 +860,6 @@ macro_rules! make_mir_visitor { PlaceContext::NonUse(NonUseContext::VarDebugInfo), location ), - VarDebugInfoContents::Composite { ty, fragments } => { - // FIXME(eddyb) use a better `TyContext` here. - self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); - for VarDebugInfoFragment { projection: _, contents } in fragments { - self.visit_place( - contents, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location, - ); - } - } } } diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index f83c62fd580b8..e2ab2cb90c72f 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -241,6 +241,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { let dbginfo = VarDebugInfo { name, source_info: SourceInfo { span, scope: self.source_scope }, + composite: None, argument_index: None, value, }; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5ec216cea616b..7e81c8b50c2d0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2287,6 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(for_arm_body.into()), + composite: None, argument_index: None, }); let locals = if has_guard.0 { @@ -2306,6 +2307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(ref_for_guard.into()), + composite: None, argument_index: None, }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e614046e83e71..4e10916ad61ef 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -823,6 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), + composite: None, argument_index: None, }); @@ -852,6 +853,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info, value: VarDebugInfoContents::Place(arg_local.into()), + composite: None, argument_index: Some(argument_index as u16 + 1), }); } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 9c6c55b0811f7..c13bafa9fbb5b 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -87,11 +87,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty)) } } - VarDebugInfoContents::Composite { ty, fragments: _ } => { - if self.known_to_be_zst(ty) { - var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty)) - } - } } } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index e66ae8ff8845f..c21b1724cbb67 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,4 +1,5 @@ use crate::MirPass; +use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; use rustc_middle::mir::patch::MirPatch; @@ -147,7 +148,7 @@ fn escaping_locals<'tcx>( } // We ignore anything that happens in debuginfo, since we expand it using - // `VarDebugInfoContents::Composite`. + // `VarDebugInfoFragment`. fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {} } } @@ -246,9 +247,7 @@ fn replace_flattened_locals<'tcx>( for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() { visitor.visit_user_type_annotation(index, annotation); } - for var_debug_info in &mut body.var_debug_info { - visitor.visit_var_debug_info(var_debug_info); - } + visitor.expand_var_debug_info(&mut body.var_debug_info); let ReplacementVisitor { patch, all_dead_locals, .. } = visitor; patch.apply(body); all_dead_locals @@ -256,7 +255,7 @@ fn replace_flattened_locals<'tcx>( struct ReplacementVisitor<'tcx, 'll> { tcx: TyCtxt<'tcx>, - /// This is only used to compute the type for `VarDebugInfoContents::Composite`. + /// This is only used to compute the type for `VarDebugInfoFragment`. local_decls: &'ll LocalDecls<'tcx>, /// Work to do. replacements: &'ll ReplacementMap<'tcx>, @@ -266,16 +265,38 @@ struct ReplacementVisitor<'tcx, 'll> { } impl<'tcx> ReplacementVisitor<'tcx, '_> { - fn gather_debug_info_fragments(&self, local: Local) -> Option>> { - let mut fragments = Vec::new(); - let parts = self.replacements.place_fragments(local.into())?; - for (field, ty, replacement_local) in parts { - fragments.push(VarDebugInfoFragment { - projection: vec![PlaceElem::Field(field, ty)], - contents: Place::from(replacement_local), - }); - } - Some(fragments) + #[instrument(level = "trace", skip(self))] + fn expand_var_debug_info(&mut self, var_debug_info: &mut Vec>) { + var_debug_info.flat_map_in_place(|mut var_debug_info| { + let place = match var_debug_info.value { + VarDebugInfoContents::Const(_) => return vec![var_debug_info], + VarDebugInfoContents::Place(ref mut place) => place, + }; + + if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { + *place = repl; + return vec![var_debug_info]; + } + + let Some(parts) = self.replacements.place_fragments(*place) else { + return vec![var_debug_info]; + }; + + let ty = place.ty(self.local_decls, self.tcx).ty; + + parts + .map(|(field, field_ty, replacement_local)| { + let mut var_debug_info = var_debug_info.clone(); + let composite = var_debug_info.composite.get_or_insert_with(|| { + Box::new(VarDebugInfoFragment { ty, projection: Vec::new() }) + }); + composite.projection.push(PlaceElem::Field(field, field_ty)); + + var_debug_info.value = VarDebugInfoContents::Place(replacement_local.into()); + var_debug_info + }) + .collect() + }); } } @@ -422,48 +443,6 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.super_statement(statement, location) } - #[instrument(level = "trace", skip(self))] - fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { - match &mut var_debug_info.value { - VarDebugInfoContents::Place(ref mut place) => { - if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { - *place = repl; - } else if let Some(local) = place.as_local() - && let Some(fragments) = self.gather_debug_info_fragments(local) - { - let ty = place.ty(self.local_decls, self.tcx).ty; - var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; - } - } - VarDebugInfoContents::Composite { ty: _, ref mut fragments } => { - let mut new_fragments = Vec::new(); - debug!(?fragments); - fragments.retain_mut(|fragment| { - if let Some(repl) = - self.replacements.replace_place(self.tcx, fragment.contents.as_ref()) - { - fragment.contents = repl; - true - } else if let Some(local) = fragment.contents.as_local() - && let Some(frg) = self.gather_debug_info_fragments(local) - { - new_fragments.extend(frg.into_iter().map(|mut f| { - f.projection.splice(0..0, fragment.projection.iter().copied()); - f - })); - false - } else { - true - } - }); - debug!(?fragments); - debug!(?new_fragments); - fragments.extend(new_fragments); - } - VarDebugInfoContents::Const(_) => {} - } - } - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { assert!(!self.all_dead_locals.contains(*local)); } diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index 255ec94816c3e..ed47baa67daba 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -33,14 +33,22 @@ let _15: bool; let _16: u32; scope 6 { - debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; +- debug ((f: (bool, bool, u32)).0: bool) => _14; +- debug ((f: (bool, bool, u32)).1: bool) => _15; +- debug ((f: (bool, bool, u32)).2: u32) => _16; ++ debug ((f: (bool, bool, u32)).0: bool) => const true; ++ debug ((f: (bool, bool, u32)).1: bool) => const false; ++ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; let _10: std::option::Option; scope 7 { debug o => _10; let _17: u32; let _18: u32; scope 8 { - debug p => Point{ .0 => _17, .1 => _18, }; +- debug ((p: Point).0: u32) => _17; +- debug ((p: Point).1: u32) => _18; ++ debug ((p: Point).0: u32) => const 32_u32; ++ debug ((p: Point).1: u32) => const 32_u32; let _11: u32; scope 9 { - debug a => _11; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 8dd2cd7900f3f..2fd669aeeb61d 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { debug self => _1; - debug index => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range).0: usize) => _3; + debug ((index: std::ops::Range).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range).0: usize) => _3; + debug ((self: std::ops::Range).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::::len) { debug self => _5; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 8dd2cd7900f3f..2fd669aeeb61d 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { debug self => _1; - debug index => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range).0: usize) => _3; + debug ((index: std::ops::Range).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range).0: usize) => _3; + debug ((self: std::ops::Range).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::::len) { debug self => _5; diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index bb14b909a956c..b020d1baafa16 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -33,7 +33,8 @@ + let _32: u32; scope 1 { - debug foo => _1; -+ debug foo => Foo{ .0 => _31, .1 => _32, }; ++ debug ((foo: Foo).0: std::result::Result, ::Err>) => _31; ++ debug ((foo: Foo).1: u32) => _32; let _5: std::result::Result, ::Err>; scope 2 { debug x => _5; diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff index 7ee0431692c1d..1330f9b3ac80d 100644 --- a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff @@ -8,7 +8,8 @@ + let _5: u8; scope 1 { - debug y => _1; -+ debug y => (usize, u8){ .0 => _4, .1 => _5, }; ++ debug ((y: (usize, u8)).0: usize) => _4; ++ debug ((y: (usize, u8)).1: u8) => _5; let _2: usize; scope 2 { debug t => _2; diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff index 0a1de891aee42..3621338635ed7 100644 --- a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _14: std::option::Option; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; ++ debug ((y: Foo).0: u8) => _11; ++ debug ((y: Foo).1: ()) => _12; ++ debug ((y: Foo).2: &str) => _13; ++ debug ((y: Foo).3: std::option::Option) => _14; let _3: u8; scope 2 { debug t => _3; @@ -25,7 +28,10 @@ + let _10: std::option::Option; scope 4 { - debug z => _5; -+ debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; ++ debug ((z: Foo).0: u8) => _7; ++ debug ((z: Foo).1: ()) => _8; ++ debug ((z: Foo).2: &str) => _9; ++ debug ((z: Foo).3: std::option::Option) => _10; let _6: (); scope 5 { debug a => _6; diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff index d7c57c293c4a9..304bf2fb1a765 100644 --- a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _8: std::option::Option; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; ++ debug ((y: Foo).0: u8) => _5; ++ debug ((y: Foo).1: ()) => _6; ++ debug ((y: Foo).2: &str) => _7; ++ debug ((y: Foo).3: std::option::Option) => _8; let _3: u8; scope 2 { debug t => _3; From 537edd0be49aa91665b71dee05662bdfd4dd00a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Tue, 5 Sep 2023 19:56:20 +0200 Subject: [PATCH 063/217] Bump stdarch submodule --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index d77878b7299dd..6100854c4b360 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit d77878b7299dd7e286799a6e8447048b65d2a861 +Subproject commit 6100854c4b360f84da5ab25e7c75cb2080667ddc From c3edc579810ae536c4a468e5b8e1cd88fda73567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Tue, 5 Sep 2023 20:06:50 +0200 Subject: [PATCH 064/217] Remove special handling in codegen for some SSE2 "storeu" intrinsics Those were removed from stdarch in https://github.com/rust-lang/stdarch/pull/1463 (`<*mut _>::write_unaligned` is used instead) --- .../rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index fdd27a454e066..b990ed7f8bc2a 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -506,14 +506,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.place_lane(fx, 2).to_ptr().store(fx, res_2, MemFlags::trusted()); ret.place_lane(fx, 3).to_ptr().store(fx, res_3, MemFlags::trusted()); } - "llvm.x86.sse2.storeu.dq" | "llvm.x86.sse2.storeu.pd" => { - intrinsic_args!(fx, args => (mem_addr, a); intrinsic); - let mem_addr = mem_addr.load_scalar(fx); - - // FIXME correctly handle the unalignment - let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout()); - dest.write_cvalue(fx, a); - } "llvm.x86.ssse3.pabs.b.128" | "llvm.x86.ssse3.pabs.w.128" | "llvm.x86.ssse3.pabs.d.128" => { let a = match args { [a] => a, From 0b6ee86d378425c781264649dc0d637160e16762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Tue, 5 Sep 2023 20:17:01 +0200 Subject: [PATCH 065/217] Remove special handling in codegen for some AVX and SSE2 shift by immediate intrinsics Those were removed from stdarch in https://github.com/rust-lang/stdarch/pull/1463 (`simd_shl` and `simd_shr` are used instead) --- .../src/intrinsics/llvm_x86.rs | 240 ------------------ 1 file changed, 240 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index b990ed7f8bc2a..e62de6b61477d 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -177,244 +177,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane) }); } - "llvm.x86.sse2.psrli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrai.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrai.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.psrli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.psrai.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrli.q" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.q imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 64 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.q" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.q imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 64 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.pslli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.psrli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.psrai.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrai.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.pslli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } "llvm.x86.ssse3.pshuf.b.128" | "llvm.x86.avx2.pshuf.b" => { let (a, b) = match args { [a, b] => (a, b), @@ -563,8 +325,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // llvm.x86.avx2.vperm2i128 // llvm.x86.ssse3.pshuf.b.128 // llvm.x86.avx2.pshuf.b -// llvm.x86.avx2.psrli.w -// llvm.x86.sse2.psrli.w fn llvm_add_sub<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, From d35be6c0970bb15903b118f07563fb81a1bc9953 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Jan 2023 20:29:02 +0000 Subject: [PATCH 066/217] Do not assert in try_to_int. --- compiler/rustc_middle/src/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6484c30167cb3..fa51b52a25bfb 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2317,7 +2317,7 @@ impl<'tcx> ConstantKind<'tcx> { #[inline] pub fn try_to_scalar_int(self) -> Option { - Some(self.try_to_scalar()?.assert_int()) + self.try_to_scalar()?.try_to_int().ok() } #[inline] From 09ce0f6ebc395fa3abeef3e29561135c961bcd1c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 5 Sep 2023 20:21:21 +0000 Subject: [PATCH 067/217] Remove type from ScalarTy. --- .../src/dataflow_const_prop.rs | 130 +++++++++--------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d4c9163b5718b..29fc3a1be37ea 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -9,7 +9,7 @@ use rustc_hir::def::DefKind; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, }; @@ -58,9 +58,13 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint()); // Collect results and patch the body afterwards. - let mut visitor = CollectAndPatch::new(tcx); + let mut visitor = CollectAndPatch::new(tcx, &body.local_decls); debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor)); - debug_span!("patch").in_scope(|| visitor.visit_body(body)); + debug_span!("patch").in_scope(|| { + for (block, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, bbdata); + } + }) } } @@ -73,7 +77,7 @@ struct ConstAnalysis<'a, 'tcx> { } impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { - type Value = FlatSet>; + type Value = FlatSet; const NAME: &'static str = "ConstAnalysis"; @@ -172,9 +176,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(overflow_target) = overflow_target { let overflow = match overflow { FlatSet::Top => FlatSet::Top, - FlatSet::Elem(overflow) => { - self.wrap_scalar(Scalar::from_bool(overflow), self.tcx.types.bool) - } + FlatSet::Elem(overflow) => FlatSet::Elem(overflow.into()), FlatSet::Bottom => FlatSet::Bottom, }; // We have flooded `target` earlier. @@ -209,7 +211,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } _ => unreachable!(), } - .map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty))) + .map(|result| ValueOrPlace::Value(self.wrap_immediate(result))) .unwrap_or(ValueOrPlace::TOP), _ => ValueOrPlace::TOP, }, @@ -242,9 +244,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { constant .literal .eval(self.tcx, self.param_env) - .try_to_scalar() - .map(|value| FlatSet::Elem(ScalarTy(value, constant.ty()))) - .unwrap_or(FlatSet::Top) + .try_to_scalar_int() + .map_or(FlatSet::Top, FlatSet::Elem) } fn handle_switch_int<'mir>( @@ -261,9 +262,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { // We are branching on uninitialized data, this is UB, treat it as unreachable. // This allows the set of visited edges to grow monotonically with the lattice. FlatSet::Bottom => TerminatorEdges::None, - FlatSet::Elem(ScalarTy(scalar, _)) => { - let int = scalar.assert_int(); - let choice = int.assert_bits(int.size()); + FlatSet::Elem(scalar) => { + let choice = scalar.assert_bits(scalar.size()); TerminatorEdges::Single(targets.target_for_value(choice)) } FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, @@ -271,16 +271,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } -#[derive(Clone, PartialEq, Eq)] -struct ScalarTy<'tcx>(Scalar, Ty<'tcx>); - -impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // This is used for dataflow visualization, so we return something more concise. - std::fmt::Display::fmt(&ConstantKind::Val(ConstValue::Scalar(self.0), self.1), f) - } -} - impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); @@ -295,17 +285,19 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { fn binary_op( &self, - state: &mut State>>, + state: &mut State>, op: BinOp, left: &Operand<'tcx>, right: &Operand<'tcx>, - ) -> (FlatSet>, FlatSet) { + ) -> (FlatSet, FlatSet) { let left = self.eval_operand(left, state); let right = self.eval_operand(right, state); match (left, right) { (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { - Ok((val, overflow, ty)) => (self.wrap_scalar(val, ty), FlatSet::Elem(overflow)), + Ok((Scalar::Int(val), overflow, _)) => { + (FlatSet::Elem(val), FlatSet::Elem(overflow)) + } _ => (FlatSet::Top, FlatSet::Top), } } @@ -320,7 +312,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { fn eval_operand( &self, op: &Operand<'tcx>, - state: &mut State>>, + state: &mut State>, ) -> FlatSet> { let value = match self.handle_operand(op, state) { ValueOrPlace::Value(value) => value, @@ -328,76 +320,76 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { }; match value { FlatSet::Top => FlatSet::Top, - FlatSet::Elem(ScalarTy(scalar, ty)) => self - .tcx - .layout_of(self.param_env.and(ty)) - .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar, layout))) - .unwrap_or(FlatSet::Top), + FlatSet::Elem(scalar) => { + let ty = op.ty(self.local_decls, self.tcx); + self.tcx + .layout_of(self.param_env.and(ty)) + .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout))) + .unwrap_or(FlatSet::Top) + } FlatSet::Bottom => FlatSet::Bottom, } } - fn eval_discriminant( - &self, - enum_ty: Ty<'tcx>, - variant_index: VariantIdx, - ) -> Option> { + fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option { if !enum_ty.is_enum() { return None; } let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?; let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?; - let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?; - Some(ScalarTy(discr_value, discr.ty)) - } - - fn wrap_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> FlatSet> { - FlatSet::Elem(ScalarTy(scalar, ty)) + let discr_value = ScalarInt::try_from_uint(discr.val, discr_layout.size)?; + Some(discr_value) } - fn wrap_immediate(&self, imm: Immediate, ty: Ty<'tcx>) -> FlatSet> { + fn wrap_immediate(&self, imm: Immediate) -> FlatSet { match imm { - Immediate::Scalar(scalar) => self.wrap_scalar(scalar, ty), + Immediate::Scalar(Scalar::Int(scalar)) => FlatSet::Elem(scalar), _ => FlatSet::Top, } } - fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet> { - self.wrap_immediate(*val, val.layout.ty) + fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet { + self.wrap_immediate(*val) } } -struct CollectAndPatch<'tcx> { +struct CollectAndPatch<'tcx, 'locals> { tcx: TyCtxt<'tcx>, + local_decls: &'locals LocalDecls<'tcx>, /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - before_effect: FxHashMap<(Location, Place<'tcx>), ScalarTy<'tcx>>, + before_effect: FxHashMap<(Location, Place<'tcx>), ScalarInt>, /// Stores the assigned values for assignments where the Rvalue is constant. - assignments: FxHashMap>, + assignments: FxHashMap, } -impl<'tcx> CollectAndPatch<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() } +impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> { + fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self { + Self { + tcx, + local_decls, + before_effect: FxHashMap::default(), + assignments: FxHashMap::default(), + } } - fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> { + fn make_operand(&self, scalar: ScalarInt, ty: Ty<'tcx>) -> Operand<'tcx> { Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, - literal: ConstantKind::Val(ConstValue::Scalar(scalar.0), scalar.1), + literal: ConstantKind::Val(ConstValue::Scalar(scalar.into()), ty), })) } } impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper>>> - for CollectAndPatch<'tcx> + for CollectAndPatch<'tcx, '_> { - type FlowState = State>>; + type FlowState = State>; fn visit_statement_before_primary_effect( &mut self, @@ -453,8 +445,8 @@ impl<'mir, 'tcx> } } -impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { +impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -462,7 +454,8 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { if let Some(value) = self.assignments.get(&location) { match &mut statement.kind { StatementKind::Assign(box (_, rvalue)) => { - *rvalue = Rvalue::Use(self.make_operand(value.clone())); + let ty = rvalue.ty(self.local_decls, self.tcx); + *rvalue = Rvalue::Use(self.make_operand(*value, ty)); } _ => bug!("found assignment info for non-assign statement"), } @@ -475,21 +468,22 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { match operand { Operand::Copy(place) | Operand::Move(place) => { if let Some(value) = self.before_effect.get(&(location, *place)) { - *operand = self.make_operand(value.clone()); + let ty = place.ty(self.local_decls, self.tcx).ty; + *operand = self.make_operand(*value, ty); } } - _ => (), + Operand::Constant(_) => {} } } } -struct OperandCollector<'tcx, 'map, 'a> { - state: &'a State>>, - visitor: &'a mut CollectAndPatch<'tcx>, +struct OperandCollector<'tcx, 'map, 'locals, 'a> { + state: &'a State>, + visitor: &'a mut CollectAndPatch<'tcx, 'locals>, map: &'map Map, } -impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> { +impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { match operand { Operand::Copy(place) | Operand::Move(place) => { @@ -572,7 +566,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm _bin_op: BinOp, _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, - ) -> interpret::InterpResult<'tcx, (interpret::Scalar, bool, Ty<'tcx>)> { + ) -> interpret::InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { throw_unsup!(Unsupported("".into())) } From 7ef555d84ab0f59ce9ee2199e6849824d9c16a63 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 12 May 2023 15:32:18 +0000 Subject: [PATCH 068/217] Support non-trivial scalars in ConstProp. --- .../rustc_mir_dataflow/src/value_analysis.rs | 74 ++++++++----------- .../src/dataflow_const_prop.rs | 2 +- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 6872ef5e98590..a7778b2be9fc3 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -626,45 +626,36 @@ pub struct Map { } impl Map { - fn new() -> Self { - Self { + /// Returns a map that only tracks places whose type has scalar layout. + /// + /// This is currently the only way to create a [`Map`]. The way in which the tracked places are + /// chosen is an implementation detail and may not be relied upon (other than that their type + /// are scalars). + pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { + let mut map = Self { locals: IndexVec::new(), projections: FxHashMap::default(), places: IndexVec::new(), value_count: 0, inner_values: IndexVec::new(), inner_values_buffer: Vec::new(), - } - } - - /// Returns a map that only tracks places whose type passes the filter. - /// - /// This is currently the only way to create a [`Map`]. The way in which the tracked places are - /// chosen is an implementation detail and may not be relied upon (other than that their type - /// passes the filter). - pub fn from_filter<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - filter: impl Fn(Ty<'tcx>) -> bool, - value_limit: Option, - ) -> Self { - let mut map = Self::new(); + }; let exclude = excluded_locals(body); - map.register_with_filter(tcx, body, filter, exclude, value_limit); + map.register(tcx, body, exclude, value_limit); debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } - /// Register all non-excluded places that pass the filter. - fn register_with_filter<'tcx>( + /// Register all non-excluded places that have scalar layout. + fn register<'tcx>( &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - filter: impl Fn(Ty<'tcx>) -> bool, exclude: BitSet, value_limit: Option, ) { let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len())); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); // Start by constructing the places for each bare local. self.locals = IndexVec::from_elem(None, &body.local_decls); @@ -679,7 +670,7 @@ impl Map { self.locals[local] = Some(place); // And push the eventual children places to the worklist. - self.register_children(tcx, place, decl.ty, &filter, &mut worklist); + self.register_children(tcx, param_env, place, decl.ty, &mut worklist); } // `place.elem1.elem2` with type `ty`. @@ -702,7 +693,7 @@ impl Map { } // And push the eventual children places to the worklist. - self.register_children(tcx, place, ty, &filter, &mut worklist); + self.register_children(tcx, param_env, place, ty, &mut worklist); } // Pre-compute the tree of ValueIndex nested in each PlaceIndex. @@ -732,42 +723,35 @@ impl Map { fn register_children<'tcx>( &mut self, tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, place: PlaceIndex, ty: Ty<'tcx>, - filter: &impl Fn(Ty<'tcx>) -> bool, worklist: &mut VecDeque<(PlaceIndex, Option, TrackElem, Ty<'tcx>)>, ) { // Allocate a value slot if it doesn't have one, and the user requested one. - if self.places[place].value_index.is_none() && filter(ty) { + assert!(self.places[place].value_index.is_none()); + if tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.abi.is_scalar()) { self.places[place].value_index = Some(self.value_count.into()); self.value_count += 1; } // For enums, directly create the `Discriminant`, as that's their main use. if ty.is_enum() { - let discr_ty = ty.discriminant_ty(tcx); - if filter(discr_ty) { - let discr = *self - .projections - .entry((place, TrackElem::Discriminant)) - .or_insert_with(|| { - // Prepend new child to the linked list. - let next = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); - self.places[next].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(next); - next - }); - - // Allocate a value slot if it doesn't have one. - if self.places[discr].value_index.is_none() { - self.places[discr].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - } + // Prepend new child to the linked list. + let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); + self.places[discr].next_sibling = self.places[place].first_child; + self.places[place].first_child = Some(discr); + let old = self.projections.insert((place, TrackElem::Discriminant), discr); + assert!(old.is_none()); + + // Allocate a value slot if it doesn't have one. + assert!(self.places[discr].value_index.is_none()); + self.places[discr].value_index = Some(self.value_count.into()); + self.value_count += 1; } // Recurse with all fields of this place. - iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| { + iter_fields(ty, tcx, param_env, |variant, field, ty| { worklist.push_back(( place, variant.map(TrackElem::Variant), diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 29fc3a1be37ea..e713a6cf0068b 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { let place_limit = if tcx.sess.mir_opt_level() < 4 { Some(PLACE_LIMIT) } else { None }; // Decide which places to track during the analysis. - let map = Map::from_filter(tcx, body, Ty::is_scalar, place_limit); + let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); From c18da3ccd4cca6295bba599324962a469aae9aa9 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 6 Sep 2023 02:21:56 +0000 Subject: [PATCH 069/217] Add regression test for LLVM 17-rc3 miscompile See #115385 for more details. --- tests/codegen/issues/issue-115385.rs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/codegen/issues/issue-115385.rs diff --git a/tests/codegen/issues/issue-115385.rs b/tests/codegen/issues/issue-115385.rs new file mode 100644 index 0000000000000..773b3507f2390 --- /dev/null +++ b/tests/codegen/issues/issue-115385.rs @@ -0,0 +1,50 @@ +// compile-flags: -O -Ccodegen-units=1 +// only-x86_64-unknown-linux-gnu + +#![crate_type = "lib"] + +#[repr(i64)] +pub enum Boolean { + False = 0, + True = 1, +} + +impl Clone for Boolean { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Boolean {} + +extern "C" { + fn set_value(foo: *mut i64); +} + +pub fn foo(x: bool) { + let mut foo = core::mem::MaybeUninit::::uninit(); + unsafe { + set_value(foo.as_mut_ptr()); + } + + if x { + let l1 = unsafe { *foo.as_mut_ptr().cast::() }; + if matches!(l1, Boolean::False) { + unsafe { + *foo.as_mut_ptr() = 0; + } + } + } + + let l2 = unsafe { *foo.as_mut_ptr() }; + if l2 == 2 { + // CHECK: call void @bar + bar(); + } +} + +#[no_mangle] +#[inline(never)] +pub fn bar() { + println!("Working correctly!"); +} From 6a286e775c51efb5f05bb98ed2df6b9a974574ad Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Wed, 6 Sep 2023 09:05:07 +0530 Subject: [PATCH 070/217] Add explanatory note to 'expected item' error --- compiler/rustc_parse/src/parser/item.rs | 12 ++++++++---- tests/ui/fn/keyword-order.stderr | 2 ++ tests/ui/parser/default-unmatched.stderr | 2 ++ tests/ui/parser/impl-parsing.stderr | 2 ++ tests/ui/parser/issue-101477-enum.stderr | 2 ++ .../issues/issue-113110-non-item-at-module-root.rs | 1 + .../issue-113110-non-item-at-module-root.stderr | 10 ++++++++++ tests/ui/parser/issues/issue-17904-2.stderr | 2 ++ tests/ui/parser/issues/issue-43196.stderr | 2 ++ tests/ui/parser/issues/issue-62913.stderr | 2 ++ tests/ui/parser/issues/issue-68890.stderr | 2 ++ tests/ui/parser/shebang/shebang-doc-comment.stderr | 2 ++ tests/ui/parser/virtual-structs.stderr | 2 ++ tests/ui/pub/pub-restricted-error-fn.stderr | 2 ++ 14 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs create mode 100644 tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 233c701641759..aad4edaba90b5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -73,12 +73,16 @@ impl<'a> Parser<'a> { if !self.maybe_consume_incorrect_semicolon(&items) { let msg = format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); - let label = if self.is_kw_followed_by_ident(kw::Let) { - "consider using `const` or `static` instead of `let` for global variables" + let span = self.token.span; + if self.is_kw_followed_by_ident(kw::Let) { + err.span_label( + span, + "consider using `const` or `static` instead of `let` for global variables", + ); } else { - "expected item" + err.span_label(span, "expected item") + .note("for a full list of items that can appear in modules, see "); }; - err.span_label(self.token.span, label); return Err(err); } } diff --git a/tests/ui/fn/keyword-order.stderr b/tests/ui/fn/keyword-order.stderr index d3b140c852860..97d8f91b1ee3b 100644 --- a/tests/ui/fn/keyword-order.stderr +++ b/tests/ui/fn/keyword-order.stderr @@ -11,6 +11,8 @@ error: expected item, found keyword `pub` | LL | default pub const async unsafe extern fn err() {} | ^^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 2 previous errors diff --git a/tests/ui/parser/default-unmatched.stderr b/tests/ui/parser/default-unmatched.stderr index 331e003f63c0f..de142411d6912 100644 --- a/tests/ui/parser/default-unmatched.stderr +++ b/tests/ui/parser/default-unmatched.stderr @@ -11,6 +11,8 @@ error: expected item, found reserved keyword `do` | LL | default do | ^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 2 previous errors diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr index 755addf14527a..a57cc075ccc90 100644 --- a/tests/ui/parser/impl-parsing.stderr +++ b/tests/ui/parser/impl-parsing.stderr @@ -35,6 +35,8 @@ error: expected item, found keyword `unsafe` | LL | default unsafe FAIL | ^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 6 previous errors diff --git a/tests/ui/parser/issue-101477-enum.stderr b/tests/ui/parser/issue-101477-enum.stderr index 1edca391e8fd0..94130671f1c9a 100644 --- a/tests/ui/parser/issue-101477-enum.stderr +++ b/tests/ui/parser/issue-101477-enum.stderr @@ -11,6 +11,8 @@ error: expected item, found `==` | LL | B == 2 | ^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs new file mode 100644 index 0000000000000..3b6f430436952 --- /dev/null +++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs @@ -0,0 +1 @@ + 5 //~ ERROR expected item, found `5` diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr new file mode 100644 index 0000000000000..0789c4548a08e --- /dev/null +++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr @@ -0,0 +1,10 @@ +error: expected item, found `5` + --> $DIR/issue-113110-non-item-at-module-root.rs:1:2 + | +LL | 5 + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-17904-2.stderr b/tests/ui/parser/issues/issue-17904-2.stderr index 9c7fdf6ccb416..7185a5e5752c3 100644 --- a/tests/ui/parser/issues/issue-17904-2.stderr +++ b/tests/ui/parser/issues/issue-17904-2.stderr @@ -3,6 +3,8 @@ error: expected item, found keyword `where` | LL | struct Bar { x: T } where T: Copy | ^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-43196.stderr b/tests/ui/parser/issues/issue-43196.stderr index 4f7ed5cc6fdd8..15bbb158cd1ab 100644 --- a/tests/ui/parser/issues/issue-43196.stderr +++ b/tests/ui/parser/issues/issue-43196.stderr @@ -11,6 +11,8 @@ error: expected item, found `|` | LL | | | ^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-62913.stderr b/tests/ui/parser/issues/issue-62913.stderr index 6f385e8dc1777..c33e46837287f 100644 --- a/tests/ui/parser/issues/issue-62913.stderr +++ b/tests/ui/parser/issues/issue-62913.stderr @@ -17,6 +17,8 @@ error: expected item, found `"\u\"` | LL | "\u\" | ^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-68890.stderr b/tests/ui/parser/issues/issue-68890.stderr index 2a3bf6b41f02e..0d7b53a67c581 100644 --- a/tests/ui/parser/issues/issue-68890.stderr +++ b/tests/ui/parser/issues/issue-68890.stderr @@ -15,6 +15,8 @@ error: expected item, found `)` | LL | enum e{A((?'a a+?+l))} | ^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 3 previous errors diff --git a/tests/ui/parser/shebang/shebang-doc-comment.stderr b/tests/ui/parser/shebang/shebang-doc-comment.stderr index 2227d45ec5a3d..a36b2a2f72b4e 100644 --- a/tests/ui/parser/shebang/shebang-doc-comment.stderr +++ b/tests/ui/parser/shebang/shebang-doc-comment.stderr @@ -3,6 +3,8 @@ error: expected item, found `[` | LL | [allow(unused_variables)] | ^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to previous error diff --git a/tests/ui/parser/virtual-structs.stderr b/tests/ui/parser/virtual-structs.stderr index a5211d83f845d..268fc10579634 100644 --- a/tests/ui/parser/virtual-structs.stderr +++ b/tests/ui/parser/virtual-structs.stderr @@ -3,6 +3,8 @@ error: expected item, found reserved keyword `virtual` | LL | virtual struct SuperStruct { | ^^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to previous error diff --git a/tests/ui/pub/pub-restricted-error-fn.stderr b/tests/ui/pub/pub-restricted-error-fn.stderr index 0511a821a7afd..ca5d8e1b58eb8 100644 --- a/tests/ui/pub/pub-restricted-error-fn.stderr +++ b/tests/ui/pub/pub-restricted-error-fn.stderr @@ -11,6 +11,8 @@ error: expected item, found `(` | LL | pub(crate) () fn foo() {} | ^ expected item + | + = note: for a full list of items that can appear in modules, see error: aborting due to 2 previous errors From 2619a6ea5105a8cd7358419000117bbc25d0409e Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 6 Sep 2023 12:58:59 +0800 Subject: [PATCH 071/217] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 96fe1c9e1aecd..d14c85f4e6e76 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 96fe1c9e1aecd8f57063e3753969bb6418fd2fd5 +Subproject commit d14c85f4e6e7671673b1a1bc87231ff7164761e1 From 42dbc72d7bb0645292d72816d768d1f5365a58ca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 6 Sep 2023 16:45:58 +1000 Subject: [PATCH 072/217] Adjust `to_attr_token_stream`. It uses `once` chained with `(0..self.num_calls).map(...)` followed by `.take(self.num_calls`. I found this hard to read. It's simpler to just use `repeat_with`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 5d6c574baa612..c4e8d9006e6d8 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -106,7 +106,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { let mut cursor_snapshot = self.cursor_snapshot.clone(); let tokens = std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) - .chain((0..self.num_calls).map(|_| { + .chain(std::iter::repeat_with(|| { let token = cursor_snapshot.next(); (FlatToken::Token(token.0), token.1) })) From e0593f30fbaf8fdc05784ee90833596b2d659d9c Mon Sep 17 00:00:00 2001 From: Goldstein Date: Wed, 6 Sep 2023 10:14:09 +0300 Subject: [PATCH 073/217] fix log formatting in bootstrap --- src/bootstrap/lib.rs | 2 +- src/bootstrap/llvm.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4396bbc51a321..671d25484d0d2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1019,7 +1019,7 @@ impl Build { fn info(&self, msg: &str) { match self.config.dry_run { - DryRun::SelfCheck => return, + DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { println!("{msg}"); } diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 07502e0e9dd2c..aefed50151314 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -598,9 +598,9 @@ fn configure_cmake( } else if target.contains("linux") { cfg.define("CMAKE_SYSTEM_NAME", "Linux"); } else { - builder.info( + builder.info(&format!( "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail", - ); + )); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in From b43e3b9f41e1bc4f3d294196103563983e2d8906 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 14:31:14 +0000 Subject: [PATCH 074/217] Add type folder to SMIR --- compiler/rustc_smir/src/rustc_smir/mod.rs | 42 +++- compiler/rustc_smir/src/stable_mir/fold.rs | 207 ++++++++++++++++++ .../rustc_smir/src/stable_mir/mir/body.rs | 2 +- compiler/rustc_smir/src/stable_mir/mod.rs | 4 + compiler/rustc_smir/src/stable_mir/ty.rs | 6 + 5 files changed, 255 insertions(+), 6 deletions(-) create mode 100644 compiler/rustc_smir/src/stable_mir/fold.rs diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 52ba4bd4e579d..671928a63c2bf 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -103,8 +103,13 @@ impl<'tcx> Context for Tables<'tcx> { } fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind { - let ty = self.types[ty.0]; - ty.stable(self) + self.types[ty.0].clone().stable(self) + } + + fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty { + let n = self.types.len(); + self.types.push(MaybeStable::Stable(kind)); + stable_mir::ty::Ty(n) } fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { @@ -128,20 +133,47 @@ impl<'tcx> Context for Tables<'tcx> { } } +#[derive(Clone)] +pub enum MaybeStable { + Stable(S), + Rustc(R), +} + +impl<'tcx, S, R> MaybeStable { + fn stable(self, tables: &mut Tables<'tcx>) -> S + where + R: Stable<'tcx, T = S>, + { + match self { + MaybeStable::Stable(s) => s, + MaybeStable::Rustc(r) => r.stable(tables), + } + } +} + +impl PartialEq for MaybeStable { + fn eq(&self, other: &R) -> bool { + match self { + MaybeStable::Stable(_) => false, + MaybeStable::Rustc(r) => r == other, + } + } +} + pub struct Tables<'tcx> { pub tcx: TyCtxt<'tcx>, pub def_ids: Vec, pub alloc_ids: Vec, - pub types: Vec>, + pub types: Vec>>, } impl<'tcx> Tables<'tcx> { fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty { - if let Some(id) = self.types.iter().position(|&t| t == ty) { + if let Some(id) = self.types.iter().position(|t| *t == ty) { return stable_mir::ty::Ty(id); } let id = self.types.len(); - self.types.push(ty); + self.types.push(MaybeStable::Rustc(ty)); stable_mir::ty::Ty(id) } } diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs new file mode 100644 index 0000000000000..560a99cb4973f --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/fold.rs @@ -0,0 +1,207 @@ +use std::ops::ControlFlow; + +use crate::rustc_internal::Opaque; + +use super::ty::{ + Allocation, Binder, Const, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, + Promoted, RigidTy, TermKind, Ty, UnevaluatedConst, +}; + +pub trait Folder: Sized { + type Break; + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow { + ty.super_fold(self) + } + fn fold_const(&mut self, c: &Const) -> ControlFlow { + c.super_fold(self) + } +} + +pub trait Foldable: Sized + Clone { + fn fold(&self, folder: &mut V) -> ControlFlow { + self.super_fold(folder) + } + fn super_fold(&self, folder: &mut V) -> ControlFlow; +} + +impl Foldable for Ty { + fn fold(&self, folder: &mut V) -> ControlFlow { + folder.visit_ty(self) + } + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut kind = self.kind(); + match &mut kind { + super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?, + super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?, + super::ty::TyKind::Param(_) => {} + super::ty::TyKind::Bound(_, _) => {} + } + ControlFlow::Continue(kind.into()) + } +} + +impl Foldable for Const { + fn fold(&self, folder: &mut V) -> ControlFlow { + folder.fold_const(self) + } + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut this = self.clone(); + match &mut this.literal { + super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?, + super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?, + super::ty::ConstantKind::ParamCt(param) => *param = param.fold(folder)?, + } + ControlFlow::Continue(this) + } +} + +impl Foldable for Opaque { + fn super_fold(&self, _folder: &mut V) -> ControlFlow { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for Allocation { + fn super_fold(&self, _folder: &mut V) -> ControlFlow { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for UnevaluatedConst { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let UnevaluatedConst { ty, def, args, promoted } = self; + ControlFlow::Continue(UnevaluatedConst { + ty: ty.fold(folder)?, + def: def.fold(folder)?, + args: args.fold(folder)?, + promoted: promoted.fold(folder)?, + }) + } +} + +impl Foldable for ConstDef { + fn super_fold(&self, _folder: &mut V) -> ControlFlow { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for Option { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + ControlFlow::Continue(match self { + Some(val) => Some(val.fold(folder)?), + None => None, + }) + } +} + +impl Foldable for Promoted { + fn super_fold(&self, _folder: &mut V) -> ControlFlow { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for GenericArgs { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + ControlFlow::Continue(GenericArgs(self.0.fold(folder)?)) + } +} + +impl Foldable for GenericArgKind { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut this = self.clone(); + match &mut this { + GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?, + GenericArgKind::Type(t) => *t = t.fold(folder)?, + GenericArgKind::Const(c) => *c = c.fold(folder)?, + } + ControlFlow::Continue(this) + } +} + +impl Foldable for RigidTy { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut this = self.clone(); + match &mut this { + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + | RigidTy::Never + | RigidTy::Foreign(_) + | RigidTy::Str => {} + RigidTy::Array(t, c) => { + *t = t.fold(folder)?; + *c = c.fold(folder)?; + } + RigidTy::Slice(inner) => *inner = inner.fold(folder)?, + RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?, + RigidTy::Ref(_, ty, _) => *ty = ty.fold(folder)?, + RigidTy::FnDef(_, args) => *args = args.fold(folder)?, + RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?, + RigidTy::Closure(_, args) => *args = args.fold(folder)?, + RigidTy::Generator(_, args, _) => *args = args.fold(folder)?, + RigidTy::Dynamic(pred, r, _) => { + *pred = pred.fold(folder)?; + *r = r.fold(folder)?; + } + RigidTy::Tuple(fields) => *fields = fields.fold(folder)?, + RigidTy::Adt(_, args) => *args = args.fold(folder)?, + } + ControlFlow::Continue(this) + } +} + +impl Foldable for Vec { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut this = self.clone(); + for arg in &mut this { + *arg = arg.fold(folder)?; + } + ControlFlow::Continue(this) + } +} + +impl Foldable for Binder { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + ControlFlow::Continue(Self { + value: self.value.fold(folder)?, + bound_vars: self.bound_vars.clone(), + }) + } +} + +impl Foldable for ExistentialPredicate { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + let mut this = self.clone(); + match &mut this { + ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?, + ExistentialPredicate::Projection(p) => { + p.term = p.term.fold(folder)?; + p.generic_args = p.generic_args.fold(folder)?; + } + ExistentialPredicate::AutoTrait(_) => {} + } + ControlFlow::Continue(this) + } +} + +impl Foldable for TermKind { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + ControlFlow::Continue(match self { + TermKind::Type(t) => TermKind::Type(t.fold(folder)?), + TermKind::Const(c) => TermKind::Const(c.fold(folder)?), + }) + } +} + +impl Foldable for FnSig { + fn super_fold(&self, folder: &mut V) -> ControlFlow { + ControlFlow::Continue(Self { + inputs_and_output: self.inputs_and_output.fold(folder)?, + c_variadic: self.c_variadic, + unsafety: self.unsafety, + abi: self.abi.clone(), + }) + } +} diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 72f719c2a5e94..5957ae0ada9e7 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -391,7 +391,7 @@ pub enum Mutability { Mut, } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Safety { Unsafe, Normal, diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index f9eafd9de7ad8..90fc569f47bb8 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -20,6 +20,7 @@ use self::ty::{ }; use crate::rustc_smir::Tables; +pub mod fold; pub mod mir; pub mod ty; pub mod visitor; @@ -158,6 +159,9 @@ pub trait Context { /// Obtain the representation of a type. fn ty_kind(&mut self, ty: Ty) -> TyKind; + /// Create a new `Ty` from scratch without information from rustc. + fn mk_ty(&mut self, kind: TyKind) -> Ty; + /// HACK: Until we have fully stable consumers, we need an escape hatch /// to get `DefId`s out of `CrateItem`s. fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)); diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 1db6b1e3d28eb..5289e233a31dd 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -10,6 +10,12 @@ impl Ty { } } +impl From for Ty { + fn from(value: TyKind) -> Self { + with(|context| context.mk_ty(value)) + } +} + #[derive(Debug, Clone)] pub struct Const { pub literal: ConstantKind, From 7f009e54bd318bdd1e17481442c2331ae0ea9c44 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 14:32:42 +0000 Subject: [PATCH 075/217] Fail to test argument instantiation since we don't have types for most constants --- tests/ui-fulldeps/stable-mir/crate-info.rs | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 182f97373ea44..6bdfed947ce6d 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -110,6 +110,23 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> { other => panic!("{other:?}"), } + let monomorphic = get_item(tcx, &items, (DefKind::Fn, "monomorphic")).unwrap(); + for block in monomorphic.body().blocks { + match &block.terminator { + stable_mir::mir::Terminator::Call { func, .. } => match func { + stable_mir::mir::Operand::Constant(c) => match &c.literal { + stable_mir::ty::ConstantKind::Allocated(alloc) => { + assert!(alloc.bytes.is_empty()) + } + other => panic!("{other:?}"), + }, + other => panic!("{other:?}"), + }, + stable_mir::mir::Terminator::Return => {} + other => panic!("{other:?}"), + } + } + ControlFlow::Continue(()) } @@ -147,6 +164,16 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" + fn generic(t: T) -> [(); U] {{ + _ = t; + [(); U] + }} + + pub fn monomorphic() {{ + generic::<(), 5>(()); + generic::(45); + }} + mod foo {{ pub fn bar(i: i32) -> i64 {{ i as i64 From a370f1baa32bac446542a74c81dd7f99e12dc8fe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 14:37:30 +0000 Subject: [PATCH 076/217] Also use `Const` in `SMIR` instead of just `ConstantKind` --- compiler/rustc_smir/src/rustc_smir/mod.rs | 30 +++++++++++-------- .../rustc_smir/src/stable_mir/mir/body.rs | 4 +-- tests/ui-fulldeps/stable-mir/crate-info.rs | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 671928a63c2bf..aea9d3ec5804c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1216,22 +1216,26 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { } impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { - type T = stable_mir::ty::ConstantKind; + type T = stable_mir::ty::Const; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match *self { - ConstantKind::Ty(c) => c.stable(tables).literal, - ConstantKind::Unevaluated(unev_const, ty) => { - stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - ty: tables.intern_ty(ty), - def: tables.const_def(unev_const.def), - args: unev_const.args.stable(tables), - promoted: unev_const.promoted.map(|u| u.as_u32()), - }) - } - ConstantKind::Val(val, ty) => { - stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(ty, val, tables)) - } + ConstantKind::Ty(c) => c.stable(tables), + ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const { + literal: stable_mir::ty::ConstantKind::Unevaluated( + stable_mir::ty::UnevaluatedConst { + ty: tables.intern_ty(ty), + def: tables.const_def(unev_const.def), + args: unev_const.args.stable(tables), + promoted: unev_const.promoted.map(|u| u.as_u32()), + }, + ), + }, + ConstantKind::Val(val, ty) => stable_mir::ty::Const { + literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( + ty, val, tables, + )), + }, } } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 5957ae0ada9e7..449ca4b8145ed 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -1,6 +1,6 @@ use crate::rustc_internal::Opaque; use crate::stable_mir::ty::{ - AdtDef, ClosureDef, Const, ConstantKind, GeneratorDef, GenericArgs, Movability, Region, + AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region, }; use crate::stable_mir::{self, ty::Ty, Span}; @@ -352,7 +352,7 @@ type UserTypeAnnotationIndex = usize; pub struct Constant { pub span: Span, pub user_ty: Option, - pub literal: ConstantKind, + pub literal: Const, } #[derive(Clone, Debug)] diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 6bdfed947ce6d..31ad42b431dbb 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -114,7 +114,7 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> { for block in monomorphic.body().blocks { match &block.terminator { stable_mir::mir::Terminator::Call { func, .. } => match func { - stable_mir::mir::Operand::Constant(c) => match &c.literal { + stable_mir::mir::Operand::Constant(c) => match &c.literal.literal { stable_mir::ty::ConstantKind::Allocated(alloc) => { assert!(alloc.bytes.is_empty()) } From 627fa80bdfe0889688e344a7b7dbaf586decd1a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 15:07:17 +0000 Subject: [PATCH 077/217] Add types to all constants --- compiler/rustc_smir/src/rustc_smir/mod.rs | 5 +++-- compiler/rustc_smir/src/stable_mir/fold.rs | 4 ++-- compiler/rustc_smir/src/stable_mir/ty.rs | 2 +- compiler/rustc_smir/src/stable_mir/visitor.rs | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index aea9d3ec5804c..6df0138262192 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1136,7 +1136,6 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { ty::PlaceholderCt(_) => unimplemented!(), ty::Unevaluated(uv) => { stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - ty: tables.intern_ty(self.ty()), def: tables.const_def(uv.def), args: uv.args.stable(tables), promoted: None, @@ -1144,6 +1143,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { } ty::ExprCt(_) => unimplemented!(), }, + ty: tables.intern_ty(self.ty()), } } } @@ -1224,17 +1224,18 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Unevaluated( stable_mir::ty::UnevaluatedConst { - ty: tables.intern_ty(ty), def: tables.const_def(unev_const.def), args: unev_const.args.stable(tables), promoted: unev_const.promoted.map(|u| u.as_u32()), }, ), + ty: tables.intern_ty(ty), }, ConstantKind::Val(val, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( ty, val, tables, )), + ty: tables.intern_ty(ty), }, } } diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs index 560a99cb4973f..89f282d1afbf0 100644 --- a/compiler/rustc_smir/src/stable_mir/fold.rs +++ b/compiler/rustc_smir/src/stable_mir/fold.rs @@ -51,6 +51,7 @@ impl Foldable for Const { super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?, super::ty::ConstantKind::ParamCt(param) => *param = param.fold(folder)?, } + this.ty = this.ty.fold(folder)?; ControlFlow::Continue(this) } } @@ -69,9 +70,8 @@ impl Foldable for Allocation { impl Foldable for UnevaluatedConst { fn super_fold(&self, folder: &mut V) -> ControlFlow { - let UnevaluatedConst { ty, def, args, promoted } = self; + let UnevaluatedConst { def, args, promoted } = self; ControlFlow::Continue(UnevaluatedConst { - ty: ty.fold(folder)?, def: def.fold(folder)?, args: args.fold(folder)?, promoted: promoted.fold(folder)?, diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 5289e233a31dd..2361f6efe0d1f 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -19,6 +19,7 @@ impl From for Ty { #[derive(Debug, Clone)] pub struct Const { pub literal: ConstantKind, + pub ty: Ty, } type Ident = Opaque; @@ -298,7 +299,6 @@ pub enum ConstantKind { #[derive(Clone, Debug)] pub struct UnevaluatedConst { - pub ty: Ty, pub def: ConstDef, pub args: GenericArgs, pub promoted: Option, diff --git a/compiler/rustc_smir/src/stable_mir/visitor.rs b/compiler/rustc_smir/src/stable_mir/visitor.rs index c928eb1381f79..6f0d96fae3757 100644 --- a/compiler/rustc_smir/src/stable_mir/visitor.rs +++ b/compiler/rustc_smir/src/stable_mir/visitor.rs @@ -47,7 +47,8 @@ impl Visitable for Const { super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor), super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor), super::ty::ConstantKind::ParamCt(param) => param.visit(visitor), - } + }?; + self.ty.visit(visitor) } } @@ -65,8 +66,7 @@ impl Visitable for Allocation { impl Visitable for UnevaluatedConst { fn super_visit(&self, visitor: &mut V) -> ControlFlow { - let UnevaluatedConst { ty, def, args, promoted } = self; - ty.visit(visitor)?; + let UnevaluatedConst { def, args, promoted } = self; def.visit(visitor)?; args.visit(visitor)?; promoted.visit(visitor) From 98d26d9c4d8f0e94ad347723606449a74596dfba Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 15:17:27 +0000 Subject: [PATCH 078/217] Deopaquify `ParamConst` --- compiler/rustc_smir/src/rustc_smir/mod.rs | 10 +++++++++- compiler/rustc_smir/src/stable_mir/fold.rs | 2 +- compiler/rustc_smir/src/stable_mir/ty.rs | 8 +++++++- compiler/rustc_smir/src/stable_mir/visitor.rs | 17 +++++++++-------- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6df0138262192..c50cc7cd7cdb5 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1129,7 +1129,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { tables, )) } - ty::ParamCt(param) => stable_mir::ty::ConstantKind::ParamCt(opaque(¶m)), + ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), ty::ErrorCt(_) => unreachable!(), ty::InferCt(_) => unreachable!(), ty::BoundCt(_, _) => unimplemented!(), @@ -1148,6 +1148,14 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { } } +impl<'tcx> Stable<'tcx> for ty::ParamConst { + type T = stable_mir::ty::ParamConst; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::ParamConst; + ParamConst { index: self.index, name: self.name.to_string() } + } +} + impl<'tcx> Stable<'tcx> for ty::ParamTy { type T = stable_mir::ty::ParamTy; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs index 89f282d1afbf0..3567a5c5a3db6 100644 --- a/compiler/rustc_smir/src/stable_mir/fold.rs +++ b/compiler/rustc_smir/src/stable_mir/fold.rs @@ -49,7 +49,7 @@ impl Foldable for Const { match &mut this.literal { super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?, super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?, - super::ty::ConstantKind::ParamCt(param) => *param = param.fold(folder)?, + super::ty::ConstantKind::Param(_) => {} } this.ty = this.ty.fold(folder)?; ControlFlow::Continue(this) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 2361f6efe0d1f..7c58b640ec77f 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -294,7 +294,13 @@ pub struct Allocation { pub enum ConstantKind { Allocated(Allocation), Unevaluated(UnevaluatedConst), - ParamCt(Opaque), + Param(ParamConst), +} + +#[derive(Clone, Debug)] +pub struct ParamConst { + pub index: u32, + pub name: String, } #[derive(Clone, Debug)] diff --git a/compiler/rustc_smir/src/stable_mir/visitor.rs b/compiler/rustc_smir/src/stable_mir/visitor.rs index 6f0d96fae3757..c86063d2ed6eb 100644 --- a/compiler/rustc_smir/src/stable_mir/visitor.rs +++ b/compiler/rustc_smir/src/stable_mir/visitor.rs @@ -30,11 +30,12 @@ impl Visitable for Ty { } fn super_visit(&self, visitor: &mut V) -> ControlFlow { match self.kind() { - super::ty::TyKind::RigidTy(ty) => ty.visit(visitor), - super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor), - super::ty::TyKind::Param(_) => todo!(), - super::ty::TyKind::Bound(_, _) => todo!(), + super::ty::TyKind::RigidTy(ty) => ty.visit(visitor)?, + super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor)?, + super::ty::TyKind::Param(_) => {} + super::ty::TyKind::Bound(_, _) => {} } + ControlFlow::Continue(()) } } @@ -44,10 +45,10 @@ impl Visitable for Const { } fn super_visit(&self, visitor: &mut V) -> ControlFlow { match &self.literal { - super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor), - super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor), - super::ty::ConstantKind::ParamCt(param) => param.visit(visitor), - }?; + super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, + super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, + super::ty::ConstantKind::Param(_) => {} + } self.ty.visit(visitor) } } From 202fbed1a693ee2600bd3ec605f026b3ac3193a7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 15:18:42 +0000 Subject: [PATCH 079/217] Allow fetching the SMIR body of FnDefs --- compiler/rustc_smir/src/rustc_smir/mod.rs | 4 ++-- compiler/rustc_smir/src/stable_mir/mod.rs | 4 ++-- compiler/rustc_smir/src/stable_mir/ty.rs | 12 +++++++++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c50cc7cd7cdb5..a764073648139 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -78,8 +78,8 @@ impl<'tcx> Context for Tables<'tcx> { impl_trait.stable(self) } - fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body { - let def_id = self[item.0]; + fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { + let def_id = self[item]; let mir = self.tcx.optimized_mir(def_id); stable_mir::mir::Body { blocks: mir diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index 90fc569f47bb8..9cab7230b971b 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -87,7 +87,7 @@ pub struct CrateItem(pub(crate) DefId); impl CrateItem { pub fn body(&self) -> mir::Body { - with(|cx| cx.mir_body(self)) + with(|cx| cx.mir_body(self.0)) } } @@ -138,7 +138,7 @@ pub trait Context { fn entry_fn(&mut self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. fn all_local_items(&mut self) -> CrateItems; - fn mir_body(&mut self, item: &CrateItem) -> mir::Body; + fn mir_body(&mut self, item: DefId) -> mir::Body; fn all_trait_decls(&mut self) -> TraitDecls; fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; fn all_trait_impls(&mut self) -> ImplTraitDecls; diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 7c58b640ec77f..ad7a67275eeeb 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1,4 +1,8 @@ -use super::{mir::Mutability, mir::Safety, with, AllocId, DefId}; +use super::{ + mir::Safety, + mir::{Body, Mutability}, + with, AllocId, DefId, +}; use crate::rustc_internal::Opaque; #[derive(Copy, Clone, Debug)] @@ -95,6 +99,12 @@ pub struct ForeignDef(pub(crate) DefId); #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct FnDef(pub(crate) DefId); +impl FnDef { + pub fn body(&self) -> Body { + with(|ctx| ctx.mir_body(self.0)) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct ClosureDef(pub(crate) DefId); From 0f4ff52e004156cfeefbb4ebc590ffda595024c9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 15:18:53 +0000 Subject: [PATCH 080/217] Implement and test monomorphization --- compiler/rustc_smir/src/stable_mir/fold.rs | 27 +++++++++++++-- compiler/rustc_smir/src/stable_mir/ty.rs | 38 ++++++++++++++++++++++ tests/ui-fulldeps/stable-mir/crate-info.rs | 31 ++++++++++++++++-- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs index 3567a5c5a3db6..831cfb40a1542 100644 --- a/compiler/rustc_smir/src/stable_mir/fold.rs +++ b/compiler/rustc_smir/src/stable_mir/fold.rs @@ -3,8 +3,8 @@ use std::ops::ControlFlow; use crate::rustc_internal::Opaque; use super::ty::{ - Allocation, Binder, Const, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, - Promoted, RigidTy, TermKind, Ty, UnevaluatedConst, + Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind, + GenericArgs, Promoted, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst, }; pub trait Folder: Sized { @@ -205,3 +205,26 @@ impl Foldable for FnSig { }) } } + +pub enum Never {} + +/// In order to instantiate a `Foldable`'s generic parameters with specific arguments, +/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params +/// with the entries in its list. +impl Folder for GenericArgs { + type Break = Never; + + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow { + ControlFlow::Continue(match ty.kind() { + TyKind::Param(p) => self[p], + _ => *ty, + }) + } + + fn fold_const(&mut self, c: &Const) -> ControlFlow { + ControlFlow::Continue(match &c.literal { + ConstantKind::Param(p) => self[p.clone()].clone(), + _ => c.clone(), + }) + } +} diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index ad7a67275eeeb..7e344dc516be9 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -138,6 +138,22 @@ pub struct ImplDef(pub(crate) DefId); #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); +impl std::ops::Index for GenericArgs { + type Output = Ty; + + fn index(&self, index: ParamTy) -> &Self::Output { + self.0[index.index as usize].expect_ty() + } +} + +impl std::ops::Index for GenericArgs { + type Output = Const; + + fn index(&self, index: ParamConst) -> &Self::Output { + self.0[index.index as usize].expect_const() + } +} + #[derive(Clone, Debug)] pub enum GenericArgKind { Lifetime(Region), @@ -145,6 +161,28 @@ pub enum GenericArgKind { Const(Const), } +impl GenericArgKind { + /// Panic if this generic argument is not a type, otherwise + /// return the type. + #[track_caller] + pub fn expect_ty(&self) -> &Ty { + match self { + GenericArgKind::Type(ty) => ty, + _ => panic!("{self:?}"), + } + } + + /// Panic if this generic argument is not a const, otherwise + /// return the const. + #[track_caller] + pub fn expect_const(&self) -> &Const { + match self { + GenericArgKind::Const(c) => c, + _ => panic!("{self:?}"), + } + } +} + #[derive(Clone, Debug)] pub enum TermKind { Type(Ty), diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 31ad42b431dbb..d55eae86f074d 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -8,6 +8,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] +#![feature(control_flow_enum)] extern crate rustc_hir; extern crate rustc_middle; @@ -15,7 +16,10 @@ extern crate rustc_smir; use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; -use rustc_smir::{rustc_internal, stable_mir}; +use rustc_smir::{ + rustc_internal, + stable_mir::{self, fold::Foldable}, +}; use std::assert_matches::assert_matches; use std::io::Write; use std::ops::ControlFlow; @@ -116,7 +120,30 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> { stable_mir::mir::Terminator::Call { func, .. } => match func { stable_mir::mir::Operand::Constant(c) => match &c.literal.literal { stable_mir::ty::ConstantKind::Allocated(alloc) => { - assert!(alloc.bytes.is_empty()) + assert!(alloc.bytes.is_empty()); + match c.literal.ty.kind() { + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::FnDef( + def, + mut args, + )) => { + let func = def.body(); + match func.locals[1] + .fold(&mut args) + .continue_value() + .unwrap() + .kind() + { + stable_mir::ty::TyKind::RigidTy( + stable_mir::ty::RigidTy::Uint(_), + ) => {} + stable_mir::ty::TyKind::RigidTy( + stable_mir::ty::RigidTy::Tuple(_), + ) => {} + other => panic!("{other:?}"), + } + } + other => panic!("{other:?}"), + } } other => panic!("{other:?}"), }, From 7928c5f830825a913ddeecbd4ec711152c7addb5 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 5 Sep 2023 17:52:39 +0300 Subject: [PATCH 081/217] make comments less cryptic --- compiler/rustc_lint/src/traits.rs | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- tests/ui/drop-bounds/drop-bounds-impl-drop.rs | 10 +++++----- tests/ui/privacy/unnameable_types.rs | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 56508a2a6ccd8..e812493b3dd39 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { }; let def_id = trait_predicate.trait_ref.def_id; if cx.tcx.lang_items().drop_trait() == Some(def_id) { - // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern. + // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern. if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 0aa37642b740f..aac83dda9018c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4408,7 +4408,7 @@ declare_lint! { /// pub struct S; /// } /// - /// pub fn get_voldemort() -> m::S { m::S } + /// pub fn get_unnameable() -> m::S { m::S } /// # fn main() {} /// ``` /// diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0291cdd6c5799..fbbdfe5f14f92 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2857,7 +2857,7 @@ impl<'tcx> Ty<'tcx> { | ty::Uint(..) | ty::Float(..) => true, - // The voldemort ZSTs are fine. + // ZST which can't be named are fine. ty::FnDef(..) => true, ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(), diff --git a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs index 063efc7b31abd..15aebdf1bc93c 100644 --- a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs +++ b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs @@ -2,13 +2,13 @@ #![deny(drop_bounds)] // As a special exemption, `impl Drop` in the return position raises no error. // This allows a convenient way to return an unnamed drop guard. -fn voldemort_type() -> impl Drop { - struct Voldemort; - impl Drop for Voldemort { +fn unnameable_type() -> impl Drop { + struct Unnameable; + impl Drop for Unnameable { fn drop(&mut self) {} } - Voldemort + Unnameable } fn main() { - let _ = voldemort_type(); + let _ = unnameable_type(); } diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs index 46e249152594b..9fa14c50583e0 100644 --- a/tests/ui/privacy/unnameable_types.rs +++ b/tests/ui/privacy/unnameable_types.rs @@ -21,10 +21,10 @@ mod m { } } -pub trait Voldemort {} +pub trait Unnameable {} -impl Voldemort for i32 {} -impl Voldemort for i32 {} -impl Voldemort for u32 where T: m::PubTr {} +impl Unnameable for i32 {} +impl Unnameable for i32 {} +impl Unnameable for u32 where T: m::PubTr {} fn main() {} From 9570cac0199c4da6d4c493a4946d6b715eb437d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Aug 2023 09:57:48 +0200 Subject: [PATCH 082/217] rustc_abi: also support debugging function pointers --- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/abi_test.rs | 124 ++++++++++++++++++-------- tests/ui/abi/debug.rs | 2 + tests/ui/abi/debug.stderr | 106 ++++++++++++++++++++-- 4 files changed, 190 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 57598cf8bcf01..aa7db3348d028 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -8,7 +8,7 @@ passes_abi = abi: {$abi} passes_abi_of = - fn_abi_of_instance({$fn_name}) = {$fn_abi} + fn_abi_of({$fn_name}) = {$fn_abi} passes_align = align: {$align} diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 5c0438e78aebc..aeaa264216dac 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -2,9 +2,10 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; -use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; +use rustc_target::abi::call::FnAbi; use crate::errors::{AbiOf, UnrecognizedField}; @@ -17,7 +18,12 @@ pub fn test_abi(tcx: TyCtxt<'_>) { match tcx.def_kind(id.owner_id) { DefKind::Fn => { for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { - dump_abi_of(tcx, id.owner_id.def_id.into(), attr); + dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr); + } + } + DefKind::TyAlias { .. } => { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr); } } DefKind::Impl { .. } => { @@ -25,7 +31,7 @@ pub fn test_abi(tcx: TyCtxt<'_>) { for &id in tcx.associated_item_def_ids(id.owner_id) { if matches!(tcx.def_kind(id), DefKind::AssocFn) { for attr in tcx.get_attrs(id, sym::rustc_abi) { - dump_abi_of(tcx, id, attr); + dump_abi_of_fn_item(tcx, id, attr); } } } @@ -35,7 +41,32 @@ pub fn test_abi(tcx: TyCtxt<'_>) { } } -fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { +fn unwrap_fn_abi<'tcx>( + abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>, + tcx: TyCtxt<'tcx>, + item_def_id: DefId, +) -> &'tcx FnAbi<'tcx, Ty<'tcx>> { + match abi { + Ok(abi) => abi, + Err(FnAbiError::Layout(layout_error)) => { + tcx.sess.emit_fatal(Spanned { + node: layout_error.into_diagnostic(), + span: tcx.def_span(item_def_id), + }); + } + Err(FnAbiError::AdjustForForeignAbi(e)) => { + // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if + // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE + // isn't the worst thing. Also this matches what codegen does. + span_bug!( + tcx.def_span(item_def_id), + "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", + ) + } + } +} + +fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); let instance = match Instance::resolve(tcx, param_env, item_def_id, args) { @@ -51,43 +82,62 @@ fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { } Err(_guaranteed) => return, }; - match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) { - Ok(abi) => { - // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. - // The `..` are the names of fields to dump. - let meta_items = attr.meta_item_list().unwrap_or_default(); - for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::debug => { - let fn_name = tcx.item_name(item_def_id); - tcx.sess.emit_err(AbiOf { - span: tcx.def_span(item_def_id), - fn_name, - fn_abi: format!("{:#?}", abi), - }); - } + let abi = unwrap_fn_abi( + tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); - name => { - tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); - } - } + // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. + // The `..` are the names of fields to dump. + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let fn_name = tcx.item_name(item_def_id); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + fn_abi: format!("{:#?}", abi), + }); } - } - Err(FnAbiError::Layout(layout_error)) => { - tcx.sess.emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - span: tcx.def_span(item_def_id), - }); + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } - Err(FnAbiError::AdjustForForeignAbi(e)) => { - // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if - // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE - // isn't the worst thing. Also this matches what codegen does. - span_bug!( - tcx.def_span(item_def_id), - "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", - ) + } +} + +fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { + let param_env = tcx.param_env(item_def_id); + let ty = tcx.type_of(item_def_id).instantiate_identity(); + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let ty::FnPtr(sig) = ty.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(debug)]` on a type alias requires function pointer type" + ); + }; + let abi = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr(param_env.and((*sig, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); + + let fn_name = tcx.item_name(item_def_id); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + fn_abi: format!("{:#?}", abi), + }); + } + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } } } diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 13464be275e7c..84d08ead08df3 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -12,6 +12,8 @@ #[rustc_abi(debug)] fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi +#[rustc_abi(debug)] +type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi #[rustc_abi(debug)] fn test_generic(_x: *const T) { } //~ ERROR: fn_abi diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 4f4ee3de4b8a0..dd0cfea351faa 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -1,4 +1,4 @@ -error: fn_abi_of_instance(test) = FnAbi { +error: fn_abi_of(test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -92,7 +92,101 @@ error: fn_abi_of_instance(test) = FnAbi { LL | fn test(_x: u8) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(test_generic) = FnAbi { +error: fn_abi_of(TestFnPtr) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:16:1 + | +LL | type TestFnPtr = fn(bool) -> u8; + | ^^^^^^^^^^^^^^ + +error: fn_abi_of(test_generic) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -163,12 +257,12 @@ error: fn_abi_of_instance(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:17:1 + --> $DIR/debug.rs:19:1 | LL | fn test_generic(_x: *const T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(assoc_test) = FnAbi { +error: fn_abi_of(assoc_test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -251,10 +345,10 @@ error: fn_abi_of_instance(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:22:5 + --> $DIR/debug.rs:24:5 | LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From e66913f8fefd54a37c0a8b86b27b7b5117360be0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Sep 2023 14:03:25 +0200 Subject: [PATCH 083/217] rustc_layout/abi: error when attribute is applied to the wrong thing --- compiler/rustc_passes/messages.ftl | 25 ++++++++--------- compiler/rustc_passes/src/abi_test.rs | 31 ++++++++++++--------- compiler/rustc_passes/src/errors.rs | 30 ++++++++++++++------ compiler/rustc_passes/src/layout_test.rs | 35 ++++++++++++++++-------- tests/ui/abi/debug.rs | 11 +++++++- tests/ui/abi/debug.stderr | 22 +++++++++++---- tests/ui/layout/debug.rs | 11 ++++++-- tests/ui/layout/debug.stderr | 32 +++++++++++++++------- 8 files changed, 134 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index aa7db3348d028..602d614295c18 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -4,15 +4,11 @@ -passes_see_issue = see issue #{$issue} for more information -passes_abi = - abi: {$abi} - +passes_abi_invalid_attribute = + `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} -passes_align = - align: {$align} - passes_allow_incoherent_impl = `rustc_allow_incoherent_impl` attribute should be applied to impl items. .label = the only currently supported targets are inherent methods @@ -318,9 +314,6 @@ passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported -passes_homogeneous_aggregate = - homogeneous_aggregate: {$homogeneous_aggregate} - passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms .warn = {-passes_previously_accepted} @@ -404,9 +397,18 @@ passes_lang_item_on_incorrect_target = passes_layout = layout error: {$layout_error} - +passes_layout_abi = + abi: {$abi} +passes_layout_align = + align: {$align} +passes_layout_homogeneous_aggregate = + homogeneous_aggregate: {$homogeneous_aggregate} +passes_layout_invalid_attribute = + `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases passes_layout_of = layout_of({$normalized_ty}) = {$ty_layout} +passes_layout_size = + size: {$size} passes_link = attribute should be applied to an `extern` block with non-Rust ABI @@ -662,9 +664,6 @@ passes_should_be_applied_to_trait = attribute should be applied to a trait .label = not a trait -passes_size = - size: {$size} - passes_skipping_const_checks = skipping const checks passes_stability_promotable = diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index aeaa264216dac..4653a9c2b39da 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_target::abi::call::FnAbi; -use crate::errors::{AbiOf, UnrecognizedField}; +use crate::errors::{AbiInvalidAttribute, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs { @@ -15,28 +15,33 @@ pub fn test_abi(tcx: TyCtxt<'_>) { return; } for id in tcx.hir().items() { - match tcx.def_kind(id.owner_id) { - DefKind::Fn => { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + match tcx.def_kind(id.owner_id) { + DefKind::Fn => { dump_abi_of_fn_item(tcx, id.owner_id.def_id.into(), attr); } - } - DefKind::TyAlias { .. } => { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { + DefKind::TyAlias { .. } => { dump_abi_of_fn_type(tcx, id.owner_id.def_id.into(), attr); } + _ => { + tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id.owner_id) }); + } } - DefKind::Impl { .. } => { - // To find associated functions we need to go into the child items here. - for &id in tcx.associated_item_def_ids(id.owner_id) { - if matches!(tcx.def_kind(id), DefKind::AssocFn) { - for attr in tcx.get_attrs(id, sym::rustc_abi) { + } + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { + // To find associated functions we need to go into the child items here. + for &id in tcx.associated_item_def_ids(id.owner_id) { + for attr in tcx.get_attrs(id, sym::rustc_abi) { + match tcx.def_kind(id) { + DefKind::AssocFn => { dump_abi_of_fn_item(tcx, id, attr); } + _ => { + tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) }); + } } } } - _ => {} } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 32dd02a4aa946..de55b5ec2cbda 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -873,32 +873,32 @@ pub struct DuplicateDiagnosticItemInCrate { } #[derive(Diagnostic)] -#[diag(passes_abi)] -pub struct Abi { +#[diag(passes_layout_abi)] +pub struct LayoutAbi { #[primary_span] pub span: Span, pub abi: String, } #[derive(Diagnostic)] -#[diag(passes_align)] -pub struct Align { +#[diag(passes_layout_align)] +pub struct LayoutAlign { #[primary_span] pub span: Span, pub align: String, } #[derive(Diagnostic)] -#[diag(passes_size)] -pub struct Size { +#[diag(passes_layout_size)] +pub struct LayoutSize { #[primary_span] pub span: Span, pub size: String, } #[derive(Diagnostic)] -#[diag(passes_homogeneous_aggregate)] -pub struct HomogeneousAggregate { +#[diag(passes_layout_homogeneous_aggregate)] +pub struct LayoutHomogeneousAggregate { #[primary_span] pub span: Span, pub homogeneous_aggregate: String, @@ -913,6 +913,13 @@ pub struct LayoutOf { pub ty_layout: String, } +#[derive(Diagnostic)] +#[diag(passes_layout_invalid_attribute)] +pub struct LayoutInvalidAttribute { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_abi_of)] pub struct AbiOf { @@ -922,6 +929,13 @@ pub struct AbiOf { pub fn_abi: String, } +#[derive(Diagnostic)] +#[diag(passes_abi_invalid_attribute)] +pub struct AbiInvalidAttribute { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_unrecognized_field)] pub struct UnrecognizedField { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index d839fee07a60d..f3c12e0746d97 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -8,7 +8,10 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; -use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField}; +use crate::errors::{ + LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf, + LayoutSize, UnrecognizedField, +}; pub fn test_layout(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs { @@ -16,12 +19,22 @@ pub fn test_layout(tcx: TyCtxt<'_>) { return; } for id in tcx.hir().items() { - if matches!( - tcx.def_kind(id.owner_id), - DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union - ) { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { - dump_layout_of(tcx, id.owner_id.def_id, attr); + for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { + match tcx.def_kind(id.owner_id) { + DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union => { + dump_layout_of(tcx, id.owner_id.def_id, attr); + } + _ => { + tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id.owner_id) }); + } + } + } + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { + // To find associated functions we need to go into the child items here. + for &id in tcx.associated_item_def_ids(id.owner_id) { + for _attr in tcx.get_attrs(id, sym::rustc_layout) { + tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) }); + } } } } @@ -38,28 +51,28 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.emit_err(Abi { + tcx.sess.emit_err(LayoutAbi { span: tcx.def_span(item_def_id.to_def_id()), abi: format!("{:?}", ty_layout.abi), }); } sym::align => { - tcx.sess.emit_err(Align { + tcx.sess.emit_err(LayoutAlign { span: tcx.def_span(item_def_id.to_def_id()), align: format!("{:?}", ty_layout.align), }); } sym::size => { - tcx.sess.emit_err(Size { + tcx.sess.emit_err(LayoutSize { span: tcx.def_span(item_def_id.to_def_id()), size: format!("{:?}", ty_layout.size), }); } sym::homogeneous_aggregate => { - tcx.sess.emit_err(HomogeneousAggregate { + tcx.sess.emit_err(LayoutHomogeneousAggregate { span: tcx.def_span(item_def_id.to_def_id()), homogeneous_aggregate: format!( "{:?}", diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 84d08ead08df3..8575021494d61 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -9,6 +9,8 @@ #![feature(rustc_attrs)] #![crate_type = "lib"] +struct S(u16); + #[rustc_abi(debug)] fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi @@ -18,7 +20,14 @@ type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi #[rustc_abi(debug)] fn test_generic(_x: *const T) { } //~ ERROR: fn_abi -struct S(u16); +#[rustc_abi(debug)] +const C: () = (); //~ ERROR: can only be applied to + +impl S { + #[rustc_abi(debug)] + const C: () = (); //~ ERROR: can only be applied to +} + impl S { #[rustc_abi(debug)] fn assoc_test(&self) { } //~ ERROR: fn_abi diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index dd0cfea351faa..2315288c3c750 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -87,7 +87,7 @@ error: fn_abi_of(test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:13:1 + --> $DIR/debug.rs:15:1 | LL | fn test(_x: u8) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:16:1 + --> $DIR/debug.rs:18:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -257,11 +257,23 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:19:1 + --> $DIR/debug.rs:21:1 | LL | fn test_generic(_x: *const T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:24:1 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:28:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + error: fn_abi_of(assoc_test) = FnAbi { args: [ ArgAbi { @@ -345,10 +357,10 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:24:5 + --> $DIR/debug.rs:33:5 | LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index b74a8d3b91730..97dc73d3aa70c 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -17,6 +17,9 @@ type Test = Result; //~ ERROR: layout_of #[rustc_layout(debug)] type T = impl std::fmt::Debug; //~ ERROR: layout_of +fn f() -> T { + 0i32 +} #[rustc_layout(debug)] pub union V { //~ ERROR: layout_of @@ -63,6 +66,10 @@ union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of #[rustc_layout(debug)] type X = std::mem::MaybeUninit; //~ ERROR: layout_of -fn f() -> T { - 0i32 +#[rustc_layout(debug)] +const C: () = (); //~ ERROR: can only be applied to + +impl S { + #[rustc_layout(debug)] + const C: () = (); //~ ERROR: can only be applied to } diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index c20a0198ccb8b..0973043c67814 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -344,7 +344,7 @@ error: layout_of(V) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:22:1 + --> $DIR/debug.rs:25:1 | LL | pub union V { | ^^^^^^^^^^^ @@ -368,7 +368,7 @@ error: layout_of(W) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:28:1 + --> $DIR/debug.rs:31:1 | LL | pub union W { | ^^^^^^^^^^^ @@ -392,7 +392,7 @@ error: layout_of(Y) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:34:1 + --> $DIR/debug.rs:37:1 | LL | pub union Y { | ^^^^^^^^^^^ @@ -416,7 +416,7 @@ error: layout_of(P1) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:41:1 + --> $DIR/debug.rs:44:1 | LL | union P1 { x: u32 } | ^^^^^^^^ @@ -440,7 +440,7 @@ error: layout_of(P2) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:45:1 + --> $DIR/debug.rs:48:1 | LL | union P2 { x: (u32, u32) } | ^^^^^^^^ @@ -464,7 +464,7 @@ error: layout_of(P3) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:53:1 + --> $DIR/debug.rs:56:1 | LL | union P3 { x: F32x4 } | ^^^^^^^^ @@ -488,7 +488,7 @@ error: layout_of(P4) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:57:1 + --> $DIR/debug.rs:60:1 | LL | union P4 { x: E } | ^^^^^^^^ @@ -517,7 +517,7 @@ error: layout_of(P5) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:61:1 + --> $DIR/debug.rs:64:1 | LL | union P5 { zst: [u16; 0], byte: u8 } | ^^^^^^^^ @@ -546,10 +546,22 @@ error: layout_of(std::mem::MaybeUninit) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:64:1 + --> $DIR/debug.rs:67:1 | LL | type X = std::mem::MaybeUninit; | ^^^^^^ -error: aborting due to 14 previous errors +error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases + --> $DIR/debug.rs:70:1 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases + --> $DIR/debug.rs:74:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: aborting due to 16 previous errors From 1abbd4cd4fa1c18c706505b71ed49cf0fda0ebee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Apr 2023 17:42:39 +0000 Subject: [PATCH 084/217] Render missing fields in tuple struct/enum as /* private fields */ --- src/librustdoc/html/render/print_item.rs | 44 +++++++++++++------ .../const-generics/const-generic-defaults.rs | 2 +- .../const-generics/const-generics-docs.rs | 4 +- tests/rustdoc/issue-88600.rs | 4 +- .../rustdoc/where.SWhere_Simd_item-decl.html | 2 +- tests/rustdoc/where.alpha_trait_decl.html | 2 +- tests/rustdoc/where.rs | 2 +- 7 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462c1..066b5d6b36c8c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1315,6 +1315,12 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( s: &'a [clean::Item], ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(|f| { + if s.iter() + .all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))) + { + return f.write_str("/* private fields */"); + } + for (i, ty) in s.iter().enumerate() { if i > 0 { f.write_str(", ")?; @@ -1936,21 +1942,31 @@ fn render_struct( } Some(CtorKind::Fn) => { w.write_str("("); - for (i, field) in fields.iter().enumerate() { - if i > 0 { - w.write_str(", "); - } - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), - clean::StructFieldItem(ref ty) => { - write!( - w, - "{}{}", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - ty.print(cx), - ) + if fields.iter().all(|field| { + matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) + }) { + write!(w, "/* private fields */"); + } else { + for (i, field) in fields.iter().enumerate() { + if i > 0 { + w.write_str(", "); + } + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), + clean::StructFieldItem(ref ty) => { + write!( + w, + "{}{}", + visibility_print_with_space( + field.visibility(tcx), + field.item_id, + cx + ), + ty.print(cx), + ) + } + _ => unreachable!(), } - _ => unreachable!(), } } w.write_str(")"); diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc/const-generics/const-generic-defaults.rs index f781c6a62f24b..7a0a794112d2d 100644 --- a/tests/rustdoc/const-generics/const-generic-defaults.rs +++ b/tests/rustdoc/const-generics/const-generic-defaults.rs @@ -1,5 +1,5 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foo(_);' +// 'pub struct Foo(' pub struct Foo(T); diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc/const-generics/const-generics-docs.rs index 828486a41d465..70a9518f05b40 100644 --- a/tests/rustdoc/const-generics/const-generics-docs.rs +++ b/tests/rustdoc/const-generics/const-generics-docs.rs @@ -33,7 +33,7 @@ impl Trait for [u8; N] {} // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ // 'pub struct Foo where u8: Trait' pub struct Foo where u8: Trait; -// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar(_)' +// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar(' pub struct Bar([T; N]); // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl Foowhere u8: Trait' @@ -92,7 +92,7 @@ macro_rules! define_me { } // @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foz(_);' +// 'pub struct Foz(/* private fields */);' define_me!(Foz); trait Q { diff --git a/tests/rustdoc/issue-88600.rs b/tests/rustdoc/issue-88600.rs index db0d102b74184..f89af472f6e42 100644 --- a/tests/rustdoc/issue-88600.rs +++ b/tests/rustdoc/issue-88600.rs @@ -8,10 +8,10 @@ pub struct S; // @has issue_88600/enum.FooEnum.html pub enum FooEnum { - // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(_)' + // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(/* private fields */)' // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0 HiddenTupleItem(#[doc(hidden)] H), - // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(_, _)' + // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(/* private fields */)' // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0 // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0 MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H), diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index 3e72ba2b74fe2..46708b9e4e925 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@ -
pub struct Simd<T>(_)
+
pub struct Simd<T>(/* private fields */)
 where
     T: MyTrait;
diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html index a7700055c9a74..0c0b2d1ceca9d 100644 --- a/tests/rustdoc/where.alpha_trait_decl.html +++ b/tests/rustdoc/where.alpha_trait_decl.html @@ -1,3 +1,3 @@ -pub struct Alpha<A>(_) +pub struct Alpha<A>(/* private fields */) where A: MyTrait; \ No newline at end of file diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 2aa9c8b546193..aea02c1403927 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -4,7 +4,7 @@ use std::io::Lines; pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(/* private fields */) where A: MyTrait" // @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code' pub struct Alpha(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravowhere B: MyTrait" From 65f25fe194d942365f8f5f870d4a6c166daff80f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Sep 2023 09:38:15 +0000 Subject: [PATCH 085/217] Don't report any errors in `lower_intrinsics`. They should have been typecked before. --- compiler/rustc_borrowck/messages.ftl | 2 ++ .../rustc_borrowck/src/session_diagnostics.rs | 7 +++++ compiler/rustc_borrowck/src/type_check/mod.rs | 29 +++++++++++++------ compiler/rustc_mir_transform/messages.ftl | 2 -- compiler/rustc_mir_transform/src/errors.rs | 7 ----- .../src/lower_intrinsics.rs | 12 +------- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 67fdb671742da..d8ca62565fa5f 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -166,6 +166,8 @@ borrowck_returned_lifetime_wrong = borrowck_returned_ref_escaped = returns a reference to a captured variable which escapes the closure body +borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item + borrowck_suggest_create_freash_reborrow = consider reborrowing the `Pin` instead of moving it diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index d1d8cfa74aa7c..ca3ccf439f280 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -452,3 +452,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> { #[note(borrowck_ty_no_impl_copy)] Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, } + +#[derive(Diagnostic)] +#[diag(borrowck_simd_shuffle_last_const)] +pub(crate) struct SimdShuffleLastConst { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 28286243e82f7..0f661421cdcf0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -50,7 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::session_diagnostics::MoveUnsized; +use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -1426,7 +1426,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *call_source); + self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1546,25 +1546,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))] fn check_call_inputs( &mut self, body: &Body<'tcx>, term: &Terminator<'tcx>, + func: &Operand<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, call_source: CallSource, ) { - debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind { - Some(func.ty(body, self.infcx.tcx)) - } else { - None - }; + let func_ty = func.ty(body, self.infcx.tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + if self.tcx().is_intrinsic(def_id) { + match self.tcx().item_name(def_id) { + sym::simd_shuffle => { + if !matches!(args[2], Operand::Constant(_)) { + self.tcx() + .sess + .emit_err(SimdShuffleLastConst { span: term.source_info.span }); + } + } + _ => {} + } + } + } debug!(?func_ty); for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { @@ -1572,7 +1583,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) + ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) } else { ConstraintCategory::Boring }; diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 2598eb2ed0968..5a99afc45b020 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -42,8 +42,6 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in } .not_inherited = items do not inherit unsafety from separate enclosing items -mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item - mir_transform_target_feature_call_label = call to function with `#[target_feature]` mir_transform_target_feature_call_note = can only be called if the required target features are available diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 4b796d79ef69a..35373bcaa41d5 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -258,10 +258,3 @@ pub(crate) struct MustNotSuspendReason { pub span: Span, pub reason: String, } - -#[derive(Diagnostic)] -#[diag(mir_transform_simd_shuffle_last_const)] -pub(crate) struct SimdShuffleLastConst { - #[primary_span] - pub span: Span, -} diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index a8dc91ca43969..13277d62bf4c9 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -1,11 +1,10 @@ //! Lowers intrinsic calls -use crate::{errors, MirPass}; +use crate::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct LowerIntrinsics; @@ -304,9 +303,6 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Unreachable; } } - sym::simd_shuffle => { - validate_simd_shuffle(tcx, args, terminator.source_info.span); - } _ => {} } } @@ -325,9 +321,3 @@ fn resolve_rust_intrinsic<'tcx>( } None } - -fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) { - if !matches!(args[2], Operand::Constant(_)) { - tcx.sess.emit_err(errors::SimdShuffleLastConst { span }); - } -} From 35e8b67fc2a48dc77245e805f3976acd51d45474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 2 Sep 2023 08:21:07 +0200 Subject: [PATCH 086/217] Use a reference to the lock in the guards --- .../rustc_data_structures/src/sync/freeze.rs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index ea75dcc4151da..d9f1d72d8510a 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -3,6 +3,7 @@ use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; use crate::sync::{DynSend, DynSync}; use std::{ cell::UnsafeCell, + marker::PhantomData, ops::{Deref, DerefMut}, sync::atomic::Ordering, }; @@ -37,10 +38,7 @@ impl FreezeLock { } else { Some(self.lock.read()) }, - // SAFETY: If this is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so - // this has shared access until the `FreezeReadGuard` is dropped. If this is frozen, - // the data cannot be modified and shared access is sound. - data: unsafe { &*self.data.get() }, + lock: self, } } @@ -50,12 +48,7 @@ impl FreezeLock { let _lock_guard = self.lock.write(); // Use relaxed ordering since we're in the write lock. assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); - FreezeWriteGuard { - _lock_guard, - // SAFETY: `_lock_guard` holds the lock to the `UnsafeCell` so this has mutable access - // until the `FreezeWriteGuard` is dropped. - data: unsafe { &mut *self.data.get() }, - } + FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData } } #[inline] @@ -75,14 +68,17 @@ impl FreezeLock { #[must_use = "if unused the FreezeLock may immediately unlock"] pub struct FreezeReadGuard<'a, T> { _lock_guard: Option>, - data: &'a T, + lock: &'a FreezeLock, } impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> { type Target = T; #[inline] fn deref(&self) -> &T { - self.data + // SAFETY: If `lock` is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so + // this has shared access until the `FreezeReadGuard` is dropped. If `lock` is frozen, + // the data cannot be modified and shared access is sound. + unsafe { &*self.lock.data.get() } } } @@ -90,20 +86,23 @@ impl<'a, T: 'a> Deref for FreezeReadGuard<'a, T> { #[must_use = "if unused the FreezeLock may immediately unlock"] pub struct FreezeWriteGuard<'a, T> { _lock_guard: WriteGuard<'a, ()>, - data: &'a mut T, + lock: &'a FreezeLock, + marker: PhantomData<&'a mut T>, } impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> { type Target = T; #[inline] fn deref(&self) -> &T { - self.data + // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has shared access. + unsafe { &*self.lock.data.get() } } } impl<'a, T: 'a> DerefMut for FreezeWriteGuard<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut T { - self.data + // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has mutable access. + unsafe { &mut *self.lock.data.get() } } } From df6e6a6d08f1ccd04e852896553e3fd7927dcdd6 Mon Sep 17 00:00:00 2001 From: mojave2 Date: Wed, 6 Sep 2023 10:51:28 +0800 Subject: [PATCH 087/217] fix #115348 --- compiler/rustc_mir_transform/src/check_unsafety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 0fce9cb19a848..d5af321d72639 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -483,7 +483,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu // `mir_built` force this. let body = &tcx.mir_built(def).borrow(); - if body.is_custom_mir() { + if body.is_custom_mir() || body.tainted_by_errors.is_some() { return tcx.arena.alloc(UnsafetyCheckResult { violations: Vec::new(), used_unsafe_blocks: Default::default(), From cfa211956309a444371442c5956d59a12260dcee Mon Sep 17 00:00:00 2001 From: mojave2 Date: Wed, 6 Sep 2023 17:46:39 +0800 Subject: [PATCH 088/217] add a regression test --- ...-positive-warning-of-unnecessary-unsafe.rs | 16 ++++++++++++++ ...itive-warning-of-unnecessary-unsafe.stderr | 21 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs create mode 100644 tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs new file mode 100644 index 0000000000000..68559338d4986 --- /dev/null +++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs @@ -0,0 +1,16 @@ +// Regression test for #115348. + +unsafe fn uwu() {} + +// Tests that the false-positive warning "unnecessary `unsafe` block" +// should not be reported, when the error "non-exhaustive patterns" +// appears. + +fn foo(x: Option) { + match x { + //~^ ERROR non-exhaustive patterns: `None` not covered + Some(_) => unsafe { uwu() }, + } +} + +fn main() {} diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr new file mode 100644 index 0000000000000..7384899b978ff --- /dev/null +++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs:10:11 + | +LL | match x { + | ^ pattern `None` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Some(_) => unsafe { uwu() }, +LL ~ None => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. From c4bb70f51b545d87a29bfb68898e5f4169345f8e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Sep 2023 13:26:56 +0200 Subject: [PATCH 089/217] Add regression test for private fields in tuple struct --- tests/rustdoc/private-fields-tuple-struct.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/rustdoc/private-fields-tuple-struct.rs diff --git a/tests/rustdoc/private-fields-tuple-struct.rs b/tests/rustdoc/private-fields-tuple-struct.rs new file mode 100644 index 0000000000000..c6989dd8cdfc8 --- /dev/null +++ b/tests/rustdoc/private-fields-tuple-struct.rs @@ -0,0 +1,15 @@ +// This test checks the diplay of "/* private fields */" sentence in tuple structs. +#![crate_name = "foo"] + +// @has 'foo/struct.A.html' '//*[@class="rust item-decl"]/code' 'pub struct A(pub u8, _);' +pub struct A(pub u8, u8); +// @has 'foo/struct.B.html' '//*[@class="rust item-decl"]/code' 'pub struct B(_, pub u8);' +pub struct B(u8, pub u8); +// @has 'foo/struct.C.html' '//*[@class="rust item-decl"]/code' 'pub struct C(_, pub u8, _);' +pub struct C(u8, pub u8, u8); +// @has 'foo/struct.D.html' '//*[@class="rust item-decl"]/code' 'pub struct D(pub u8, _, pub u8);' +pub struct D(pub u8, u8, pub u8); +// @has 'foo/struct.E.html' '//*[@class="rust item-decl"]/code' 'pub struct E(/* private fields */);' +pub struct E(u8); +// @has 'foo/struct.F.html' '//*[@class="rust item-decl"]/code' 'pub struct F(/* private fields */);' +pub struct F(u8, u8); From cc7c5ad20b5aa3ebaa12bbf62b48254e18609017 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 6 Sep 2023 14:03:12 +0300 Subject: [PATCH 090/217] Ty Debug now prints id and kind --- compiler/rustc_smir/src/stable_mir/ty.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 1db6b1e3d28eb..37c6be39a6410 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1,9 +1,16 @@ use super::{mir::Mutability, mir::Safety, with, AllocId, DefId}; use crate::rustc_internal::Opaque; +use std::fmt::{self, Debug, Formatter}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Ty(pub usize); +impl Debug for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish() + } +} + impl Ty { pub fn kind(&self) -> TyKind { with(|context| context.ty_kind(*self)) From 73d8dcb803aad67df31abe99f573a2320282bc60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 16:36:00 +0200 Subject: [PATCH 091/217] miri: catch function calls where the argument is caller-invalid / the return value callee-invalid --- .../rustc_const_eval/src/interpret/place.rs | 7 ++++ ...1.rs => cast_fn_ptr_invalid_callee_arg.rs} | 0 ... => cast_fn_ptr_invalid_callee_arg.stderr} | 4 +-- .../cast_fn_ptr_invalid_callee_ret.rs | 28 +++++++++++++++ .../cast_fn_ptr_invalid_callee_ret.stderr | 15 ++++++++ .../cast_fn_ptr_invalid_caller_arg.rs | 34 +++++++++++++++++++ .../cast_fn_ptr_invalid_caller_arg.stderr | 20 +++++++++++ ...2.rs => cast_fn_ptr_invalid_caller_ret.rs} | 0 ... => cast_fn_ptr_invalid_caller_ret.stderr} | 4 +-- 9 files changed, 108 insertions(+), 4 deletions(-) rename src/tools/miri/tests/fail/validity/{cast_fn_ptr1.rs => cast_fn_ptr_invalid_callee_arg.rs} (100%) rename src/tools/miri/tests/fail/validity/{cast_fn_ptr1.stderr => cast_fn_ptr_invalid_callee_arg.stderr} (83%) create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs create mode 100644 src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr rename src/tools/miri/tests/fail/validity/{cast_fn_ptr2.rs => cast_fn_ptr_invalid_caller_ret.rs} (100%) rename src/tools/miri/tests/fail/validity/{cast_fn_ptr2.stderr => cast_fn_ptr_invalid_caller_ret.stderr} (82%) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index d8ad82d3da0a1..90f2b470179e7 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -796,6 +796,13 @@ where dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { + // Generally for transmutation, data must be valid both at the old and new type. + // But if the types are the same, the 2nd validation below suffices. + if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { + self.validate_operand(&src.to_op(self)?)?; + } + + // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; if M::enforce_validity(self, dest.layout()) { diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs similarity index 100% rename from src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs rename to src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr similarity index 83% rename from src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr rename to src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index 133e4b2c16a10..21e403b47f8d8 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr1.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | LL | g(0usize as *const i32) | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | g(0usize as *const i32) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs new file mode 100644 index 0000000000000..7cdc15c609495 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -0,0 +1,28 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that +// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// type. That way we never get an "invalid value constructed" error inside the function, it can +// only possibly be detected when the return value is passed to the caller. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn f() -> NonZeroU32 { + mir! { + { + let tmp = ptr::addr_of_mut!(RET); + let ptr = tmp as *mut u32; + *ptr = 0; + Return() + } + } +} + +fn main() { + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; + // There's a NonZeroU32-to-u32 transmute happening here + f(); //~ERROR: expected something greater or equal to 1 +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr new file mode 100644 index 0000000000000..ccfb889093993 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + | +LL | f(); + | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs new file mode 100644 index 0000000000000..ee80186d4b50b --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -0,0 +1,34 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +fn f(c: u32) { + println!("{c}"); +} + +// Call that function in a bad way, with an invalid NonZeroU32, but without +// ever materializing this as a NonZeroU32 value outside the call itself. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn call(f: fn(NonZeroU32)) { + mir! { + let _res: (); + { + let c = 0; + let tmp = ptr::addr_of!(c); + let ptr = tmp as *const NonZeroU32; + // The call site now is a NonZeroU32-to-u32 transmute. + Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1 + } + retblock = { + Return() + } + } +} + +fn main() { + let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + call(f); +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr new file mode 100644 index 0000000000000..234c280400861 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | Call(_res = f(*ptr), retblock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC +note: inside `main` + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | call(f); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs similarity index 100% rename from src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs rename to src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr similarity index 82% rename from src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr rename to src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr index 21001f2b46096..bd9866acbd4fd 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC | LL | let _x = g(); | ^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | let _x = g(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 74a967bcec51461b189048c1cc7fdcc684efb0de Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 16:41:57 +0000 Subject: [PATCH 092/217] Support a few more rvalues. --- compiler/rustc_middle/src/ty/consts/int.rs | 5 ++ .../src/dataflow_const_prop.rs | 83 +++++++++++-------- ...oncrete.DataflowConstProp.panic-abort.diff | 76 +++++++++++++++++ ...ncrete.DataflowConstProp.panic-unwind.diff | 76 +++++++++++++++++ ...generic.DataflowConstProp.panic-abort.diff | 72 ++++++++++++++++ ...eneric.DataflowConstProp.panic-unwind.diff | 72 ++++++++++++++++ .../mir-opt/dataflow-const-prop/offset_of.rs | 49 +++++++++++ ...ute.from_char.DataflowConstProp.32bit.diff | 15 ++++ ...ute.from_char.DataflowConstProp.64bit.diff | 15 ++++ ....invalid_bool.DataflowConstProp.32bit.diff | 15 ++++ ....invalid_bool.DataflowConstProp.64bit.diff | 15 ++++ ....invalid_char.DataflowConstProp.32bit.diff | 15 ++++ ....invalid_char.DataflowConstProp.64bit.diff | 15 ++++ ...te.less_as_i8.DataflowConstProp.32bit.diff | 18 ++++ ...te.less_as_i8.DataflowConstProp.64bit.diff | 18 ++++ .../mir-opt/dataflow-const-prop/transmute.rs | 63 ++++++++++++++ ...on_as_integer.DataflowConstProp.32bit.diff | 22 +++++ ...on_as_integer.DataflowConstProp.64bit.diff | 22 +++++ ...reachable_box.DataflowConstProp.32bit.diff | 20 +++++ ...reachable_box.DataflowConstProp.64bit.diff | 20 +++++ ...chable_direct.DataflowConstProp.32bit.diff | 22 +++++ ...chable_direct.DataflowConstProp.64bit.diff | 22 +++++ ...reachable_mut.DataflowConstProp.32bit.diff | 24 ++++++ ...reachable_mut.DataflowConstProp.64bit.diff | 24 ++++++ ...reachable_ref.DataflowConstProp.32bit.diff | 20 +++++ ...reachable_ref.DataflowConstProp.64bit.diff | 20 +++++ ...te.valid_char.DataflowConstProp.32bit.diff | 15 ++++ ...te.valid_char.DataflowConstProp.64bit.diff | 15 ++++ 28 files changed, 835 insertions(+), 33 deletions(-) create mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.rs create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.rs create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff create mode 100644 tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index b16163edf1448..9d99344d5bdfb 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -226,6 +226,11 @@ impl ScalarInt { } } + #[inline] + pub fn try_from_target_usize(i: impl Into, tcx: TyCtxt<'_>) -> Option { + Self::try_from_uint(i, tcx.data_layout.pointer_size) + } + #[inline] pub fn assert_bits(self, target_size: Size) -> u128 { self.to_bits(target_size).unwrap_or_else(|size| { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index e713a6cf0068b..91bed82a6345f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -193,47 +193,64 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { rvalue: &Rvalue<'tcx>, state: &mut State, ) -> ValueOrPlace { - match rvalue { - Rvalue::Cast( - kind @ (CastKind::IntToInt - | CastKind::FloatToInt - | CastKind::FloatToFloat - | CastKind::IntToFloat), - operand, - ty, - ) => match self.eval_operand(operand, state) { - FlatSet::Elem(op) => match kind { - CastKind::IntToInt | CastKind::IntToFloat => { - self.ecx.int_to_int_or_float(&op, *ty) - } - CastKind::FloatToInt | CastKind::FloatToFloat => { - self.ecx.float_to_float_or_int(&op, *ty) - } - _ => unreachable!(), + let val = match rvalue { + Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self + .ecx + .int_to_int_or_float(&op, *ty) + .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, } - .map(|result| ValueOrPlace::Value(self.wrap_immediate(result))) - .unwrap_or(ValueOrPlace::TOP), - _ => ValueOrPlace::TOP, - }, + } + Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self + .ecx + .float_to_float_or_int(&op, *ty) + .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } + Rvalue::Cast(CastKind::Transmute, operand, _) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self.wrap_immediate(*op), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } Rvalue::BinaryOp(op, box (left, right)) => { // Overflows must be ignored here. let (val, _overflow) = self.binary_op(state, *op, left, right); - ValueOrPlace::Value(val) + val } Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) { - FlatSet::Elem(value) => self - .ecx - .unary_op(*op, &value) - .map(|val| ValueOrPlace::Value(self.wrap_immty(val))) - .unwrap_or(ValueOrPlace::Value(FlatSet::Top)), - FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom), - FlatSet::Top => ValueOrPlace::Value(FlatSet::Top), + FlatSet::Elem(value) => { + self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val)) + } + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, }, - Rvalue::Discriminant(place) => { - ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map())) + Rvalue::NullaryOp(null_op, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; + let val = match null_op { + NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), + NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), + NullOp::OffsetOf(fields) => layout + .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index())) + .bytes(), + _ => return ValueOrPlace::Value(FlatSet::Top), + }; + ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem) } - _ => self.super_rvalue(rvalue, state), - } + Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()), + _ => return self.super_rvalue(rvalue, state), + }; + ValueOrPlace::Value(val) } fn handle_constant( diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff new file mode 100644 index 0000000000000..c61414b6541a7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff @@ -0,0 +1,76 @@ +- // MIR for `concrete` before DataflowConstProp ++ // MIR for `concrete` after DataflowConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); +- _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; ++ _2 = const 4_usize; ++ _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); +- _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; ++ _4 = const 0_usize; ++ _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); +- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; ++ _6 = const 2_usize; ++ _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); +- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; ++ _8 = const 3_usize; ++ _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff new file mode 100644 index 0000000000000..0c3939a3456ac --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff @@ -0,0 +1,76 @@ +- // MIR for `concrete` before DataflowConstProp ++ // MIR for `concrete` after DataflowConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); +- _1 = must_use::(move _2) -> [return: bb1, unwind continue]; ++ _2 = const 4_usize; ++ _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); +- _3 = must_use::(move _4) -> [return: bb2, unwind continue]; ++ _4 = const 0_usize; ++ _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); +- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; ++ _6 = const 2_usize; ++ _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); +- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; ++ _8 = const 3_usize; ++ _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff new file mode 100644 index 0000000000000..d54d46870609d --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff @@ -0,0 +1,72 @@ +- // MIR for `generic` before DataflowConstProp ++ // MIR for `generic` after DataflowConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma, [0]); + _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma, [1]); + _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Delta, [1]); +- _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; ++ _6 = const 0_usize; ++ _5 = must_use::(const 0_usize) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Delta, [2]); +- _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; ++ _8 = const 2_usize; ++ _7 = must_use::(const 2_usize) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff new file mode 100644 index 0000000000000..6032a2274efe9 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff @@ -0,0 +1,72 @@ +- // MIR for `generic` before DataflowConstProp ++ // MIR for `generic` after DataflowConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma, [0]); + _1 = must_use::(move _2) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma, [1]); + _3 = must_use::(move _4) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Delta, [1]); +- _5 = must_use::(move _6) -> [return: bb3, unwind continue]; ++ _6 = const 0_usize; ++ _5 = must_use::(const 0_usize) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Delta, [2]); +- _7 = must_use::(move _8) -> [return: bb4, unwind continue]; ++ _8 = const 2_usize; ++ _7 = must_use::(const 2_usize) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs new file mode 100644 index 0000000000000..ccc90790e52c9 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -0,0 +1,49 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(offset_of)] + +use std::marker::PhantomData; +use std::mem::offset_of; + +struct Alpha { + x: u8, + y: u16, + z: Beta, +} + +struct Beta(u8, u8); + +struct Gamma { + x: u8, + y: u16, + _t: T, +} + +#[repr(C)] +struct Delta { + _phantom: PhantomData, + x: u8, + y: u16, +} + +// EMIT_MIR offset_of.concrete.DataflowConstProp.diff +fn concrete() { + let x = offset_of!(Alpha, x); + let y = offset_of!(Alpha, y); + let z0 = offset_of!(Alpha, z.0); + let z1 = offset_of!(Alpha, z.1); +} + +// EMIT_MIR offset_of.generic.DataflowConstProp.diff +fn generic() { + let gx = offset_of!(Gamma, x); + let gy = offset_of!(Gamma, y); + let dx = offset_of!(Delta, x); + let dy = offset_of!(Delta, y); +} + +fn main() { + concrete(); + generic::<()>(); +} diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..52f096ac0e4ea --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before DataflowConstProp ++ // MIR for `from_char` after DataflowConstProp + + fn from_char() -> i32 { + let mut _0: i32; + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); ++ _0 = const 82_i32; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..52f096ac0e4ea --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before DataflowConstProp ++ // MIR for `from_char` after DataflowConstProp + + fn from_char() -> i32 { + let mut _0: i32; + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); ++ _0 = const 82_i32; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..3972eb209a169 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_bool` before DataflowConstProp ++ // MIR for `invalid_bool` after DataflowConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; + scope 1 { + } + + bb0: { +- _0 = const -1_i8 as bool (Transmute); ++ _0 = const {transmute(0xff): bool}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..3972eb209a169 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_bool` before DataflowConstProp ++ // MIR for `invalid_bool` after DataflowConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; + scope 1 { + } + + bb0: { +- _0 = const -1_i8 as bool (Transmute); ++ _0 = const {transmute(0xff): bool}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..837dabde42a58 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_char` before DataflowConstProp ++ // MIR for `invalid_char` after DataflowConstProp + + fn invalid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const _ as char (Transmute); ++ _0 = const {transmute(0x7fffffff): char}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..837dabde42a58 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_char` before DataflowConstProp ++ // MIR for `invalid_char` after DataflowConstProp + + fn invalid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const _ as char (Transmute); ++ _0 = const {transmute(0x7fffffff): char}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..6091e169e8eb3 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff @@ -0,0 +1,18 @@ +- // MIR for `less_as_i8` before DataflowConstProp ++ // MIR for `less_as_i8` after DataflowConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; + let mut _1: std::cmp::Ordering; + scope 1 { + } + + bb0: { + StorageLive(_1); + _1 = Less; + _0 = move _1 as i8 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..6091e169e8eb3 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff @@ -0,0 +1,18 @@ +- // MIR for `less_as_i8` before DataflowConstProp ++ // MIR for `less_as_i8` after DataflowConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; + let mut _1: std::cmp::Ordering; + scope 1 { + } + + bb0: { + StorageLive(_1); + _1 = Less; + _0 = move _1 as i8 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs new file mode 100644 index 0000000000000..c25e33ab0b637 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.rs @@ -0,0 +1,63 @@ +// unit-test: DataflowConstProp +// compile-flags: -O --crate-type=lib +// ignore-endian-big +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +use std::mem::transmute; + +// EMIT_MIR transmute.less_as_i8.DataflowConstProp.diff +pub fn less_as_i8() -> i8 { + unsafe { transmute(std::cmp::Ordering::Less) } +} + +// EMIT_MIR transmute.from_char.DataflowConstProp.diff +pub fn from_char() -> i32 { + unsafe { transmute('R') } +} + +// EMIT_MIR transmute.valid_char.DataflowConstProp.diff +pub fn valid_char() -> char { + unsafe { transmute(0x52_u32) } +} + +// EMIT_MIR transmute.invalid_char.DataflowConstProp.diff +pub unsafe fn invalid_char() -> char { + unsafe { transmute(i32::MAX) } +} + +// EMIT_MIR transmute.invalid_bool.DataflowConstProp.diff +pub unsafe fn invalid_bool() -> bool { + unsafe { transmute(-1_i8) } +} + +// EMIT_MIR transmute.undef_union_as_integer.DataflowConstProp.diff +pub unsafe fn undef_union_as_integer() -> u32 { + union Union32 { value: u32, unit: () } + unsafe { transmute(Union32 { unit: () }) } +} + +// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff +pub unsafe fn unreachable_direct() -> ! { + let x: Never = unsafe { transmute(()) }; + match x {} +} + +// EMIT_MIR transmute.unreachable_ref.DataflowConstProp.diff +pub unsafe fn unreachable_ref() -> ! { + let x: &Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_mut.DataflowConstProp.diff +pub unsafe fn unreachable_mut() -> ! { + let x: &mut Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_box.DataflowConstProp.diff +pub unsafe fn unreachable_box() -> ! { + let x: Box = unsafe { transmute(1_usize) }; + match *x {} +} + +enum Never {} diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..fc0634b1f8fc9 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before DataflowConstProp ++ // MIR for `undef_union_as_integer` after DataflowConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; + let mut _1: undef_union_as_integer::Union32; + let mut _2: (); + scope 1 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = Union32 { value: move _2 }; + StorageDead(_2); + _0 = move _1 as u32 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..fc0634b1f8fc9 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before DataflowConstProp ++ // MIR for `undef_union_as_integer` after DataflowConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; + let mut _1: undef_union_as_integer::Union32; + let mut _2: (); + scope 1 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = Union32 { value: move _2 }; + StorageDead(_2); + _0 = move _1 as u32 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..d0c298ba23311 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_box` before DataflowConstProp ++ // MIR for `unreachable_box` after DataflowConstProp + + fn unreachable_box() -> ! { + let mut _0: !; + let _1: std::boxed::Box; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as std::boxed::Box (Transmute); ++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..d0c298ba23311 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_box` before DataflowConstProp ++ // MIR for `unreachable_box` after DataflowConstProp + + fn unreachable_box() -> ! { + let mut _0: !; + let _1: std::boxed::Box; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as std::boxed::Box (Transmute); ++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..acbb5cd1bc733 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff @@ -0,0 +1,22 @@ +- // MIR for `unreachable_direct` before DataflowConstProp ++ // MIR for `unreachable_direct` after DataflowConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; + let _1: Never; + let mut _2: (); + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = move _2 as Never (Transmute); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..acbb5cd1bc733 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff @@ -0,0 +1,22 @@ +- // MIR for `unreachable_direct` before DataflowConstProp ++ // MIR for `unreachable_direct` after DataflowConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; + let _1: Never; + let mut _2: (); + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = move _2 as Never (Transmute); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..2ffaeea72db27 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff @@ -0,0 +1,24 @@ +- // MIR for `unreachable_mut` before DataflowConstProp ++ // MIR for `unreachable_mut` after DataflowConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; + let _1: &mut Never; + let mut _2: &mut Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = const 1_usize as &mut Never (Transmute); ++ _2 = const {0x1 as &mut Never}; + _1 = &mut (*_2); + StorageDead(_2); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..2ffaeea72db27 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff @@ -0,0 +1,24 @@ +- // MIR for `unreachable_mut` before DataflowConstProp ++ // MIR for `unreachable_mut` after DataflowConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; + let _1: &mut Never; + let mut _2: &mut Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = const 1_usize as &mut Never (Transmute); ++ _2 = const {0x1 as &mut Never}; + _1 = &mut (*_2); + StorageDead(_2); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..31fcaafc5bca3 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_ref` before DataflowConstProp ++ // MIR for `unreachable_ref` after DataflowConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; + let _1: &Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as &Never (Transmute); ++ _1 = const {0x1 as &Never}; + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..31fcaafc5bca3 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_ref` before DataflowConstProp ++ // MIR for `unreachable_ref` after DataflowConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; + let _1: &Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as &Never (Transmute); ++ _1 = const {0x1 as &Never}; + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff new file mode 100644 index 0000000000000..402ef754a6484 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before DataflowConstProp ++ // MIR for `valid_char` after DataflowConstProp + + fn valid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); ++ _0 = const 'R'; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff new file mode 100644 index 0000000000000..402ef754a6484 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before DataflowConstProp ++ // MIR for `valid_char` after DataflowConstProp + + fn valid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); ++ _0 = const 'R'; + return; + } + } + From 22986b72e5a94768aec538bf3ccc0b834f9d7da2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Apr 2023 17:00:43 +0000 Subject: [PATCH 093/217] Implement algebraic simplifications. --- .../src/dataflow_const_prop.rs | 36 ++++++++++++++++--- .../dataflow-const-prop/boolean_identities.rs | 10 ++++++ ...ean_identities.test.DataflowConstProp.diff | 33 +++++++++++++++++ .../dataflow-const-prop/mult_by_zero.rs | 10 ++++++ .../mult_by_zero.test.DataflowConstProp.diff | 18 ++++++++++ 5 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/dataflow-const-prop/boolean_identities.rs create mode 100644 tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff create mode 100644 tests/mir-opt/dataflow-const-prop/mult_by_zero.rs create mode 100644 tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 91bed82a6345f..e5e419cdae9d9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -309,7 +309,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { ) -> (FlatSet, FlatSet) { let left = self.eval_operand(left, state); let right = self.eval_operand(right, state); + match (left, right) { + (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), + // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { Ok((Scalar::Int(val), overflow, _)) => { @@ -318,11 +321,36 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { _ => (FlatSet::Top, FlatSet::Top), } } - (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), - (_, _) => { - // Could attempt some algebraic simplifications here. - (FlatSet::Top, FlatSet::Top) + // Exactly one side is known, attempt some algebraic simplifications. + (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => { + let layout = const_arg.layout; + if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) { + return (FlatSet::Top, FlatSet::Top); + } + + let arg_scalar = const_arg.to_scalar(); + let Ok(arg_scalar) = arg_scalar.try_to_int() else { + return (FlatSet::Top, FlatSet::Top); + }; + let Ok(arg_value) = arg_scalar.to_bits(layout.size) else { + return (FlatSet::Top, FlatSet::Top); + }; + + match op { + BinOp::BitAnd if arg_value == 0 => (FlatSet::Elem(arg_scalar), FlatSet::Bottom), + BinOp::BitOr + if arg_value == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && arg_value == 1) => + { + (FlatSet::Elem(arg_scalar), FlatSet::Bottom) + } + BinOp::Mul if layout.ty.is_integral() && arg_value == 0 => { + (FlatSet::Elem(arg_scalar), FlatSet::Elem(false)) + } + _ => (FlatSet::Top, FlatSet::Top), + } } + (FlatSet::Top, FlatSet::Top) => (FlatSet::Top, FlatSet::Top), } } diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs new file mode 100644 index 0000000000000..9e911e85b8825 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR boolean_identities.test.DataflowConstProp.diff +pub fn test(x: bool, y: bool) -> bool { + (y | true) & (x & false) +} + +fn main() { + test(true, false); +} diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff new file mode 100644 index 0000000000000..5440c38ce4bcf --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff @@ -0,0 +1,33 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: bool, _2: bool) -> bool { + debug x => _1; + debug y => _2; + let mut _0: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + let mut _6: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = _2; +- _3 = BitOr(move _4, const true); ++ _3 = const true; + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = _1; +- _5 = BitAnd(move _6, const false); ++ _5 = const false; + StorageDead(_6); +- _0 = BitAnd(move _3, move _5); ++ _0 = const false; + StorageDead(_5); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs new file mode 100644 index 0000000000000..dbea1480445f7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR mult_by_zero.test.DataflowConstProp.diff +fn test(x : i32) -> i32 { + x * 0 +} + +fn main() { + test(10); +} diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff new file mode 100644 index 0000000000000..91bc10a562f7a --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff @@ -0,0 +1,18 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: i32) -> i32 { + debug x => _1; + let mut _0: i32; + let mut _2: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = Mul(move _2, const 0_i32); ++ _0 = const 0_i32; + StorageDead(_2); + return; + } + } + From fc6354379208be4c252da9fec15b4baa20e23a18 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 23 Apr 2023 16:15:22 +0000 Subject: [PATCH 094/217] Support array length. --- compiler/rustc_middle/src/mir/mod.rs | 7 +++ .../rustc_mir_dataflow/src/value_analysis.rs | 36 +++++++++++++++ .../src/dataflow_const_prop.rs | 30 ++++++++++++ ...ices.main.ConstProp.32bit.panic-abort.diff | 6 +-- ...ces.main.ConstProp.32bit.panic-unwind.diff | 6 +-- ...ices.main.ConstProp.64bit.panic-abort.diff | 6 +-- ...ces.main.ConstProp.64bit.panic-unwind.diff | 6 +-- .../bad_op_unsafe_oob_for_slices.rs | 3 +- tests/mir-opt/const_prop/large_array_index.rs | 1 - tests/mir-opt/const_prop/repeat.rs | 1 - ...n.DataflowConstProp.32bit.panic-abort.diff | 38 +++++++++++++++ ....DataflowConstProp.32bit.panic-unwind.diff | 38 +++++++++++++++ ...n.DataflowConstProp.64bit.panic-abort.diff | 38 +++++++++++++++ ....DataflowConstProp.64bit.panic-unwind.diff | 38 +++++++++++++++ .../dataflow-const-prop/array_index.rs | 8 ++++ ...n.DataflowConstProp.32bit.panic-abort.diff | 38 +++++++++++++++ ....DataflowConstProp.32bit.panic-unwind.diff | 38 +++++++++++++++ ...n.DataflowConstProp.64bit.panic-abort.diff | 38 +++++++++++++++ ....DataflowConstProp.64bit.panic-unwind.diff | 38 +++++++++++++++ .../dataflow-const-prop/large_array_index.rs | 9 ++++ ...n.DataflowConstProp.32bit.panic-abort.diff | 42 +++++++++++++++++ ....DataflowConstProp.32bit.panic-unwind.diff | 42 +++++++++++++++++ ...n.DataflowConstProp.64bit.panic-abort.diff | 42 +++++++++++++++++ ....DataflowConstProp.64bit.panic-unwind.diff | 42 +++++++++++++++++ tests/mir-opt/dataflow-const-prop/repeat.rs | 8 ++++ ...n.DataflowConstProp.32bit.panic-abort.diff | 46 +++++++++++++++++++ ....DataflowConstProp.32bit.panic-unwind.diff | 46 +++++++++++++++++++ ...n.DataflowConstProp.64bit.panic-abort.diff | 46 +++++++++++++++++++ ....DataflowConstProp.64bit.panic-unwind.diff | 46 +++++++++++++++++++ .../mir-opt/dataflow-const-prop/slice_len.rs | 9 ++++ ...implifyComparisonIntegral.panic-abort.diff | 8 ++-- ...mplifyComparisonIntegral.panic-unwind.diff | 8 ++-- 32 files changed, 782 insertions(+), 26 deletions(-) create mode 100644 tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/array_index.rs create mode 100644 tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/large_array_index.rs create mode 100644 tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/repeat.rs create mode 100644 tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff create mode 100644 tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff create mode 100644 tests/mir-opt/dataflow-const-prop/slice_len.rs diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fa51b52a25bfb..c690159368f4b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1751,6 +1751,13 @@ impl<'tcx> PlaceRef<'tcx> { } } +impl From for PlaceRef<'_> { + #[inline] + fn from(local: Local) -> Self { + PlaceRef { local, projection: &[] } + } +} + impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { for elem in self.projection.iter().rev() { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index a7778b2be9fc3..b5f39f1a9d547 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -581,6 +581,14 @@ impl State { } } + /// Retrieve the value stored for a place, or ⊤ if it is not tracked. + pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V { + match map.find_len(place) { + Some(place) => self.get_idx(place, map), + None => V::TOP, + } + } + /// Retrieve the value stored for a place index, or ⊤ if it is not tracked. pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V { match &self.0 { @@ -750,6 +758,24 @@ impl Map { self.value_count += 1; } + if let Some(ref_ty) = ty.builtin_deref(true) && let ty::Slice(..) = ref_ty.ty.kind() { + assert!(self.places[place].value_index.is_none(), "slices are not scalars"); + + // Prepend new child to the linked list. + let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen))); + self.places[len].next_sibling = self.places[place].first_child; + self.places[place].first_child = Some(len); + + let old = self.projections.insert((place, TrackElem::DerefLen), len); + assert!(old.is_none()); + + // Allocate a value slot if it doesn't have one. + if self.places[len].value_index.is_none() { + self.places[len].value_index = Some(self.value_count.into()); + self.value_count += 1; + } + } + // Recurse with all fields of this place. iter_fields(ty, tcx, param_env, |variant, field, ty| { worklist.push_back(( @@ -818,6 +844,11 @@ impl Map { self.find_extra(place, [TrackElem::Discriminant]) } + /// Locates the given place and applies `DerefLen`, if it exists in the tree. + pub fn find_len(&self, place: PlaceRef<'_>) -> Option { + self.find_extra(place, [TrackElem::DerefLen]) + } + /// Iterate over all direct children. pub fn children(&self, parent: PlaceIndex) -> impl Iterator + '_ { Children::new(self, parent) @@ -969,6 +1000,8 @@ pub enum TrackElem { Field(FieldIdx), Variant(VariantIdx), Discriminant, + // Length of a slice. + DerefLen, } impl TryFrom> for TrackElem { @@ -1108,6 +1141,9 @@ fn debug_with_context_rec( format!("{}.{}", place_str, field.index()) } } + TrackElem::DerefLen => { + format!("Len(*{})", place_str) + } }; debug_with_context_rec(child, &child_place_str, new, old, map, f)?; } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index e5e419cdae9d9..0bf0889b1d8a9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -184,6 +184,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } } + Rvalue::Cast( + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + operand, + _, + ) => { + let pointer = self.handle_operand(operand, state); + state.assign(target.as_ref(), pointer, self.map()); + + if let Some(target_len) = self.map().find_len(target.as_ref()) + && let operand_ty = operand.ty(self.local_decls, self.tcx) + && let Some(operand_ty) = operand_ty.builtin_deref(true) + && let ty::Array(_, len) = operand_ty.ty.kind() + && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int() + { + state.insert_value_idx(target_len, FlatSet::Elem(len), self.map()); + } + } _ => self.super_assign(target, rvalue, state), } } @@ -194,6 +211,19 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { state: &mut State, ) -> ValueOrPlace { let val = match rvalue { + Rvalue::Len(place) => { + let place_ty = place.ty(self.local_decls, self.tcx); + if let ty::Array(_, len) = place_ty.ty.kind() { + ConstantKind::Ty(*len) + .eval(self.tcx, self.param_env) + .try_to_scalar_int() + .map_or(FlatSet::Top, FlatSet::Elem) + } else if let [ProjectionElem::Deref] = place.projection[..] { + state.get_len(place.local.into(), self.map()) + } else { + FlatSet::Top + } + } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff index 55c774d555d4b..e443c8991f9a6 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff index dcab570ea776e..592f43f473979 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff index 55c774d555d4b..e443c8991f9a6 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff index dcab570ea776e..592f43f473979 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs index 7931c4f02ae67..d6b1a93f30499 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs @@ -1,8 +1,7 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen - // EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff #[allow(unconditional_panic)] fn main() { diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs index 6c03fe9d9c2f7..d226bd5467165 100644 --- a/tests/mir-opt/const_prop/large_array_index.rs +++ b/tests/mir-opt/const_prop/large_array_index.rs @@ -1,6 +1,5 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR large_array_index.main.ConstProp.diff diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs index 21dba84af375c..fb8b825ee368b 100644 --- a/tests/mir-opt/const_prop/repeat.rs +++ b/tests/mir-opt/const_prop/repeat.rs @@ -1,6 +1,5 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR repeat.main.ConstProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 0000000000000..ca5ac1b94fbfe --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 0000000000000..b49441f12c068 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 0000000000000..ca5ac1b94fbfe --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 0000000000000..b49441f12c068 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs new file mode 100644 index 0000000000000..ddb3646ca9b63 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -0,0 +1,8 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR array_index.main.DataflowConstProp.diff +fn main() { + let x: u32 = [0, 1, 2, 3][2]; +} diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 0000000000000..28676af83940c --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 0000000000000..b95ea03eb2b16 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 0000000000000..28676af83940c --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 0000000000000..b95ea03eb2b16 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,38 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = _2[_3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs new file mode 100644 index 0000000000000..af13c7d1020d6 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -0,0 +1,9 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR large_array_index.main.DataflowConstProp.diff +fn main() { + // check that we don't propagate this, because it's too large + let x: u8 = [0_u8; 5000][2]; +} diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 0000000000000..fce4165139dca --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _2 = _3[_4]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 0000000000000..966e19dc33a86 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _2 = _3[_4]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 0000000000000..fce4165139dca --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _2 = _3[_4]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 0000000000000..966e19dc33a86 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _2 = _3[_4]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs new file mode 100644 index 0000000000000..9fa353e44c543 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -0,0 +1,8 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR repeat.main.DataflowConstProp.diff +fn main() { + let x: u32 = [42; 8][2] + 0; +} diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 0000000000000..4a42fb01cb367 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _9: &[u32; 3]; + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _9 = const _; + _4 = _9; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = (*_2)[_6]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 0000000000000..67e45fd06107b --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _9: &[u32; 3]; + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _9 = const _; + _4 = _9; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = (*_2)[_6]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 0000000000000..4a42fb01cb367 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _9: &[u32; 3]; + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _9 = const _; + _4 = _9; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _1 = (*_2)[_6]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 0000000000000..67e45fd06107b --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _9: &[u32; 3]; + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _9 = const _; + _4 = _9; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { + _1 = (*_2)[_6]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs new file mode 100644 index 0000000000000..7937e5de7e3e2 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -0,0 +1,9 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// unit-test: DataflowConstProp +// compile-flags: -Zmir-enable-passes=+InstSimplify +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR slice_len.main.DataflowConstProp.diff +fn main() { + (&[1u32, 2, 3] as &[u32])[1]; +} diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index f61632728baa9..9d8f272abea3a 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -33,12 +33,10 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _8 = Len((*_2)); + _8 = const 3_usize; _9 = const 3_usize; -- _10 = Eq(move _8, const 3_usize); -- switchInt(move _10) -> [0: bb1, otherwise: bb2]; -+ nop; -+ switchInt(move _8) -> [3: bb2, otherwise: bb1]; + _10 = const true; + goto -> bb2; } bb1: { diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index f6c337be10f2c..738b0b1b3e5ac 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -33,12 +33,10 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _8 = Len((*_2)); + _8 = const 3_usize; _9 = const 3_usize; -- _10 = Eq(move _8, const 3_usize); -- switchInt(move _10) -> [0: bb1, otherwise: bb2]; -+ nop; -+ switchInt(move _8) -> [3: bb2, otherwise: bb1]; + _10 = const true; + goto -> bb2; } bb1: { From f96c6e04cb93459513e3d10626e4a3290fb6e8a0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 23 Apr 2023 16:15:22 +0000 Subject: [PATCH 095/217] Propagate PlaceElem::Index. --- .../src/dataflow_const_prop.rs | 44 ++++++++++++++----- ...n.DataflowConstProp.32bit.panic-abort.diff | 3 +- ....DataflowConstProp.32bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.64bit.panic-abort.diff | 3 +- ....DataflowConstProp.64bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.32bit.panic-abort.diff | 3 +- ....DataflowConstProp.32bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.64bit.panic-abort.diff | 3 +- ....DataflowConstProp.64bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.32bit.panic-abort.diff | 3 +- ....DataflowConstProp.32bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.64bit.panic-abort.diff | 3 +- ....DataflowConstProp.64bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.32bit.panic-abort.diff | 3 +- ....DataflowConstProp.32bit.panic-unwind.diff | 3 +- ...n.DataflowConstProp.64bit.panic-abort.diff | 3 +- ....DataflowConstProp.64bit.panic-unwind.diff | 3 +- 17 files changed, 65 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0bf0889b1d8a9..333a14be996b0 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment; use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; -use rustc_middle::mir::visit::{MutVisitor, Visitor}; +use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; @@ -545,11 +545,29 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> { if let Some(value) = self.before_effect.get(&(location, *place)) { let ty = place.ty(self.local_decls, self.tcx).ty; *operand = self.make_operand(*value, ty); + } else if !place.projection.is_empty() { + self.super_operand(operand, location) } } Operand::Constant(_) => {} } } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + location: Location, + ) -> Option> { + if let PlaceElem::Index(local) = elem + && let Some(value) = self.before_effect.get(&(location, local.into())) + && let Ok(offset) = value.try_to_target_usize(self.tcx) + && let Some(min_length) = offset.checked_add(1) + { + Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false }) + } else { + None + } + } } struct OperandCollector<'tcx, 'map, 'locals, 'a> { @@ -560,17 +578,21 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> { impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - match self.state.get(place.as_ref(), self.map) { - FlatSet::Top => (), - FlatSet::Elem(value) => { - self.visitor.before_effect.insert((location, *place), value); - } - FlatSet::Bottom => (), - } + if let Some(place) = operand.place() { + if let FlatSet::Elem(value) = self.state.get(place.as_ref(), self.map) { + self.visitor.before_effect.insert((location, place), value); + } else if !place.projection.is_empty() { + // Try to propagate into `Index` projections. + self.super_operand(operand, location) } - _ => (), + } + } + + fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) { + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt + && let FlatSet::Elem(value) = self.state.get(local.into(), self.map) + { + self.visitor.before_effect.insert((location, local.into()), value); } } } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff index ca5ac1b94fbfe..212ddc5b15418 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff index b49441f12c068..5c53d4f446131 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff index ca5ac1b94fbfe..212ddc5b15418 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff index b49441f12c068..5c53d4f446131 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff index 28676af83940c..6c612d4672500 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff index b95ea03eb2b16..87024da2628bf 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff index 28676af83940c..6c612d4672500 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff index b95ea03eb2b16..87024da2628bf 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -27,7 +27,8 @@ } bb1: { - _1 = _2[_3]; +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff index fce4165139dca..a18ef6c9db763 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff @@ -29,7 +29,8 @@ } bb1: { - _2 = _3[_4]; +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; _1 = Add(move _2, const 0_u32); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff index 966e19dc33a86..3356ef98b14a8 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff @@ -29,7 +29,8 @@ } bb1: { - _2 = _3[_4]; +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; _1 = Add(move _2, const 0_u32); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff index fce4165139dca..a18ef6c9db763 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff @@ -29,7 +29,8 @@ } bb1: { - _2 = _3[_4]; +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; _1 = Add(move _2, const 0_u32); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff index 966e19dc33a86..3356ef98b14a8 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff @@ -29,7 +29,8 @@ } bb1: { - _2 = _3[_4]; +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; _1 = Add(move _2, const 0_u32); StorageDead(_2); StorageDead(_4); diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff index 4a42fb01cb367..580ac8ea4c092 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -34,7 +34,8 @@ } bb1: { - _1 = (*_2)[_6]; +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff index 67e45fd06107b..4792db7ac0c4b 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -34,7 +34,8 @@ } bb1: { - _1 = (*_2)[_6]; +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff index 4a42fb01cb367..580ac8ea4c092 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -34,7 +34,8 @@ } bb1: { - _1 = (*_2)[_6]; +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; StorageDead(_6); StorageDead(_4); StorageDead(_2); diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff index 67e45fd06107b..4792db7ac0c4b 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -34,7 +34,8 @@ } bb1: { - _1 = (*_2)[_6]; +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; StorageDead(_6); StorageDead(_4); StorageDead(_2); From 3988ff25bc577a007926f016fac04333b1ea57bc Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 28 Aug 2023 16:57:29 +0800 Subject: [PATCH 096/217] suggest iter_mut() where trying to modify elements from .iter() --- .../src/diagnostics/mutability_errors.rs | 42 ++++++++++++++++++- .../issue-115259-suggest-iter-mut.fixed | 20 +++++++++ .../borrowck/issue-115259-suggest-iter-mut.rs | 20 +++++++++ .../issue-115259-suggest-iter-mut.stderr | 16 +++++++ .../issue-62387-suggest-iter-mut-2.fixed | 36 ++++++++++++++++ .../issue-62387-suggest-iter-mut-2.rs | 36 ++++++++++++++++ .../issue-62387-suggest-iter-mut-2.stderr | 16 +++++++ .../issue-62387-suggest-iter-mut.fixed | 30 +++++++++++++ .../borrowck/issue-62387-suggest-iter-mut.rs | 30 +++++++++++++ .../issue-62387-suggest-iter-mut.stderr | 29 +++++++++++++ 10 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed create mode 100644 tests/ui/borrowck/issue-115259-suggest-iter-mut.rs create mode 100644 tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut.rs create mode 100644 tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 31e863b8a4ed6..54a557c514547 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,9 +1,10 @@ +use hir::ExprKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -491,6 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), ); + self.suggest_using_iter_mut(&mut err); self.suggest_make_local_mut(&mut err, local, name); } _ => { @@ -953,6 +955,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) { + let source = self.body.source; + let hir = self.infcx.tcx.hir(); + if let InstanceDef::Item(def_id) = source.instance + && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) + && let ExprKind::Closure(closure) = kind && closure.movability == None + && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { + let mut cur_expr = expr; + while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { + if path_segment.ident.name == sym::iter { + // check `_ty` has `iter_mut` method + let res = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(cur_expr.hir_id) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() + }); + + if let Some(mut res) = res && res.peek().is_some() { + err.span_suggestion_verbose( + path_segment.ident.span, + "you may want to use `iter_mut` here", + "iter_mut", + Applicability::MaybeIncorrect, + ); + } + break; + } else { + cur_expr = recv; + } + } + } + } + fn suggest_make_local_mut( &self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed new file mode 100644 index 0000000000000..4653fe7375d38 --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +pub trait Layer { + fn process(&mut self) -> u32; +} + +pub struct State { + layers: Vec>, +} + +impl State { + pub fn process(&mut self) -> u32 { + self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process()) + //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs new file mode 100644 index 0000000000000..e0f6ab1321f83 --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +pub trait Layer { + fn process(&mut self) -> u32; +} + +pub struct State { + layers: Vec>, +} + +impl State { + pub fn process(&mut self) -> u32 { + self.layers.iter().fold(0, |result, mut layer| result + layer.process()) + //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr new file mode 100644 index 0000000000000..7e0fc2cf298b0 --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference + --> $DIR/issue-115259-suggest-iter-mut.rs:15:65 + | +LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process()) + | --------- ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut Box` + | +help: you may want to use `iter_mut` here + | +LL | self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process()) + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed new file mode 100644 index 0000000000000..f02374d8e11de --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed @@ -0,0 +1,36 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] +use std::path::PathBuf; + +#[derive(Clone)] +struct Container { + things: Vec, +} + +impl Container { + fn things(&mut self) -> &[PathBuf] { + &self.things + } +} + +// contains containers +struct ContainerContainer { + contained: Vec, +} + +impl ContainerContainer { + fn contained(&self) -> &[Container] { + &self.contained + } + + fn all_the_things(&mut self) -> &[PathBuf] { + let mut vec = self.contained.clone(); + let _a = + vec.iter_mut().flat_map(|container| container.things()).cloned().collect::>(); + //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs new file mode 100644 index 0000000000000..2d0b837a946ca --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs @@ -0,0 +1,36 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] +use std::path::PathBuf; + +#[derive(Clone)] +struct Container { + things: Vec, +} + +impl Container { + fn things(&mut self) -> &[PathBuf] { + &self.things + } +} + +// contains containers +struct ContainerContainer { + contained: Vec, +} + +impl ContainerContainer { + fn contained(&self) -> &[Container] { + &self.contained + } + + fn all_the_things(&mut self) -> &[PathBuf] { + let mut vec = self.contained.clone(); + let _a = + vec.iter().flat_map(|container| container.things()).cloned().collect::>(); + //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr new file mode 100644 index 0000000000000..19f194100a199 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45 + | +LL | vec.iter().flat_map(|container| container.things()).cloned().collect::>(); + | --------- ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut Container` + | +help: you may want to use `iter_mut` here + | +LL | vec.iter_mut().flat_map(|container| container.things()).cloned().collect::>(); + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed new file mode 100644 index 0000000000000..8bf2625de6da6 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed @@ -0,0 +1,30 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Debug)] +struct A { + a: i32, +} + +impl A { + fn double(&mut self) { + self.a += self.a + } +} + +fn baz() { + let mut v = [A { a: 4 }]; + v.iter_mut().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn bar() { + let mut v = [A { a: 4 }]; + v.iter_mut().rev().rev().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs new file mode 100644 index 0000000000000..39bc30bf29452 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs @@ -0,0 +1,30 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Debug)] +struct A { + a: i32, +} + +impl A { + fn double(&mut self) { + self.a += self.a + } +} + +fn baz() { + let mut v = [A { a: 4 }]; + v.iter().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn bar() { + let mut v = [A { a: 4 }]; + v.iter().rev().rev().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr new file mode 100644 index 0000000000000..fd58e43302025 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr @@ -0,0 +1,29 @@ +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut.rs:18:27 + | +LL | v.iter().for_each(|a| a.double()); + | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut A` + | +help: you may want to use `iter_mut` here + | +LL | v.iter_mut().for_each(|a| a.double()); + | ~~~~~~~~ + +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut.rs:25:39 + | +LL | v.iter().rev().rev().for_each(|a| a.double()); + | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut A` + | +help: you may want to use `iter_mut` here + | +LL | v.iter_mut().rev().rev().for_each(|a| a.double()); + | ~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. From 408dca7241f9af843ea4a88f04a7c3008105dcbe Mon Sep 17 00:00:00 2001 From: Darius Wiles Date: Wed, 6 Sep 2023 09:47:22 -0700 Subject: [PATCH 097/217] Fix minor grammar typo --- library/core/src/error.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/error.md b/library/core/src/error.md index 7771b8adc920b..a5deb71e6b80a 100644 --- a/library/core/src/error.md +++ b/library/core/src/error.md @@ -37,7 +37,7 @@ responsibilities they cover: The panic and error systems are not entirely distinct. Often times errors that are anticipated runtime failures in an API might instead represent bugs to a caller. For these situations the standard library provides APIs for -constructing panics with an `Error` as it's source. +constructing panics with an `Error` as its source. * [`Result::unwrap`] * [`Result::expect`] From dda103b1e33c4902deca8bccf614991ada781fa6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Sep 2023 18:33:08 +0000 Subject: [PATCH 098/217] Rustup to rustc 1.74.0-nightly (a991861ec 2023-09-05) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 39e348f37f3cf..2cc5d7777a621 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-09-01" +channel = "nightly-2023-09-06" components = ["rust-src", "rustc-dev", "llvm-tools"] From 2b02142eabb690d6ef6174cc6810cfd7b23346eb Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Wed, 6 Sep 2023 20:53:54 +0200 Subject: [PATCH 099/217] Bump: Include RISC-V intrinsics for stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index d77878b7299dd..6100854c4b360 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit d77878b7299dd7e286799a6e8447048b65d2a861 +Subproject commit 6100854c4b360f84da5ab25e7c75cb2080667ddc From ddd8878d697ac0006b25000137d457093917ae12 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 6 Sep 2023 22:13:56 +0000 Subject: [PATCH 100/217] Address feedback --- ...115385.rs => issue-115385-llvm-jump-threading.rs} | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) rename tests/codegen/issues/{issue-115385.rs => issue-115385-llvm-jump-threading.rs} (84%) diff --git a/tests/codegen/issues/issue-115385.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs similarity index 84% rename from tests/codegen/issues/issue-115385.rs rename to tests/codegen/issues/issue-115385-llvm-jump-threading.rs index 773b3507f2390..142e3596d9617 100644 --- a/tests/codegen/issues/issue-115385.rs +++ b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs @@ -1,5 +1,4 @@ // compile-flags: -O -Ccodegen-units=1 -// only-x86_64-unknown-linux-gnu #![crate_type = "lib"] @@ -19,6 +18,7 @@ impl Copy for Boolean {} extern "C" { fn set_value(foo: *mut i64); + fn bar(); } pub fn foo(x: bool) { @@ -39,12 +39,8 @@ pub fn foo(x: bool) { let l2 = unsafe { *foo.as_mut_ptr() }; if l2 == 2 { // CHECK: call void @bar - bar(); + unsafe { + bar(); + } } } - -#[no_mangle] -#[inline(never)] -pub fn bar() { - println!("Working correctly!"); -} From e10262ca0aa2ff434b33898d1d03413fdde60edf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 2 Sep 2023 04:02:11 +0000 Subject: [PATCH 101/217] Implement refinement lint for RPITIT --- compiler/rustc_errors/src/lib.rs | 6 +- compiler/rustc_hir_analysis/messages.ftl | 5 + .../src/check/compare_impl_item.rs | 8 + .../src/check/compare_impl_item/refine.rs | 271 ++++++++++++++++++ compiler/rustc_hir_analysis/src/errors.rs | 15 + compiler/rustc_lint_defs/src/builtin.rs | 46 ++- compiler/rustc_middle/src/ty/generic_args.rs | 2 +- .../in-trait/async-example-desugared-extra.rs | 3 +- .../in-trait/async-example-desugared.rs | 2 +- .../impl-trait/in-trait/auxiliary/rpitit.rs | 1 + .../in-trait/bad-item-bound-within-rpitit.rs | 1 + .../bad-item-bound-within-rpitit.stderr | 17 +- .../impl-trait/in-trait/deep-match-works.rs | 1 + tests/ui/impl-trait/in-trait/foreign.rs | 1 + tests/ui/impl-trait/in-trait/issue-102571.rs | 8 - .../impl-trait/in-trait/issue-102571.stderr | 2 +- tests/ui/impl-trait/in-trait/nested-rpitit.rs | 2 + tests/ui/impl-trait/in-trait/object-safety.rs | 2 +- tests/ui/impl-trait/in-trait/refine.rs | 36 +++ tests/ui/impl-trait/in-trait/refine.stderr | 63 ++++ tests/ui/impl-trait/in-trait/reveal.rs | 1 + .../rpitit-shadowed-by-missing-adt.rs | 1 + .../signature-mismatch.failure.stderr | 2 +- .../impl-trait/in-trait/signature-mismatch.rs | 4 +- .../in-trait/specialization-substs-remap.rs | 1 + tests/ui/impl-trait/in-trait/success.rs | 3 + 26 files changed, 483 insertions(+), 21 deletions(-) create mode 100644 compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs create mode 100644 tests/ui/impl-trait/in-trait/refine.rs create mode 100644 tests/ui/impl-trait/in-trait/refine.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 55c4ec66cd9ed..31547f19be0a2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -44,7 +44,7 @@ use rustc_fluent_macro::fluent_messages; pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; pub use rustc_span::ErrorGuaranteed; -use rustc_span::{Loc, Span}; +use rustc_span::{Loc, Span, DUMMY_SP}; use std::borrow::Cow; use std::error::Report; @@ -1754,7 +1754,7 @@ impl DelayedDiagnostic { BacktraceStatus::Captured => { let inner = &self.inner; self.inner.subdiagnostic(DelayedAtWithNewline { - span: inner.span.primary_span().unwrap(), + span: inner.span.primary_span().unwrap_or(DUMMY_SP), emitted_at: inner.emitted_at.clone(), note: self.note, }); @@ -1764,7 +1764,7 @@ impl DelayedDiagnostic { _ => { let inner = &self.inner; self.inner.subdiagnostic(DelayedAtWithoutNewline { - span: inner.span.primary_span().unwrap(), + span: inner.span.primary_span().unwrap_or(DUMMY_SP), emitted_at: inner.emitted_at.clone(), note: self.note, }); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 597cae6ff33ca..6a08fc528d70c 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -222,6 +222,11 @@ hir_analysis_return_type_notation_on_non_rpitit = .note = function returns `{$ty}`, which is not compatible with associated type return bounds .label = this function must be `async` or return `impl Trait` +hir_analysis_rpitit_refined = impl trait in impl method signature does not match trait method signature + .suggestion = replace the return type so that it matches the trait + .label = return type from trait method defined here + .unmatched_bound_label = this bound is stronger than that defined on the trait + hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index bd0ab6463f08a..92cc9759304fc 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -28,6 +28,8 @@ use rustc_trait_selection::traits::{ use std::borrow::Cow; use std::iter; +mod refine; + /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. /// @@ -53,6 +55,12 @@ pub(super) fn compare_impl_method<'tcx>( impl_trait_ref, CheckImpliedWfMode::Check, )?; + refine::check_refining_return_position_impl_trait_in_trait( + tcx, + impl_m, + trait_m, + impl_trait_ref, + ); }; } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs new file mode 100644 index 0000000000000..bc80cd62057f7 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -0,0 +1,271 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt}; +use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT; +use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; +use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::{ + elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt, +}; +use std::ops::ControlFlow; + +/// Check that an implementation does not refine an RPITIT from a trait method signature. +pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) { + if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { + return; + } + + let impl_def_id = impl_m.container_id(tcx); + let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id); + let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); + let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); + let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig); + + let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else { + // Error already emitted, no need to delay another. + return; + }; + + let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() }; + trait_m_sig.visit_with(&mut collector); + + // Bound that we find on RPITITs in the trait signature. + let mut trait_bounds = vec![]; + // Bounds that we find on the RPITITs in the impl signature. + let mut impl_bounds = vec![]; + + for trait_projection in collector.types.into_iter().rev() { + let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args); + let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args); + + // If the hidden type is not an opaque, then we have "refined" the trait signature. + let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + }; + + // This opaque also needs to be from the impl method -- otherwise, + // it's a refinement to a TAIT. + if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| { + matches!( + node.expect_item().expect_opaque_ty().origin, + hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id) + if def_id == impl_m.def_id.expect_local() + ) + }) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + } + + trait_bounds.extend( + tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args), + ); + impl_bounds.extend(elaborate( + tcx, + tcx.explicit_item_bounds(impl_opaque.def_id) + .iter_instantiated_copied(tcx, impl_opaque.args), + )); + } + + let hybrid_preds = tcx + .predicates_of(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args)) + .map(|(clause, _)| clause); + let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); + let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); + + let ref infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + + // Normalize the bounds. This has two purposes: + // + // 1. Project the RPITIT projections from the trait to the opaques on the impl, + // which means that they don't need to be mapped manually. + // + // 2. Project any other projections that show up in the bound. That makes sure that + // we don't consider `tests/ui/async-await/in-trait/async-associated-types.rs` + // to be refining. + let (trait_bounds, impl_bounds) = + ocx.normalize(&ObligationCause::dummy(), param_env, (trait_bounds, impl_bounds)); + + // Since we've normalized things, we need to resolve regions, since we'll + // possibly have introduced region vars during projection. We don't expect + // this resolution to have incurred any region errors -- but if we do, then + // just delay a bug. + let mut implied_wf_types = FxIndexSet::default(); + implied_wf_types.extend(trait_m_sig.inputs_and_output); + implied_wf_types.extend(ocx.normalize( + &ObligationCause::dummy(), + param_env, + trait_m_sig.inputs_and_output, + )); + if !ocx.select_all_or_error().is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (selection)", + ); + return; + } + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types), + ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (regions)", + ); + return; + } + // Resolve any lifetime variables that may have been introduced during normalization. + let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (resolution)", + ); + return; + }; + + // For quicker lookup, use an `IndexSet` + // (we don't use one earlier because it's not foldable..) + let trait_bounds = FxIndexSet::from_iter(trait_bounds); + + // Find any clauses that are present in the impl's RPITITs that are not + // present in the trait's RPITITs. This will trigger on trivial predicates, + // too, since we *do not* use the trait solver to prove that the RPITIT's + // bounds are not stronger -- we're doing a simple, syntactic compatibility + // check between bounds. This is strictly forwards compatible, though. + for (clause, span) in impl_bounds { + if !trait_bounds.contains(&clause) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig, + trait_m.def_id, + impl_m.def_id, + Some(span), + ); + return; + } + } +} + +struct ImplTraitInTraitCollector<'tcx> { + tcx: TyCtxt<'tcx>, + types: FxIndexSet>, +} + +impl<'tcx> TypeVisitor> for ImplTraitInTraitCollector<'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { + if let ty::Alias(ty::Projection, proj) = *ty.kind() + && self.tcx.is_impl_trait_in_trait(proj.def_id) + { + if self.types.insert(proj) { + for (pred, _) in self + .tcx + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.tcx, proj.args) + { + pred.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self) + } + } +} + +fn report_mismatched_rpitit_signature<'tcx>( + tcx: TyCtxt<'tcx>, + trait_m_sig: ty::FnSig<'tcx>, + trait_m_def_id: DefId, + impl_m_def_id: DefId, + unmatched_bound: Option, +) { + let mapping = std::iter::zip( + tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(), + tcx.fn_sig(impl_m_def_id).skip_binder().bound_vars(), + ) + .filter_map(|(impl_bv, trait_bv)| { + if let ty::BoundVariableKind::Region(impl_bv) = impl_bv + && let ty::BoundVariableKind::Region(trait_bv) = trait_bv + { + Some((impl_bv, trait_bv)) + } else { + None + } + }) + .collect(); + + let mut return_ty = + trait_m_sig.output().fold_with(&mut super::RemapLateBound { tcx, mapping: &mapping }); + + if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() { + let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else { + bug!(); + }; + let Some(future_output_ty) = tcx + .explicit_item_bounds(future_ty.def_id) + .iter_instantiated_copied(tcx, future_ty.args) + .find_map(|(clause, _)| match clause.kind().no_bound_vars()? { + ty::ClauseKind::Projection(proj) => proj.term.ty(), + _ => None, + }) + else { + bug!() + }; + return_ty = future_output_ty; + } + + let (span, impl_return_span, pre, post) = + match tcx.hir().get_by_def_id(impl_m_def_id.expect_local()).fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(span) => (tcx.def_span(impl_m_def_id), span, "-> ", " "), + hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""), + }; + let trait_return_span = + tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id), + hir::FnRetTy::Return(ty) => ty.span, + }); + + let span = unmatched_bound.unwrap_or(span); + tcx.emit_spanned_lint( + REFINING_IMPL_TRAIT, + tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), + span, + crate::errors::ReturnPositionImplTraitInTraitRefined { + impl_return_span, + trait_return_span, + pre, + post, + return_ty, + unmatched_bound, + }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9471ad9ca9063..a1b306edd64fc 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -919,6 +919,21 @@ pub struct UnusedAssociatedTypeBounds { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_rpitit_refined)] +pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { + #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")] + pub impl_return_span: Span, + #[label] + pub trait_return_span: Option, + #[label(hir_analysis_unmatched_bound_label)] + pub unmatched_bound: Option, + + pub pre: &'static str, + pub post: &'static str, + pub return_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_assoc_bound_on_const)] #[note] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 394b6aa1a06b4..df0151dc4997d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3381,6 +3381,7 @@ declare_lint_pass! { PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REFINING_IMPL_TRAIT, RENAMED_AND_REMOVED_LINTS, REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, @@ -4448,7 +4449,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// /// #![deny(ambiguous_glob_imports)] /// pub fn foo() -> u32 { /// use sub::*; @@ -4484,6 +4484,50 @@ declare_lint! { }; } +declare_lint! { + /// The `refining_impl_trait` lint detects usages of return-position impl + /// traits in trait signatures which are refined by implementations. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(return_position_impl_trait_in_trait)] + /// #![deny(refining_impl_trait)] + /// + /// use std::fmt::Display; + /// + /// trait AsDisplay { + /// fn as_display(&self) -> impl Display; + /// } + /// + /// impl<'s> AsDisplay for &'s str { + /// fn as_display(&self) -> Self { + /// *self + /// } + /// } + /// + /// fn main() { + /// // users can observe that the return type of + /// // `<&str as AsDisplay>::as_display()` is `&str`. + /// let x: &str = "".as_display(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Return-position impl trait in traits (RPITITs) desugar to associated types, + /// and callers of methods for types where the implementation is known are + /// able to observe the types written in the impl signature. This may be + /// intended behavior, but may also pose a semver hazard for authors of libraries + /// who do not wish to make stronger guarantees about the types than what is + /// written in the trait signature. + pub REFINING_IMPL_TRAIT, + Warn, + "impl trait in impl method signature does not match trait method signature", +} + declare_lint! { /// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes /// that were erroneously allowed in associated constants. diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 97dab5cb47e8b..53a3d5fc6be7f 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -440,7 +440,7 @@ impl<'tcx> GenericArgs<'tcx> { target_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { let defs = tcx.generics_of(source_ancestor); - tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.params.len()))) + tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count()))) } pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> { diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index 81e1e59a36249..1bbf4836a2abb 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -27,8 +27,7 @@ impl Future for MyFuture { } impl MyTrait for i32 { - // FIXME: this should eventually require `#[refine]` to compile, because it also provides - // `Clone`. + #[allow(refining_impl_trait)] fn foo(&self) -> impl Future + Clone { MyFuture(*self) } diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs index fb92ec786746f..0a5023176fef7 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared.rs @@ -12,7 +12,7 @@ trait MyTrait { } impl MyTrait for i32 { - fn foo(&self) -> impl Future + '_ { + fn foo(&self) -> impl Future { async { *self } } } diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index cfc2193f633e0..5bd5c48ca69e4 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -8,6 +8,7 @@ pub trait Foo { pub struct Foreign; impl Foo for Foreign { + #[allow(refining_impl_trait)] fn bar(self) -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs index ff7ad4bf38944..063adb7c378a8 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs @@ -17,6 +17,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR impl has stricter requirements than trait fn iter(&self) -> impl 'a + Iterator> { + //~^ WARN impl trait in impl method signature does not match trait method signature (*self).iter() } } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index 106b8a7c80474..8d08d5e521e8b 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -12,6 +12,21 @@ help: copy the `where` clause predicates from the trait LL | where Self: 'b; | ~~~~~~~~~~~~~~ -error: aborting due to previous error +warning: impl trait in impl method signature does not match trait method signature + --> $DIR/bad-item-bound-within-rpitit.rs:19:28 + | +LL | fn iter(&self) -> impl '_ + Iterator>; + | ----------------------------------------- return type from trait method defined here +... +LL | fn iter(&self) -> impl 'a + Iterator> { + | ^^ this bound is stronger than that defined on the trait + | + = note: `#[warn(refining_impl_trait)]` on by default +help: replace the return type so that it matches the trait + | +LL | fn iter(&self) -> impl Iterator::Item<'_>> + '_ { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs index 78cff97c61654..ffd10d9b1ff8c 100644 --- a/tests/ui/impl-trait/in-trait/deep-match-works.rs +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -10,6 +10,7 @@ trait Foo { } impl Foo for () { + #[allow(refining_impl_trait)] fn bar() -> Wrapper { Wrapper(0) } diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs index b0c93a0293512..035d91c187627 100644 --- a/tests/ui/impl-trait/in-trait/foreign.rs +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -9,6 +9,7 @@ use std::sync::Arc; // Implement an RPITIT from another crate. struct Local; impl Foo for Local { + #[allow(refining_impl_trait)] fn bar(self) -> Arc { Arc::new(String::new()) } diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index 61c91e64417b3..ccb53031c44bc 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -8,14 +8,6 @@ trait Foo { fn bar(self) -> impl Deref; } -struct A; - -impl Foo for A { - fn bar(self) -> &'static str { - "Hello, world" - } -} - fn foo(t: T) { let () = t.bar(); //~^ ERROR mismatched types diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr index 87219941d9161..594b9ae9cd6bc 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:20:9 + --> $DIR/issue-102571.rs:12:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref` diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs index 65285e3a3ccaf..cb943eb5af99f 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -13,6 +13,7 @@ trait Foo { struct A; impl Foo for A { + #[allow(refining_impl_trait)] fn bar(self) -> &'static str { "Hello, world" } @@ -21,6 +22,7 @@ impl Foo for A { struct B; impl Foo for B { + #[allow(refining_impl_trait)] fn bar(self) -> Box { Box::new(42) } diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index 9a231e59b09bf..d1c9fba4e99f3 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -8,7 +8,7 @@ trait Foo { } impl Foo for u32 { - fn baz(&self) -> u32 { + fn baz(&self) -> impl Debug { 32 } } diff --git a/tests/ui/impl-trait/in-trait/refine.rs b/tests/ui/impl-trait/in-trait/refine.rs new file mode 100644 index 0000000000000..e9b5e669fde1f --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine.rs @@ -0,0 +1,36 @@ +#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] +#![deny(refining_impl_trait)] + +trait Foo { + fn bar() -> impl Sized; +} + +struct A; +impl Foo for A { + fn bar() -> impl Copy {} + //~^ ERROR impl method signature does not match trait method signature +} + +struct B; +impl Foo for B { + fn bar() {} + //~^ ERROR impl method signature does not match trait method signature +} + +struct C; +impl Foo for C { + fn bar() -> () {} + //~^ ERROR impl method signature does not match trait method signature +} + +trait Late { + fn bar<'a>(&'a self) -> impl Sized + 'a; +} + +struct D; +impl Late for D { + fn bar(&self) -> impl Copy + '_ {} + //~^ ERROR impl method signature does not match trait method signature +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr new file mode 100644 index 0000000000000..28d53270da3d7 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine.stderr @@ -0,0 +1,63 @@ +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:10:22 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() -> impl Copy {} + | ^^^^ this bound is stronger than that defined on the trait + | +note: the lint level is defined here + --> $DIR/refine.rs:2:9 + | +LL | #![deny(refining_impl_trait)] + | ^^^^^^^^^^^^^^^^^^^ +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | ~~~~~~~~~~ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:16:5 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() {} + | ^^^^^^^^ + | +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | +++++++++++++ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:22:17 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() -> () {} + | ^^ + | +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | ~~~~~~~~~~ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:32:27 + | +LL | fn bar<'a>(&'a self) -> impl Sized + 'a; + | --------------- return type from trait method defined here +... +LL | fn bar(&self) -> impl Copy + '_ {} + | ^^^^ this bound is stronger than that defined on the trait + | +help: replace the return type so that it matches the trait + | +LL | fn bar(&self) -> impl Sized + '_ {} + | ~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs index d6ede1cc495c6..65425ba1a84f8 100644 --- a/tests/ui/impl-trait/in-trait/reveal.rs +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -8,6 +8,7 @@ trait Foo { } impl Foo for () { + #[allow(refining_impl_trait)] fn f() -> Box { Box::new(String::new()) } diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs index 7682884f87931..747f7ed9e727f 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs @@ -10,6 +10,7 @@ pub trait Tr { } impl Tr for () { + #[allow(refining_impl_trait)] fn w() -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr index 186580f57566d..468cf12f1bc03 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> $DIR/signature-mismatch.rs:77:10 + --> $DIR/signature-mismatch.rs:79:10 | LL | &'a self, | -------- this parameter and the return type are declared with different lifetimes... diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index c84a3b8f46b5e..135467d57eed7 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -3,7 +3,6 @@ //[success] check-pass #![feature(return_position_impl_trait_in_trait)] -#![allow(incomplete_features)] use std::future::Future; @@ -45,6 +44,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[allow(refining_impl_trait)] fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { async move { buff.to_vec() } } @@ -52,6 +52,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[allow(refining_impl_trait)] fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { async move { buff.to_vec() } } @@ -59,6 +60,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[allow(refining_impl_trait)] fn async_fn_multiple<'a, 'b>( &'a self, buff: &'b [u8], diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs index c9ee877db8ec5..83812d6cd8aca 100644 --- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -12,6 +12,7 @@ impl Foo for U where U: Copy, { + #[allow(refining_impl_trait)] fn bar(&self) -> U { *self } diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs index 4cbe682b46f73..f583604a021cf 100644 --- a/tests/ui/impl-trait/in-trait/success.rs +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -10,12 +10,14 @@ trait Foo { } impl Foo for i32 { + #[allow(refining_impl_trait)] fn bar(&self) -> i32 { *self } } impl Foo for &'static str { + #[allow(refining_impl_trait)] fn bar(&self) -> &'static str { *self } @@ -24,6 +26,7 @@ impl Foo for &'static str { struct Yay; impl Foo for Yay { + #[allow(refining_impl_trait)] fn bar(&self) -> String { String::from(":^)") } From 4745d34bc3ac377f8444d5dac94e0f206b7cded7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 00:20:31 +0000 Subject: [PATCH 102/217] Use self instead of the actual self ty --- .../src/check/compare_impl_item/refine.rs | 18 +++++++++++++++--- .../bad-item-bound-within-rpitit.stderr | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index bc80cd62057f7..b013f292e52e0 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -29,6 +29,18 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig); + // replace the self type of the trait ref with `Self` so that diagnostics render better. + let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions( + impl_m.def_id, + tcx.fn_sig(trait_m.def_id).instantiate( + tcx, + tcx.mk_args_from_iter( + [tcx.types.self_param.into()] + .into_iter() + .chain(trait_m_to_impl_m_args.iter().skip(1)), + ), + ), + ); let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else { // Error already emitted, no need to delay another. @@ -51,7 +63,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else { report_mismatched_rpitit_signature( tcx, - trait_m_sig, + trait_m_sig_with_self_for_diag, trait_m.def_id, impl_m.def_id, None, @@ -70,7 +82,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( }) { report_mismatched_rpitit_signature( tcx, - trait_m_sig, + trait_m_sig_with_self_for_diag, trait_m.def_id, impl_m.def_id, None, @@ -163,7 +175,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !trait_bounds.contains(&clause) { report_mismatched_rpitit_signature( tcx, - trait_m_sig, + trait_m_sig_with_self_for_diag, trait_m.def_id, impl_m.def_id, Some(span), diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index 8d08d5e521e8b..c0e07e94dabbe 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -24,8 +24,8 @@ LL | fn iter(&self) -> impl 'a + Iterator> { = note: `#[warn(refining_impl_trait)]` on by default help: replace the return type so that it matches the trait | -LL | fn iter(&self) -> impl Iterator::Item<'_>> + '_ { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | fn iter(&self) -> impl Iterator::Item<'_>> + '_ { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error; 1 warning emitted From 469dc8f0fa29760ccc0012de18b7edee4d2f22a4 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 6 Sep 2023 21:15:03 -0400 Subject: [PATCH 103/217] Add comments with the same level of detail as the PR description --- .../rustc_query_system/src/dep_graph/edges.rs | 13 +++++ .../rustc_query_system/src/dep_graph/graph.rs | 6 +-- .../src/dep_graph/serialized.rs | 47 ++++++++++++++++--- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs index ab161e9b5b56e..6ba3924f65eb0 100644 --- a/compiler/rustc_query_system/src/dep_graph/edges.rs +++ b/compiler/rustc_query_system/src/dep_graph/edges.rs @@ -1,6 +1,7 @@ use crate::dep_graph::DepNodeIndex; use smallvec::SmallVec; use std::hash::{Hash, Hasher}; +use std::iter::Extend; use std::ops::Deref; #[derive(Default, Debug)] @@ -58,3 +59,15 @@ impl FromIterator for EdgesVec { vec } } + +impl Extend for EdgesVec { + #[inline] + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for elem in iter { + self.push(elem); + } + } +} diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index c83b69d7f6389..7b7981e1425d3 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -574,11 +574,7 @@ impl DepGraph { let mut edges = EdgesVec::new(); K::read_deps(|task_deps| match task_deps { - TaskDepsRef::Allow(deps) => { - for index in deps.lock().reads.iter().copied() { - edges.push(index); - } - } + TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), TaskDepsRef::EvalAlways => { edges.push(DepNodeIndex::FOREVER_RED_NODE); } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 91460fa039955..4ba0cb31d0b66 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -11,6 +11,29 @@ //! sequence of NodeInfos to the different arrays in SerializedDepGraph. Since the //! node and edge count are stored at the end of the file, all the arrays can be //! pre-allocated with the right length. +//! +//! The encoding of the de-pgraph is generally designed around the fact that fixed-size +//! reads of encoded data are generally faster than variable-sized reads. Ergo we adopt +//! essentially the same varint encoding scheme used in the rmeta format; the edge lists +//! for each node on the graph store a 2-bit integer which is the number of bytes per edge +//! index in that node's edge list. We effectively ignore that an edge index of 0 could be +//! encoded with 0 bytes in order to not require 3 bits to store the byte width of the edges. +//! The overhead of calculating the correct byte width for each edge is mitigated by +//! building edge lists with [`EdgesVec`] which keeps a running max of the edges in a node. +//! +//! When we decode this data, we do not immediately create [`SerializedDepNodeIndex`] and +//! instead keep the data in its denser serialized form which lets us turn our on-disk size +//! efficiency directly into a peak memory reduction. When we convert these encoded-in-memory +//! values into their fully-deserialized type, we use a fixed-size read of the encoded array +//! then mask off any errant bytes we read. The array of edge index bytes is padded to permit this. +//! +//! We also encode and decode the entire rest of each node using [`SerializedNodeHeader`] +//! to let this encoding and decoding be done in one fixed-size operation. These headers contain +//! two [`Fingerprint`]s along with the serialized [`DepKind`], and the number of edge indices +//! in the node and the number of bytes used to encode the edge indices for this node. The +//! [`DepKind`], number of edges, and bytes per edge are all bit-packed together, if they fit. +//! If the number of edges in this node does not fit in the bits available in the header, we +//! store it directly after the header with leb128. use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex}; @@ -37,7 +60,7 @@ const DEP_NODE_SIZE: usize = std::mem::size_of::(); /// Amount of padding we need to add to the edge list data so that we can retrieve every /// SerializedDepNodeIndex with a fixed-size read then mask. const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; -/// Amount of bits we need to store the number of used bytes in a SerializedDepNodeIndex. +/// Number of bits we need to store the number of used bytes in a SerializedDepNodeIndex. /// Note that wherever we encode byte widths like this we actually store the number of bytes used /// minus 1; for a 4-byte value we technically would have 5 widths to store, but using one byte to /// store zeroes (which are relatively rare) is a decent tradeoff to save a bit in our bitfields. @@ -181,8 +204,15 @@ impl<'a, K: DepKind + Decodable>> Decodable> let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); - // This slightly over-estimates the amount of bytes used for all the edge data but never by - // more than ~6%, because over-estimation only occurs for large nodes. + // This estimation assumes that all of the encoded bytes are for the edge lists or for the + // fixed-size node headers. But that's not necessarily true; if any edge list has a length + // that spills out of the size we can bit-pack into SerializedNodeHeader then some of the + // total serialized size is also used by leb128-encoded edge list lengths. Neglecting that + // contribution to graph_bytes means our estimation of the bytes needed for edge_list_data + // slightly overshoots. But it cannot overshoot by much; consider that the worse case is + // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at + // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 + // length is about the same fractional overhead and it amortizes for yet greater lengths. let mut edge_list_data = Vec::with_capacity( graph_bytes - node_count * std::mem::size_of::>(), ); @@ -254,10 +284,13 @@ struct Unpacked { fingerprint: Fingerprint, } -// Bit fields are -// 0..? length of the edge -// ?..?+2 bytes per index -// ?+2..16 kind +// Bit fields, where +// M: bits used to store the length of a node's edge list +// N: bits used to store the byte width of elements of the edge list +// are +// 0..M length of the edge +// M..M+N bytes per index +// M+N..16 kind impl SerializedNodeHeader { const TOTAL_BITS: usize = std::mem::size_of::() * 8; const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; From 4d05da46e7154a6fc31bed3b217892d9a98cc0e3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 00:45:12 +0000 Subject: [PATCH 104/217] Don't emit refining_impl_trait for private items --- .../src/check/compare_impl_item/refine.rs | 28 +++++++++++++++++++ compiler/rustc_lint_defs/src/builtin.rs | 2 +- .../in-trait/async-example-desugared-extra.rs | 6 ++-- .../impl-trait/in-trait/auxiliary/rpitit.rs | 4 +-- .../in-trait/bad-item-bound-within-rpitit.rs | 2 +- .../impl-trait/in-trait/deep-match-works.rs | 8 +++--- tests/ui/impl-trait/in-trait/foreign.rs | 15 ++++++++-- tests/ui/impl-trait/in-trait/nested-rpitit.rs | 12 ++++---- tests/ui/impl-trait/in-trait/refine.rs | 24 ++++++++++++---- tests/ui/impl-trait/in-trait/refine.stderr | 2 +- tests/ui/impl-trait/in-trait/reveal.rs | 6 ++-- .../rpitit-shadowed-by-missing-adt.rs | 4 +-- .../impl-trait/in-trait/signature-mismatch.rs | 14 +++++----- .../in-trait/specialization-substs-remap.rs | 6 ++-- tests/ui/impl-trait/in-trait/success.rs | 12 ++++---- 15 files changed, 98 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index b013f292e52e0..a8149b634ef7c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -23,8 +23,22 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { return; } + // crate-private traits don't have any library guarantees, there's no need to do this check. + if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + return; + } + // If a type in the trait ref is private, then there's also no reason to to do this check. let impl_def_id = impl_m.container_id(tcx); + for arg in impl_trait_ref.args { + if let Some(ty) = arg.as_type() + && let Some(self_visibility) = type_visibility(tcx, ty) + && !self_visibility.is_public() + { + return; + } + } + let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id); let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); @@ -281,3 +295,17 @@ fn report_mismatched_rpitit_signature<'tcx>( }, ); } + +fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { + match *ty.kind() { + ty::Ref(_, ty, _) => type_visibility(tcx, ty), + ty::Adt(def, args) => { + if def.is_fundamental() { + type_visibility(tcx, args.type_at(0)) + } else { + Some(tcx.visibility(def.did())) + } + } + _ => None, + } +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index df0151dc4997d..2567e273e1131 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4496,7 +4496,7 @@ declare_lint! { /// /// use std::fmt::Display; /// - /// trait AsDisplay { + /// pub trait AsDisplay { /// fn as_display(&self) -> impl Display; /// } /// diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index 1bbf4836a2abb..3505690f1ec7a 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -2,14 +2,14 @@ // edition: 2021 #![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::future::Future; use std::pin::Pin; use std::task::Poll; -trait MyTrait { +pub trait MyTrait { async fn foo(&self) -> i32; } @@ -27,7 +27,7 @@ impl Future for MyFuture { } impl MyTrait for i32 { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn foo(&self) -> impl Future + Clone { MyFuture(*self) } diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index 5bd5c48ca69e4..6e99402113ad0 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,4 +1,4 @@ -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::ops::Deref; @@ -8,7 +8,7 @@ pub trait Foo { pub struct Foreign; impl Foo for Foreign { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(self) -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs index 063adb7c378a8..fbbbb8585d174 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs @@ -2,7 +2,7 @@ #![feature(return_position_impl_trait_in_trait)] -trait Iterable { +pub trait Iterable { type Item<'a> where Self: 'a; diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs index ffd10d9b1ff8c..fc290f11f9d9c 100644 --- a/tests/ui/impl-trait/in-trait/deep-match-works.rs +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -1,16 +1,16 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -struct Wrapper(T); +pub struct Wrapper(T); -trait Foo { +pub trait Foo { fn bar() -> Wrapper; } impl Foo for () { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar() -> Wrapper { Wrapper(0) } diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs index 035d91c187627..6285d7786d56a 100644 --- a/tests/ui/impl-trait/in-trait/foreign.rs +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -1,15 +1,25 @@ // check-pass // aux-build: rpitit.rs +#![feature(lint_reasons)] + extern crate rpitit; use rpitit::{Foo, Foreign}; use std::sync::Arc; // Implement an RPITIT from another crate. -struct Local; +pub struct Local; impl Foo for Local { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] + fn bar(self) -> Arc { + Arc::new(String::new()) + } +} + +struct LocalIgnoreRefining; +impl Foo for LocalIgnoreRefining { + #[deny(refining_impl_trait)] fn bar(self) -> Arc { Arc::new(String::new()) } @@ -24,4 +34,5 @@ fn main() { let &() = Foreign.bar(); let x: Arc = Local.bar(); + let x: Arc = LocalIgnoreRefining.bar(); } diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs index cb943eb5af99f..58ba1acaf14b0 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -1,28 +1,28 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; use std::ops::Deref; -trait Foo { +pub trait Foo { fn bar(self) -> impl Deref; } -struct A; +pub struct A; impl Foo for A { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(self) -> &'static str { "Hello, world" } } -struct B; +pub struct B; impl Foo for B { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(self) -> Box { Box::new(42) } diff --git a/tests/ui/impl-trait/in-trait/refine.rs b/tests/ui/impl-trait/in-trait/refine.rs index e9b5e669fde1f..a91f9b3e72258 100644 --- a/tests/ui/impl-trait/in-trait/refine.rs +++ b/tests/ui/impl-trait/in-trait/refine.rs @@ -1,33 +1,45 @@ #![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] #![deny(refining_impl_trait)] -trait Foo { +pub trait Foo { fn bar() -> impl Sized; } -struct A; +pub struct A; impl Foo for A { fn bar() -> impl Copy {} //~^ ERROR impl method signature does not match trait method signature } -struct B; +pub struct B; impl Foo for B { fn bar() {} //~^ ERROR impl method signature does not match trait method signature } -struct C; +pub struct C; impl Foo for C { fn bar() -> () {} //~^ ERROR impl method signature does not match trait method signature } -trait Late { +struct Private; +impl Foo for Private { + fn bar() -> () {} +} + +pub trait Arg { + fn bar() -> impl Sized; +} +impl Arg for A { + fn bar() -> () {} +} + +pub trait Late { fn bar<'a>(&'a self) -> impl Sized + 'a; } -struct D; +pub struct D; impl Late for D { fn bar(&self) -> impl Copy + '_ {} //~^ ERROR impl method signature does not match trait method signature diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr index 28d53270da3d7..65dfdf869e4b1 100644 --- a/tests/ui/impl-trait/in-trait/refine.stderr +++ b/tests/ui/impl-trait/in-trait/refine.stderr @@ -46,7 +46,7 @@ LL | fn bar() -> impl Sized {} | ~~~~~~~~~~ error: impl trait in impl method signature does not match trait method signature - --> $DIR/refine.rs:32:27 + --> $DIR/refine.rs:44:27 | LL | fn bar<'a>(&'a self) -> impl Sized + 'a; | --------------- return type from trait method defined here diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs index 65425ba1a84f8..b1b46d75b8f37 100644 --- a/tests/ui/impl-trait/in-trait/reveal.rs +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -1,14 +1,14 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -trait Foo { +pub trait Foo { fn f() -> Box; } impl Foo for () { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn f() -> Box { Box::new(String::new()) } diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs index 747f7ed9e727f..44a2b4303441e 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs @@ -1,6 +1,6 @@ // issue: 113903 -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::ops::Deref; @@ -10,7 +10,7 @@ pub trait Tr { } impl Tr for () { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn w() -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index 135467d57eed7..685c0f06e885b 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -2,17 +2,17 @@ // revisions: success failure //[success] check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::future::Future; -trait Captures<'a> {} +pub trait Captures<'a> {} impl Captures<'_> for T {} -trait Captures2<'a, 'b> {} +pub trait Captures2<'a, 'b> {} impl Captures2<'_, '_> for T {} -trait AsyncTrait { +pub trait AsyncTrait { #[cfg(success)] fn async_fn(&self, buff: &[u8]) -> impl Future>; @@ -44,7 +44,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { async move { buff.to_vec() } } @@ -52,7 +52,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { async move { buff.to_vec() } } @@ -60,7 +60,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn async_fn_multiple<'a, 'b>( &'a self, buff: &'b [u8], diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs index 83812d6cd8aca..41fc285883a84 100644 --- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -1,10 +1,10 @@ // check-pass #![feature(specialization)] -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -trait Foo { +pub trait Foo { fn bar(&self) -> impl Sized; } @@ -12,7 +12,7 @@ impl Foo for U where U: Copy, { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(&self) -> U { *self } diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs index f583604a021cf..7d415ea17a46f 100644 --- a/tests/ui/impl-trait/in-trait/success.rs +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -1,32 +1,32 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; -trait Foo { +pub trait Foo { fn bar(&self) -> impl Display; } impl Foo for i32 { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(&self) -> i32 { *self } } impl Foo for &'static str { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(&self) -> &'static str { *self } } -struct Yay; +pub struct Yay; impl Foo for Yay { - #[allow(refining_impl_trait)] + #[expect(refining_impl_trait)] fn bar(&self) -> String { String::from(":^)") } From 7714db873e3172f34bed004ac1976cf72a54c2e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 00:49:04 +0000 Subject: [PATCH 105/217] Add note --- compiler/rustc_hir_analysis/messages.ftl | 1 + compiler/rustc_hir_analysis/src/errors.rs | 1 + .../impl-trait/in-trait/bad-item-bound-within-rpitit.stderr | 1 + tests/ui/impl-trait/in-trait/refine.stderr | 4 ++++ 4 files changed, 7 insertions(+) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 6a08fc528d70c..50da227831200 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -226,6 +226,7 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match .suggestion = replace the return type so that it matches the trait .label = return type from trait method defined here .unmatched_bound_label = this bound is stronger than that defined on the trait + .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a1b306edd64fc..7614913f4bf51 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -921,6 +921,7 @@ pub struct UnusedAssociatedTypeBounds { #[derive(LintDiagnostic)] #[diag(hir_analysis_rpitit_refined)] +#[note] pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")] pub impl_return_span: Span, diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index c0e07e94dabbe..a5fb338ea4e13 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -21,6 +21,7 @@ LL | fn iter(&self) -> impl '_ + Iterator>; LL | fn iter(&self) -> impl 'a + Iterator> { | ^^ this bound is stronger than that defined on the trait | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate = note: `#[warn(refining_impl_trait)]` on by default help: replace the return type so that it matches the trait | diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr index 65dfdf869e4b1..29aa08e25bb91 100644 --- a/tests/ui/impl-trait/in-trait/refine.stderr +++ b/tests/ui/impl-trait/in-trait/refine.stderr @@ -7,6 +7,7 @@ LL | fn bar() -> impl Sized; LL | fn bar() -> impl Copy {} | ^^^^ this bound is stronger than that defined on the trait | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate note: the lint level is defined here --> $DIR/refine.rs:2:9 | @@ -26,6 +27,7 @@ LL | fn bar() -> impl Sized; LL | fn bar() {} | ^^^^^^^^ | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate help: replace the return type so that it matches the trait | LL | fn bar() -> impl Sized {} @@ -40,6 +42,7 @@ LL | fn bar() -> impl Sized; LL | fn bar() -> () {} | ^^ | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate help: replace the return type so that it matches the trait | LL | fn bar() -> impl Sized {} @@ -54,6 +57,7 @@ LL | fn bar<'a>(&'a self) -> impl Sized + 'a; LL | fn bar(&self) -> impl Copy + '_ {} | ^^^^ this bound is stronger than that defined on the trait | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate help: replace the return type so that it matches the trait | LL | fn bar(&self) -> impl Sized + '_ {} From 748476d94d0fd87a0ee149e49ab3b196bbb08420 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 01:20:43 +0000 Subject: [PATCH 106/217] Print the path of an RPITIT in RTN --- compiler/rustc_middle/src/ty/print/pretty.rs | 11 ++++++++ .../return-type-notation/basic.without.stderr | 4 +-- ...elf-auto-trait-issue-109924.current.stderr | 27 +++++++++++++++++++ ...g-self-auto-trait-issue-109924.next.stderr | 11 ++++++++ ...ormalizing-self-auto-trait-issue-109924.rs | 24 +++++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr create mode 100644 tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr create mode 100644 tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ac0c88468faa5..7191ed7a0f6fa 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1123,6 +1123,17 @@ pub trait PrettyPrinter<'tcx>: } } + if self.tcx().features().return_type_notation + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id) + && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() + && alias_ty.def_id == def_id + { + let num_args = self.tcx().generics_of(fn_def_id).count(); + write!(self, " {{ ")?; + self = self.print_def_path(fn_def_id, &args[..num_args])?; + write!(self, "() }}")?; + } + Ok(self) } diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index c2da4f57696f5..edce1045e245f 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -13,12 +13,12 @@ error: future cannot be sent between threads safely LL | is_send(foo::()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future>` + = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future> { ::method() }` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:13:5 | LL | T::method().await?; - | ^^^^^^^^^^^ await occurs here on type `impl Future>`, which is not `Send` + | ^^^^^^^^^^^ await occurs here on type `impl Future> { ::method() }`, which is not `Send` note: required by a bound in `is_send` --> $DIR/basic.rs:17:20 | diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr new file mode 100644 index 0000000000000..3b63ec45804ea --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr @@ -0,0 +1,27 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11 + | +LL | build(Bar); + | ----- ^^^ `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Send` is not implemented for `impl Future { <_ as Foo>::bar() }` +note: required by a bound in `build` + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:20:39 + | +LL | fn build(_: T) where T: Foo {} + | ^^^^ required by this bound in `build` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr new file mode 100644 index 0000000000000..6fab71787679b --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs new file mode 100644 index 0000000000000..b2cd9707db99f --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -0,0 +1,24 @@ +// revisions: current next +//[current] known-bug: #109924 +//[next] check-pass +//[next] compile-flags: -Ztrait-solver=next +// edition:2021 + +#![feature(async_fn_in_trait)] +#![feature(return_type_notation)] +//[next]~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + async fn bar(&self); +} + +struct Bar; +impl Foo for Bar { + async fn bar(&self) {} +} + +fn build(_: T) where T: Foo {} + +fn main() { + build(Bar); +} From a8f3c7684df5ac15c770ef92d58436aa3386cfcf Mon Sep 17 00:00:00 2001 From: surechen Date: Wed, 6 Sep 2023 11:33:03 +0800 Subject: [PATCH 107/217] fixes #114896 --- .../src/diagnostics/mutability_errors.rs | 84 +++++++++++++++++-- tests/ui/pattern/issue-114896.rs | 7 ++ tests/ui/pattern/issue-114896.stderr | 11 +++ 3 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 tests/ui/pattern/issue-114896.rs create mode 100644 tests/ui/pattern/issue-114896.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 31e863b8a4ed6..1df4e94b9145a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -370,12 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(span, format!("cannot {act}")); } if suggest { - err.span_suggestion_verbose( - local_decl.source_info.span.shrink_to_lo(), - "consider changing this to be mutable", - "mut ", - Applicability::MachineApplicable, - ); + self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local); let tcx = self.infcx.tcx; if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() { self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err); @@ -710,6 +705,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) } + fn construct_mut_suggestion_for_local_binding_patterns( + &self, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + local: Local, + ) { + let local_decl = &self.body.local_decls[local]; + debug!("local_decl: {:?}", local_decl); + let pat_span = match *local_decl.local_info() { + LocalInfo::User(BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + opt_ty_info: _, + opt_match_place: _, + pat_span, + })) => pat_span, + _ => local_decl.source_info.span, + }; + + struct BindingFinder { + span: Span, + hir_id: Option, + } + + impl<'tcx> Visitor<'tcx> for BindingFinder { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + if let hir::StmtKind::Local(local) = s.kind { + if local.pat.span == self.span { + self.hir_id = Some(local.hir_id); + } + } + hir::intravisit::walk_stmt(self, s); + } + } + + let hir_map = self.infcx.tcx.hir(); + let def_id = self.body.source.def_id(); + let hir_id = if let Some(local_def_id) = def_id.as_local() + && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) + { + let body = hir_map.body(body_id); + let mut v = BindingFinder { + span: pat_span, + hir_id: None, + }; + v.visit_body(body); + v.hir_id + } else { + None + }; + + // With ref-binding patterns, the mutability suggestion has to apply to + // the binding, not the reference (which would be a type error): + // + // `let &b = a;` -> `let &(mut b) = a;` + if let Some(hir_id) = hir_id + && let Some(hir::Node::Local(hir::Local { + pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, + .. + })) = hir_map.find(hir_id) + && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) + { + err.span_suggestion( + pat_span, + "consider changing this to be mutable", + format!("&(mut {name})"), + Applicability::MachineApplicable, + ); + return; + } + + err.span_suggestion_verbose( + local_decl.source_info.span.shrink_to_lo(), + "consider changing this to be mutable", + "mut ", + Applicability::MachineApplicable, + ); + } + // point to span of upvar making closure call require mutable borrow fn show_mutating_upvar( &self, diff --git a/tests/ui/pattern/issue-114896.rs b/tests/ui/pattern/issue-114896.rs new file mode 100644 index 0000000000000..cde37f658d6ae --- /dev/null +++ b/tests/ui/pattern/issue-114896.rs @@ -0,0 +1,7 @@ +fn main() { + fn x(a: &char) { + let &b = a; + b.make_ascii_uppercase(); +//~^ cannot borrow `b` as mutable, as it is not declared as mutable + } +} diff --git a/tests/ui/pattern/issue-114896.stderr b/tests/ui/pattern/issue-114896.stderr new file mode 100644 index 0000000000000..ffeb7bc136508 --- /dev/null +++ b/tests/ui/pattern/issue-114896.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable + --> $DIR/issue-114896.rs:4:9 + | +LL | let &b = a; + | -- help: consider changing this to be mutable: `&(mut b)` +LL | b.make_ascii_uppercase(); + | ^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. From ee9727e263f32d1bc3aa5b8fdbe42098e84aa923 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 04:51:36 +0000 Subject: [PATCH 108/217] Don't suggest dereferencing to unsized type --- .../src/traits/error_reporting/suggestions.rs | 15 ++++++++++++- .../dont-suggest-unsize-deref.rs | 15 +++++++++++++ .../dont-suggest-unsize-deref.stderr | 22 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs create mode 100644 tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 611ec6b00ef60..32fb10ce4a676 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -838,7 +838,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, real_trait_pred_and_base_ty, ); - if self.predicate_may_hold(&obligation) { + let sized_obligation = Obligation::new( + self.tcx, + obligation.cause.clone(), + obligation.param_env, + ty::TraitRef::from_lang_item( + self.tcx, + hir::LangItem::Sized, + obligation.cause.span, + [base_ty], + ), + ); + if self.predicate_may_hold(&obligation) + && self.predicate_must_hold_modulo_regions(&sized_obligation) + { let call_node = self.tcx.hir().get(*call_hir_id); let msg = "consider dereferencing here"; let is_receiver = matches!( diff --git a/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs b/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs new file mode 100644 index 0000000000000..8133036991c2b --- /dev/null +++ b/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs @@ -0,0 +1,15 @@ +fn use_iterator(itr: I) +where + I: IntoIterator, +{ +} + +fn pass_iterator(i: &dyn IntoIterator) +where + I: Iterator, +{ + use_iterator(i); + //~^ ERROR `&dyn IntoIterator` is not an iterator +} + +fn main() {} diff --git a/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr new file mode 100644 index 0000000000000..18ce9939eb26b --- /dev/null +++ b/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr @@ -0,0 +1,22 @@ +error[E0277]: `&dyn IntoIterator` is not an iterator + --> $DIR/dont-suggest-unsize-deref.rs:11:18 + | +LL | use_iterator(i); + | ------------ ^ `&dyn IntoIterator` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&dyn IntoIterator` + = note: required for `&dyn IntoIterator` to implement `IntoIterator` +note: required by a bound in `use_iterator` + --> $DIR/dont-suggest-unsize-deref.rs:3:8 + | +LL | fn use_iterator(itr: I) + | ------------ required by a bound in this function +LL | where +LL | I: IntoIterator, + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `use_iterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 67e7d85ad2c01376c5fe2de5f98f2b4fb4109bb7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 04:52:17 +0000 Subject: [PATCH 109/217] Rename folder typo --- .../dont-suggest-unsize-deref.rs | 0 .../dont-suggest-unsize-deref.stderr | 0 .../issue-39029.fixed | 0 .../{suggest-deferences => suggest-dereferences}/issue-39029.rs | 0 .../issue-39029.stderr | 0 .../issue-62530.fixed | 0 .../{suggest-deferences => suggest-dereferences}/issue-62530.rs | 0 .../issue-62530.stderr | 0 .../{suggest-deferences => suggest-dereferences}/multiple-0.fixed | 0 .../{suggest-deferences => suggest-dereferences}/multiple-0.rs | 0 .../multiple-0.stderr | 0 .../{suggest-deferences => suggest-dereferences}/multiple-1.rs | 0 .../multiple-1.stderr | 0 .../root-obligation.fixed | 0 .../root-obligation.rs | 0 .../root-obligation.stderr | 0 .../suggest-dereferencing-receiver-argument.fixed | 0 .../suggest-dereferencing-receiver-argument.rs | 0 .../suggest-dereferencing-receiver-argument.stderr | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/dont-suggest-unsize-deref.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/dont-suggest-unsize-deref.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-39029.fixed (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-39029.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-39029.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-62530.fixed (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-62530.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/issue-62530.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/multiple-0.fixed (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/multiple-0.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/multiple-0.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/multiple-1.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/multiple-1.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/root-obligation.fixed (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/root-obligation.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/root-obligation.stderr (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/suggest-dereferencing-receiver-argument.fixed (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/suggest-dereferencing-receiver-argument.rs (100%) rename tests/ui/traits/{suggest-deferences => suggest-dereferences}/suggest-dereferencing-receiver-argument.stderr (100%) diff --git a/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.rs rename to tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs diff --git a/tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/dont-suggest-unsize-deref.stderr rename to tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr diff --git a/tests/ui/traits/suggest-deferences/issue-39029.fixed b/tests/ui/traits/suggest-dereferences/issue-39029.fixed similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-39029.fixed rename to tests/ui/traits/suggest-dereferences/issue-39029.fixed diff --git a/tests/ui/traits/suggest-deferences/issue-39029.rs b/tests/ui/traits/suggest-dereferences/issue-39029.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-39029.rs rename to tests/ui/traits/suggest-dereferences/issue-39029.rs diff --git a/tests/ui/traits/suggest-deferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-39029.stderr rename to tests/ui/traits/suggest-dereferences/issue-39029.stderr diff --git a/tests/ui/traits/suggest-deferences/issue-62530.fixed b/tests/ui/traits/suggest-dereferences/issue-62530.fixed similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-62530.fixed rename to tests/ui/traits/suggest-dereferences/issue-62530.fixed diff --git a/tests/ui/traits/suggest-deferences/issue-62530.rs b/tests/ui/traits/suggest-dereferences/issue-62530.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-62530.rs rename to tests/ui/traits/suggest-dereferences/issue-62530.rs diff --git a/tests/ui/traits/suggest-deferences/issue-62530.stderr b/tests/ui/traits/suggest-dereferences/issue-62530.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/issue-62530.stderr rename to tests/ui/traits/suggest-dereferences/issue-62530.stderr diff --git a/tests/ui/traits/suggest-deferences/multiple-0.fixed b/tests/ui/traits/suggest-dereferences/multiple-0.fixed similarity index 100% rename from tests/ui/traits/suggest-deferences/multiple-0.fixed rename to tests/ui/traits/suggest-dereferences/multiple-0.fixed diff --git a/tests/ui/traits/suggest-deferences/multiple-0.rs b/tests/ui/traits/suggest-dereferences/multiple-0.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/multiple-0.rs rename to tests/ui/traits/suggest-dereferences/multiple-0.rs diff --git a/tests/ui/traits/suggest-deferences/multiple-0.stderr b/tests/ui/traits/suggest-dereferences/multiple-0.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/multiple-0.stderr rename to tests/ui/traits/suggest-dereferences/multiple-0.stderr diff --git a/tests/ui/traits/suggest-deferences/multiple-1.rs b/tests/ui/traits/suggest-dereferences/multiple-1.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/multiple-1.rs rename to tests/ui/traits/suggest-dereferences/multiple-1.rs diff --git a/tests/ui/traits/suggest-deferences/multiple-1.stderr b/tests/ui/traits/suggest-dereferences/multiple-1.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/multiple-1.stderr rename to tests/ui/traits/suggest-dereferences/multiple-1.stderr diff --git a/tests/ui/traits/suggest-deferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed similarity index 100% rename from tests/ui/traits/suggest-deferences/root-obligation.fixed rename to tests/ui/traits/suggest-dereferences/root-obligation.fixed diff --git a/tests/ui/traits/suggest-deferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/root-obligation.rs rename to tests/ui/traits/suggest-dereferences/root-obligation.rs diff --git a/tests/ui/traits/suggest-deferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/root-obligation.stderr rename to tests/ui/traits/suggest-dereferences/root-obligation.stderr diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed similarity index 100% rename from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed rename to tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs similarity index 100% rename from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs rename to tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr similarity index 100% rename from tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr rename to tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr From 4da6eb2ec6141eb7b4172d62e48c277ea8a191fb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 05:11:41 +0000 Subject: [PATCH 110/217] Test showing it doesnt work --- ...suggest-import-without-clobbering-attrs.fixed | 16 ++++++++++++++++ .../suggest-import-without-clobbering-attrs.rs | 15 +++++++++++++++ ...uggest-import-without-clobbering-attrs.stderr | 14 ++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed create mode 100644 tests/ui/resolve/suggest-import-without-clobbering-attrs.rs create mode 100644 tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed new file mode 100644 index 0000000000000..881b973e3ef1e --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed @@ -0,0 +1,16 @@ +// run-rustfix +// compile-flags: --cfg=whatever -Aunused + +#[cfg(whatever)] +use y::z; +use y::Whatever; + +mod y { + pub(crate) fn z() {} + pub(crate) struct Whatever; +} + +fn main() { + z(); + //~^ ERROR cannot find function `z` in this scope +} diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs new file mode 100644 index 0000000000000..38a1095703b69 --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs @@ -0,0 +1,15 @@ +// run-rustfix +// compile-flags: --cfg=whatever -Aunused + +#[cfg(whatever)] +use y::Whatever; + +mod y { + pub(crate) fn z() {} + pub(crate) struct Whatever; +} + +fn main() { + z(); + //~^ ERROR cannot find function `z` in this scope +} diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr new file mode 100644 index 0000000000000..d3574851d5c11 --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find function `z` in this scope + --> $DIR/suggest-import-without-clobbering-attrs.rs:13:5 + | +LL | z(); + | ^ not found in this scope + | +help: consider importing this function + | +LL + use y::z; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 03bee1f53dbf28c582d52ced9b165812514303f9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 05:13:52 +0000 Subject: [PATCH 111/217] Find lowest span out of use + attrs --- compiler/rustc_resolve/src/diagnostics.rs | 8 +++++++- .../resolve/suggest-import-without-clobbering-attrs.fixed | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d99fc07a7cd28..e9edfb53b4450 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2753,7 +2753,13 @@ fn search_for_any_use_in_items(items: &[P]) -> Option { for item in items { if let ItemKind::Use(..) = item.kind { if is_span_suitable_for_use_injection(item.span) { - return Some(item.span.shrink_to_lo()); + let mut lo = item.span.lo(); + for attr in &item.attrs { + if attr.span.eq_ctxt(item.span) { + lo = std::cmp::min(lo, attr.span.lo()); + } + } + return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } } } diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed index 881b973e3ef1e..fc68884fe9c6f 100644 --- a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed @@ -1,8 +1,8 @@ // run-rustfix // compile-flags: --cfg=whatever -Aunused -#[cfg(whatever)] use y::z; +#[cfg(whatever)] use y::Whatever; mod y { From 086cf346342263f3f53a7b1794fd7623f94d82fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 06:04:37 +0000 Subject: [PATCH 112/217] Don't ICE when computing ctype's repr_nullable_ptr for possibly-unsized ty --- compiler/rustc_lint/src/types.rs | 7 ++++++- .../lint/lint-ctypes-option-nonnull-unsized.rs | 8 ++++++++ .../lint-ctypes-option-nonnull-unsized.stderr | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs create mode 100644 tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fc4c29eb36d61..b30ab1b47338d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -923,7 +923,12 @@ pub(crate) fn repr_nullable_ptr<'tcx>( } // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi; + let field_ty_layout = tcx.layout_of(param_env.and(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } + + let field_ty_abi = &field_ty_layout.ok()?.abi; if let Abi::Scalar(field_ty_scalar) = field_ty_abi { match field_ty_scalar.valid_range(&tcx) { WrappingRange { start: 0, end } diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs new file mode 100644 index 0000000000000..ca08eb23a57eb --- /dev/null +++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs @@ -0,0 +1,8 @@ +#![deny(improper_ctypes_definitions)] + +extern "C" fn foo() -> Option<&'static T> { + //~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe + None +} + +fn main() {} diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr new file mode 100644 index 0000000000000..f59fb3cc750dd --- /dev/null +++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr @@ -0,0 +1,16 @@ +error: `extern` fn uses type `Option<&T>`, which is not FFI-safe + --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45 + | +LL | extern "C" fn foo() -> Option<&'static T> { + | ^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint +note: the lint level is defined here + --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9 + | +LL | #![deny(improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 14e59bb317c3c901bce83deb16ee9bfa5cc90e28 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 06:27:10 +0000 Subject: [PATCH 113/217] Lint node for PRIVATE_BOUNDS is the item which has the bounds --- compiler/rustc_privacy/src/lib.rs | 7 ++++--- tests/ui/privacy/private-bounds-locally-allowed.rs | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/ui/privacy/private-bounds-locally-allowed.rs diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 906a36cdb25d1..aedc7b22725aa 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1463,14 +1463,15 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let vis = self.tcx.local_visibility(local_def_id); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let span = self.tcx.def_span(self.item_def_id.to_def_id()); let vis_span = self.tcx.def_span(def_id); if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) { let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { - if vis_def_id == self.tcx.parent_module(hir_id).to_local_def_id() { + if vis_def_id + == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id() + { "private" } else if vis_def_id.is_top_level_module() { "crate-private" @@ -1504,7 +1505,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; self.tcx.emit_spanned_lint( lint, - hir_id, + self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), span, PrivateInterfacesOrBoundsLint { item_span: span, diff --git a/tests/ui/privacy/private-bounds-locally-allowed.rs b/tests/ui/privacy/private-bounds-locally-allowed.rs new file mode 100644 index 0000000000000..96a007a64f630 --- /dev/null +++ b/tests/ui/privacy/private-bounds-locally-allowed.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: --crate-type=lib + +#[allow(private_bounds)] +pub trait Foo: FooImpl {} + +trait FooImpl {} From 3bf3dadbc02736c66f56754769dcc001b040862b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 06:57:08 +0000 Subject: [PATCH 114/217] Ensure that dyn trait bounds stay sorted --- compiler/rustc_middle/src/ty/print/pretty.rs | 19 ++++++++----------- .../object/enforce-supertrait-projection.rs | 2 +- .../enforce-supertrait-projection.stderr | 2 +- .../dont-suggest-unsize-deref.rs | 2 +- .../dont-suggest-unsize-deref.stderr | 8 ++++---- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ac0c88468faa5..83c9269f24e36 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1239,21 +1239,18 @@ pub trait PrettyPrinter<'tcx>: .generics_of(principal.def_id) .own_args_no_defaults(cx.tcx(), principal.args); - let mut projections = predicates.projection_bounds(); - - let mut args = args.iter().cloned(); - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); + let mut projections: Vec<_> = predicates.projection_bounds().collect(); + projections.sort_by_cached_key(|proj| { + cx.tcx().item_name(proj.item_def_id()).to_string() + }); + if !args.is_empty() || !projections.is_empty() { p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { + cx = cx.comma_sep(args.iter().copied())?; + if !args.is_empty() && !projections.is_empty() { write!(cx, ", ")?; } - cx.comma_sep(projections) + cx.comma_sep(projections.iter().copied()) })); } } diff --git a/tests/ui/traits/object/enforce-supertrait-projection.rs b/tests/ui/traits/object/enforce-supertrait-projection.rs index 2c9b41eea2abe..0ea944ec2df55 100644 --- a/tests/ui/traits/object/enforce-supertrait-projection.rs +++ b/tests/ui/traits/object/enforce-supertrait-projection.rs @@ -7,7 +7,7 @@ trait Trait: SuperTrait::B> {} fn transmute(x: A) -> B { foo::>(x) - //~^ ERROR type mismatch resolving ` as SuperTrait>::A == B` + //~^ ERROR type mismatch resolving ` as SuperTrait>::A == B` } fn foo(x: T::A) -> B diff --git a/tests/ui/traits/object/enforce-supertrait-projection.stderr b/tests/ui/traits/object/enforce-supertrait-projection.stderr index 848b4e69a4bb8..2fb94d348966a 100644 --- a/tests/ui/traits/object/enforce-supertrait-projection.stderr +++ b/tests/ui/traits/object/enforce-supertrait-projection.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` +error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` --> $DIR/enforce-supertrait-projection.rs:9:17 | LL | fn transmute(x: A) -> B { diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs index 8133036991c2b..c6f9e3456186c 100644 --- a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs @@ -9,7 +9,7 @@ where I: Iterator, { use_iterator(i); - //~^ ERROR `&dyn IntoIterator` is not an iterator + //~^ ERROR `&dyn IntoIterator` is not an iterator } fn main() {} diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr index 18ce9939eb26b..bd0e7ca2c02e5 100644 --- a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr @@ -1,13 +1,13 @@ -error[E0277]: `&dyn IntoIterator` is not an iterator +error[E0277]: `&dyn IntoIterator` is not an iterator --> $DIR/dont-suggest-unsize-deref.rs:11:18 | LL | use_iterator(i); - | ------------ ^ `&dyn IntoIterator` is not an iterator + | ------------ ^ `&dyn IntoIterator` is not an iterator | | | required by a bound introduced by this call | - = help: the trait `Iterator` is not implemented for `&dyn IntoIterator` - = note: required for `&dyn IntoIterator` to implement `IntoIterator` + = help: the trait `Iterator` is not implemented for `&dyn IntoIterator` + = note: required for `&dyn IntoIterator` to implement `IntoIterator` note: required by a bound in `use_iterator` --> $DIR/dont-suggest-unsize-deref.rs:3:8 | From c9810261956faa1152ade6a37efe6583b2caaa20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 11:12:23 +0200 Subject: [PATCH 115/217] extend comments around PassMode::Direct --- compiler/rustc_codegen_llvm/src/abi.rs | 42 ++++++++++++++++++++++- compiler/rustc_target/src/abi/call/mod.rs | 4 ++- compiler/rustc_ty_utils/src/abi.rs | 2 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 863cb7068f865..1e72b7db1e4e7 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -340,15 +340,53 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { }; for arg in args { + // Note that the exact number of arguments pushed here is carefully synchronized with + // code all over the place, both in the codegen_llvm and codegen_ssa crates. That's how + // other code then knows which LLVM argument(s) correspond to the n-th Rust argument. let llarg_ty = match &arg.mode { PassMode::Ignore => continue, - PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), + PassMode::Direct(_) => { + // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges), + // and for Scalar ABIs the LLVM type is fully determined by `layout.abi`, + // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for + // aggregates... + if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) { + // This is the most critical case for ABI compatibility, since + // `immediate_llvm_type` will use `layout.fields` to turn this Rust type + // into an LLVM type. ABI-compatible Rust types can have different `fields`, + // so we need to be very sure that LLVM wil treat those different types in + // an ABI-compatible way. Mostly we do this by disallowing + // `PassMode::Direct` for aggregates, but we actually do use that mode on + // wasm. wasm doesn't have aggregate types so we are fairly sure that LLVM + // will treat `{ i32, i32, i32 }` and `{ { i32, i32, i32 } }` the same way + // for ABI purposes. + assert!( + matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"), + "`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}", + arg.layout, + ); + } + arg.layout.immediate_llvm_type(cx) + } PassMode::Pair(..) => { + // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges), + // so for ScalarPair we can easily be sure that we are generating ABI-compatible + // LLVM IR. + assert!( + matches!(arg.layout.abi, abi::Abi::ScalarPair(..)), + "PassMode::Pair for type {}", + arg.layout.ty + ); llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + assert!(arg.layout.is_unsized()); + // Construct the type of a (wide) pointer to `ty`, and pass its two fields. + // Any two ABI-compatible unsized types have the same metadata type and + // moreover the same metadata value leads to the same dynamic size and + // alignment, so this respects ABI compatibility. let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty); let ptr_layout = cx.layout_of(ptr_ty); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -360,6 +398,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if *pad_i32 { llargument_tys.push(Reg::i32().llvm_type(cx)); } + // Compute the LLVM type we use for this function from the cast type. + // We assume here that ABI-compatible Rust types have the same cast type. cast.llvm_type(cx) } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(), diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8d573def9bb05..9a905dbc806d2 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -36,7 +36,7 @@ pub enum PassMode { Ignore, /// Pass the argument directly. /// - /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases `Aggregate`. + /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases (e.g. on wasm) `Aggregate`. Direct(ArgAttributes), /// Pass a pair's elements directly in two arguments. /// @@ -465,6 +465,7 @@ pub struct ArgAbi<'a, Ty> { } impl<'a, Ty> ArgAbi<'a, Ty> { + /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`. pub fn new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, @@ -478,6 +479,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), ), Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), + // The `Aggregate` ABI is almost always adjusted later. Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 802391f1aadea..3ffe670d87ac1 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -520,6 +520,8 @@ fn fn_abi_adjust_for_abi<'tcx>( _ => return, } + // `Aggregate` ABI must be adjusted to ensure that ABI-compatible Rust types are passed + // the same way. let size = arg.layout.size; if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) { From 8922c0c541c0fbfe6d0465eed6362a2bdbe6a0f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 11:13:20 +0200 Subject: [PATCH 116/217] add support for rustc_abi(assert_eq) and use it to test some repr(transparent) cases --- compiler/rustc_passes/messages.ftl | 4 + compiler/rustc_passes/src/abi_test.rs | 78 +++++++++++++- compiler/rustc_passes/src/errors.rs | 9 ++ compiler/rustc_span/src/symbol.rs | 1 + tests/codegen/repr/transparent.rs | 1 - tests/ui/abi/debug.rs | 6 ++ tests/ui/abi/debug.stderr | 148 +++++++++++++++++++++++++- tests/ui/abi/transparent.rs | 79 ++++++++++++++ 8 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 tests/ui/abi/transparent.rs diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 602d614295c18..9f3cd656bd100 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -6,6 +6,10 @@ passes_abi_invalid_attribute = `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions +passes_abi_ne = + ABIs are not compatible + left ABI = {$left} + right ABI = {$right} passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 4653a9c2b39da..48c18912703de 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -5,9 +5,9 @@ use rustc_middle::ty::layout::{FnAbiError, LayoutError}; use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_target::abi::call::FnAbi; +use rustc_target::abi::call::{ArgAbi, FnAbi}; -use crate::errors::{AbiInvalidAttribute, AbiOf, UnrecognizedField}; +use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs { @@ -114,6 +114,32 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { } } +fn test_arg_abi_eq<'tcx>( + abi1: &'tcx ArgAbi<'tcx, Ty<'tcx>>, + abi2: &'tcx ArgAbi<'tcx, Ty<'tcx>>, +) -> bool { + // Ideally we'd just compare the `mode`, but that is not enough -- for some modes LLVM will look + // at the type. Comparing the `mode` and `layout.abi` should catch basically everything though + // (except for tricky cases around unized types). + // This *is* overly strict (e.g. we compare the sign of integer `Primitive`s, or parts of `ArgAttributes` that do not affect ABI), + // but for the purpose of ensuring repr(transparent) ABI compatibility that is fine. + abi1.mode == abi2.mode && abi1.layout.abi == abi2.layout.abi +} + +fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, Ty<'tcx>>) -> bool { + if abi1.conv != abi2.conv + || abi1.args.len() != abi2.args.len() + || abi1.c_variadic != abi2.c_variadic + || abi1.fixed_count != abi2.fixed_count + || abi1.can_unwind != abi2.can_unwind + { + return false; + } + + test_arg_abi_eq(&abi1.ret, &abi2.ret) + && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| test_arg_abi_eq(arg1, arg2)) +} + fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); @@ -140,6 +166,54 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { fn_abi: format!("{:#?}", abi), }); } + sym::assert_eq => { + let ty::Tuple(fields) = ty.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair type" + ); + }; + let [field1, field2] = ***fields else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair type" + ); + }; + let ty::FnPtr(sig1) = field1.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types" + ); + }; + let abi1 = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr( + param_env.and((*sig1, /* extra_args */ ty::List::empty())), + ), + tcx, + item_def_id, + ); + let ty::FnPtr(sig2) = field2.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types" + ); + }; + let abi2 = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr( + param_env.and((*sig2, /* extra_args */ ty::List::empty())), + ), + tcx, + item_def_id, + ); + + if !test_abi_eq(abi1, abi2) { + tcx.sess.emit_err(AbiNe { + span: tcx.def_span(item_def_id), + left: format!("{:#?}", abi1), + right: format!("{:#?}", abi2), + }); + } + } name => { tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index de55b5ec2cbda..d7319ef91e03e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -929,6 +929,15 @@ pub struct AbiOf { pub fn_abi: String, } +#[derive(Diagnostic)] +#[diag(passes_abi_ne)] +pub struct AbiNe { + #[primary_span] + pub span: Span, + pub left: String, + pub right: String, +} + #[derive(Diagnostic)] #[diag(passes_abi_invalid_attribute)] pub struct AbiInvalidAttribute { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 656deebb5d06b..63070b67717de 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -387,6 +387,7 @@ symbols! { asm_sym, asm_unwind, assert, + assert_eq, assert_eq_macro, assert_inhabited, assert_macro, diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs index b140fc719daf3..c5974248bb373 100644 --- a/tests/codegen/repr/transparent.rs +++ b/tests/codegen/repr/transparent.rs @@ -43,7 +43,6 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} } #[repr(transparent)] pub struct WithZeroSizedArray(*const f32, [i8; 0]); -// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. // CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1) #[no_mangle] pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 8575021494d61..058c205abd8d6 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -32,3 +32,9 @@ impl S { #[rustc_abi(debug)] fn assoc_test(&self) { } //~ ERROR: fn_abi } + +#[rustc_abi(assert_eq)] +type TestAbiEq = (fn(bool), fn(bool)); + +#[rustc_abi(assert_eq)] +type TestAbiNe = (fn(u8), fn(u32)); //~ ERROR: ABIs are not compatible diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 2315288c3c750..321ec8715c6bb 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -362,5 +362,151 @@ error: fn_abi_of(assoc_test) = FnAbi { LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:40:1 + | +LL | type TestAbiNe = (fn(u8), fn(u32)); + | ^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors diff --git a/tests/ui/abi/transparent.rs b/tests/ui/abi/transparent.rs new file mode 100644 index 0000000000000..90bdc129a4aa0 --- /dev/null +++ b/tests/ui/abi/transparent.rs @@ -0,0 +1,79 @@ +// check-pass +#![feature(rustc_attrs)] +#![allow(unused, improper_ctypes_definitions)] + +use std::marker::PhantomData; + +macro_rules! assert_abi_compatible { + ($name:ident, $t1:ty, $t2:ty) => { + mod $name { + use super::*; + // Test argument and return value, `Rust` and `C` ABIs. + #[rustc_abi(assert_eq)] + type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2); + #[rustc_abi(assert_eq)] + type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2); + } + } +} + +#[derive(Copy, Clone)] +struct Zst; + +// Check that various `transparent` wrappers result in equal ABIs. +#[repr(transparent)] +struct Wrapper1(T); +#[repr(transparent)] +struct Wrapper2((), Zst, T); +#[repr(transparent)] +struct Wrapper3(T, [u8; 0], PhantomData); + +#[repr(C)] +struct ReprCStruct(T, f32, i32, T); +#[repr(C)] +enum ReprCEnum { + Variant1, + Variant2(T), +} +#[repr(C)] +union ReprCUnion { + nothing: (), + something: T, +} + +macro_rules! test_transparent { + ($name:ident, $t:ty) => { + mod $name { + use super::*; + assert_abi_compatible!(wrap1, $t, Wrapper1<$t>); + assert_abi_compatible!(wrap2, $t, Wrapper2<$t>); + assert_abi_compatible!(wrap3, $t, Wrapper3<$t>); + // Also try adding some surrounding `repr(C)` types. + assert_abi_compatible!(repr_c_struct_wrap1, ReprCStruct<$t>, ReprCStruct>); + assert_abi_compatible!(repr_c_enum_wrap1, ReprCEnum<$t>, ReprCEnum>); + assert_abi_compatible!(repr_c_union_wrap1, ReprCUnion<$t>, ReprCUnion>); + assert_abi_compatible!(repr_c_struct_wrap2, ReprCStruct<$t>, ReprCStruct>); + assert_abi_compatible!(repr_c_enum_wrap2, ReprCEnum<$t>, ReprCEnum>); + assert_abi_compatible!(repr_c_union_wrap2, ReprCUnion<$t>, ReprCUnion>); + assert_abi_compatible!(repr_c_struct_wrap3, ReprCStruct<$t>, ReprCStruct>); + assert_abi_compatible!(repr_c_enum_wrap3, ReprCEnum<$t>, ReprCEnum>); + assert_abi_compatible!(repr_c_union_wrap3, ReprCUnion<$t>, ReprCUnion>); + } + } +} + +test_transparent!(simple, i32); +test_transparent!(reference, &'static i32); +test_transparent!(zst, Zst); +test_transparent!(unit, ()); +test_transparent!(pair, (i32, f32)); +test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit +test_transparent!(tuple, (i32, f32, i64, f64)); +test_transparent!(empty_array, [u32; 0]); +test_transparent!(empty_1zst_array, [u8; 0]); +test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit +test_transparent!(large_array, [i32; 16]); +test_transparent!(enum_, Option); +test_transparent!(enum_niched, Option<&'static i32>); + +fn main() {} From a932990ed48018d60cdbf3d66dfe5eb146866002 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Sep 2023 17:31:35 +1000 Subject: [PATCH 117/217] Use `newtype_index` for `IntVid` and `FloatVid`. `TyVid` already uses `newtype_index`. --- compiler/rustc_infer/src/infer/mod.rs | 4 +-- compiler/rustc_type_ir/src/lib.rs | 36 +++++++++------------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aaabf1482e2d2..dabebe0adc063 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -764,13 +764,13 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); vars.extend( (0..inner.int_unification_table().len()) - .map(|i| ty::IntVid { index: i as u32 }) + .map(|i| ty::IntVid::from_u32(i as u32)) .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none()) .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) - .map(|i| ty::FloatVid { index: i as u32 }) + .map(|i| ty::FloatVid::from_u32(i as u32)) .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none()) .map(|v| Ty::new_float_var(self.tcx, v)), ); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e0abc7f04f575..e348591ebba2f 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -574,16 +574,16 @@ rustc_index::newtype_index! { pub struct TyVid {} } -/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct IntVid { - pub index: u32, +rustc_index::newtype_index! { + /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. + #[debug_format = "?{}i"] + pub struct IntVid {} } -/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct FloatVid { - pub index: u32, +rustc_index::newtype_index! { + /// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. + #[debug_format = "?{}f"] + pub struct FloatVid {} } /// A placeholder for a type that hasn't been inferred yet. @@ -645,11 +645,11 @@ impl UnifyKey for IntVid { type Value = Option; #[inline] // make this function eligible for inlining - it is quite hot. fn index(&self) -> u32 { - self.index + self.as_u32() } #[inline] fn from_index(i: u32) -> IntVid { - IntVid { index: i } + IntVid::from_u32(i) } fn tag() -> &'static str { "IntVid" @@ -662,11 +662,11 @@ impl UnifyKey for FloatVid { type Value = Option; #[inline] fn index(&self) -> u32 { - self.index + self.as_u32() } #[inline] fn from_index(i: u32) -> FloatVid { - FloatVid { index: i } + FloatVid::from_u32(i) } fn tag() -> &'static str { "FloatVid" @@ -770,18 +770,6 @@ impl fmt::Debug for FloatVarValue { } } -impl fmt::Debug for IntVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}i", self.index) - } -} - -impl fmt::Debug for FloatVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}f", self.index) - } -} - impl fmt::Debug for Variance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { From 3f549466a84754f25b1daf28c315eb97b548f218 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 30 Aug 2023 23:29:37 +1000 Subject: [PATCH 118/217] coverage: Extract a common iterator over a function's coverage statements Both of the coverage queries can now use this one helper function to iterate over all of the `mir::Coverage` payloads in the statements of a `mir::Body`. --- .../rustc_mir_transform/src/coverage/query.rs | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index aa205655f9dab..9bf9932eab25e 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,5 +1,6 @@ use super::*; +use rustc_data_structures::captures::Captures; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; use rustc_middle::query::Providers; @@ -66,15 +67,8 @@ impl CoverageVisitor { } fn visit_body(&mut self, body: &Body<'_>) { - for bb_data in body.basic_blocks.iter() { - for statement in bb_data.statements.iter() { - if let StatementKind::Coverage(box ref coverage) = statement.kind { - if is_inlined(body, statement) { - continue; - } - self.visit_coverage(coverage); - } - } + for coverage in all_coverage_in_mir_body(body) { + self.visit_coverage(coverage); } } @@ -115,23 +109,25 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> { let body = mir_body(tcx, def_id); - body.basic_blocks - .iter() - .flat_map(|data| { - data.statements.iter().filter_map(|statement| match statement.kind { - StatementKind::Coverage(box ref coverage) => { - if is_inlined(body, statement) { - None - } else { - coverage.code_region.as_ref() // may be None - } - } - _ => None, - }) - }) + all_coverage_in_mir_body(body) + // Not all coverage statements have an attached code region. + .filter_map(|coverage| coverage.code_region.as_ref()) .collect() } +fn all_coverage_in_mir_body<'a, 'tcx>( + body: &'a Body<'tcx>, +) -> impl Iterator + Captures<'tcx> { + body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| { + match statement.kind { + StatementKind::Coverage(box ref coverage) if !is_inlined(body, statement) => { + Some(coverage) + } + _ => None, + } + }) +} + fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { let scope_data = &body.source_scopes[statement.source_info.scope]; scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() From f191b1c2fc2bbd5585e3c436d2deaae203345c5e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 30 Aug 2023 23:36:11 +1000 Subject: [PATCH 119/217] coverage: Simplify the `coverageinfo` query to a single pass --- .../rustc_mir_transform/src/coverage/query.rs | 43 ++++++------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 9bf9932eab25e..90efe02cb2544 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -29,18 +29,12 @@ pub(crate) fn provide(providers: &mut Providers) { /// calls may not work; but computing the number of counters or expressions by adding `1` to the /// highest ID (for a given instrumented function) is valid. /// -/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum -/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a -/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression -/// IDs referenced by expression operands, if not already seen. -/// -/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage` -/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future -/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to -/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs. +/// It's possible for a coverage expression to remain in MIR while one or both of its operands +/// have been optimized away. To avoid problems in codegen, we include those operands' IDs when +/// determining the maximum counter/expression ID, even if the underlying counter/expression is +/// no longer present. struct CoverageVisitor { info: CoverageInfo, - add_missing_operands: bool, } impl CoverageVisitor { @@ -73,20 +67,14 @@ impl CoverageVisitor { } fn visit_coverage(&mut self, coverage: &Coverage) { - if self.add_missing_operands { - match coverage.kind { - CoverageKind::Expression { lhs, rhs, .. } => { - self.update_from_expression_operand(lhs); - self.update_from_expression_operand(rhs); - } - _ => {} - } - } else { - match coverage.kind { - CoverageKind::Counter { id, .. } => self.update_num_counters(id), - CoverageKind::Expression { id, .. } => self.update_num_expressions(id), - _ => {} + match coverage.kind { + CoverageKind::Counter { id, .. } => self.update_num_counters(id), + CoverageKind::Expression { id, lhs, rhs, .. } => { + self.update_num_expressions(id); + self.update_from_expression_operand(lhs); + self.update_from_expression_operand(rhs); } + CoverageKind::Unreachable => {} } } } @@ -94,14 +82,9 @@ impl CoverageVisitor { fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { let mir_body = tcx.instance_mir(instance_def); - let mut coverage_visitor = CoverageVisitor { - info: CoverageInfo { num_counters: 0, num_expressions: 0 }, - add_missing_operands: false, - }; - - coverage_visitor.visit_body(mir_body); + let mut coverage_visitor = + CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; - coverage_visitor.add_missing_operands = true; coverage_visitor.visit_body(mir_body); coverage_visitor.info From e54204c8e914959e8b42a7bd3531706e4a436fd6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 6 Sep 2023 12:37:38 +1000 Subject: [PATCH 120/217] coverage: In the visitor, track max counter/expression IDs without +1 This makes the visitor track the highest seen counter/expression IDs directly, and only add +1 (to convert to a vector length) at the very end. --- .../rustc_mir_transform/src/coverage/query.rs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 90efe02cb2544..56365c5d474a7 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -13,15 +13,10 @@ pub(crate) fn provide(providers: &mut Providers) { providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); } -/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in -/// other words, the number of counter value references injected into the MIR (plus 1 for the -/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected -/// counters have a counter ID from `1..num_counters-1`. -/// -/// `num_expressions` is the number of counter expressions added to the MIR body. -/// -/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend -/// code generate, to lookup counters and expressions by simple u32 indexes. +/// Coverage codegen needs to know the total number of counter IDs and expression IDs that have +/// been used by a function's coverage mappings. These totals are used to create vectors to hold +/// the relevant counter and expression data, and the maximum counter ID (+ 1) is also needed by +/// the `llvm.instrprof.increment` intrinsic. /// /// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code /// including injected counters. (It is OK if some counters are optimized out, but those counters @@ -34,28 +29,27 @@ pub(crate) fn provide(providers: &mut Providers) { /// determining the maximum counter/expression ID, even if the underlying counter/expression is /// no longer present. struct CoverageVisitor { - info: CoverageInfo, + max_counter_id: CounterId, + max_expression_id: ExpressionId, } impl CoverageVisitor { - /// Updates `num_counters` to the maximum encountered counter ID plus 1. + /// Updates `max_counter_id` to the maximum encountered counter ID. #[inline(always)] - fn update_num_counters(&mut self, counter_id: CounterId) { - let counter_id = counter_id.as_u32(); - self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); + fn update_max_counter_id(&mut self, counter_id: CounterId) { + self.max_counter_id = self.max_counter_id.max(counter_id); } - /// Updates `num_expressions` to the maximum encountered expression ID plus 1. + /// Updates `max_expression_id` to the maximum encountered expression ID. #[inline(always)] - fn update_num_expressions(&mut self, expression_id: ExpressionId) { - let expression_id = expression_id.as_u32(); - self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1); + fn update_max_expression_id(&mut self, expression_id: ExpressionId) { + self.max_expression_id = self.max_expression_id.max(expression_id); } fn update_from_expression_operand(&mut self, operand: Operand) { match operand { - Operand::Counter(id) => self.update_num_counters(id), - Operand::Expression(id) => self.update_num_expressions(id), + Operand::Counter(id) => self.update_max_counter_id(id), + Operand::Expression(id) => self.update_max_expression_id(id), Operand::Zero => {} } } @@ -68,9 +62,9 @@ impl CoverageVisitor { fn visit_coverage(&mut self, coverage: &Coverage) { match coverage.kind { - CoverageKind::Counter { id, .. } => self.update_num_counters(id), + CoverageKind::Counter { id, .. } => self.update_max_counter_id(id), CoverageKind::Expression { id, lhs, rhs, .. } => { - self.update_num_expressions(id); + self.update_max_expression_id(id); self.update_from_expression_operand(lhs); self.update_from_expression_operand(rhs); } @@ -82,12 +76,18 @@ impl CoverageVisitor { fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { let mir_body = tcx.instance_mir(instance_def); - let mut coverage_visitor = - CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; + let mut coverage_visitor = CoverageVisitor { + max_counter_id: CounterId::START, + max_expression_id: ExpressionId::START, + }; coverage_visitor.visit_body(mir_body); - coverage_visitor.info + // Add 1 to the highest IDs to get the total number of IDs. + CoverageInfo { + num_counters: (coverage_visitor.max_counter_id + 1).as_u32(), + num_expressions: (coverage_visitor.max_expression_id + 1).as_u32(), + } } fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> { From bb6dcf5f740f6147eaf8774509ca27adc47c009b Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Thu, 7 Sep 2023 17:34:41 +0800 Subject: [PATCH 121/217] Add `RegisterCodeGenFlags` to get full codegen flags list --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4ac739326d2dd..4b30a4fefd9d9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -9,6 +9,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" @@ -50,6 +51,8 @@ using namespace llvm; +static codegen::RegisterCodeGenFlags CGF; + typedef struct LLVMOpaquePass *LLVMPassRef; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; From 487766cef0faa12c3e744b8c754ea7c58427ec2f Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Thu, 7 Sep 2023 17:36:21 +0800 Subject: [PATCH 122/217] Using parsed codegen flags --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4b30a4fefd9d9..194ebe6d96890 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -424,7 +424,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return nullptr; } - TargetOptions Options; + TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Trip); Options.FloatABIType = FloatABI::Default; if (UseSoftFloat) { From c5996b80beaba54502fa86583b48cd6980b17b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 31 Aug 2023 12:50:44 +0200 Subject: [PATCH 123/217] Use `Freeze` for `SourceFile.external_src` --- .../rustc_data_structures/src/sync/freeze.rs | 47 +++++++++++++- .../src/annotate_snippet_emitter_writer.rs | 2 +- compiler/rustc_errors/src/emitter.rs | 4 +- compiler/rustc_errors/src/json.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- compiler/rustc_span/src/lib.rs | 64 ++++++++++--------- compiler/rustc_span/src/source_map.rs | 12 ++-- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index d9f1d72d8510a..88c710e52361f 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -27,7 +27,26 @@ unsafe impl DynSync for FreezeLock {} impl FreezeLock { #[inline] pub fn new(value: T) -> Self { - Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: RwLock::new(()) } + Self::with(value, false) + } + + #[inline] + pub fn frozen(value: T) -> Self { + Self::with(value, true) + } + + #[inline] + pub fn with(value: T, frozen: bool) -> Self { + Self { + data: UnsafeCell::new(value), + frozen: AtomicBool::new(frozen), + lock: RwLock::new(()), + } + } + + #[inline] + pub fn is_frozen(&self) -> bool { + self.frozen.load(Ordering::Acquire) } #[inline] @@ -42,13 +61,26 @@ impl FreezeLock { } } + #[inline] + pub fn borrow(&self) -> FreezeReadGuard<'_, T> { + self.read() + } + #[inline] #[track_caller] pub fn write(&self) -> FreezeWriteGuard<'_, T> { + self.try_write().expect("still mutable") + } + + #[inline] + pub fn try_write(&self) -> Option> { let _lock_guard = self.lock.write(); // Use relaxed ordering since we're in the write lock. - assert!(!self.frozen.load(Ordering::Relaxed), "still mutable"); - FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData } + if self.frozen.load(Ordering::Relaxed) { + None + } else { + Some(FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData }) + } } #[inline] @@ -90,6 +122,15 @@ pub struct FreezeWriteGuard<'a, T> { marker: PhantomData<&'a mut T>, } +impl<'a, T> FreezeWriteGuard<'a, T> { + pub fn freeze(self) -> &'a T { + self.lock.frozen.store(true, Ordering::Release); + + // SAFETY: This is frozen so the data cannot be modified and shared access is sound. + unsafe { &*self.lock.data.get() } + } +} + impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> { type Target = T; #[inline] diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index d7a008f9a57f9..5d3b2f45166b3 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -169,7 +169,7 @@ impl AnnotateSnippetEmitterWriter { .map(|line| { // Ensure the source file is present before we try // to load a string from it. - source_map.ensure_source_file_source_present(file.clone()); + source_map.ensure_source_file_source_present(&file); ( format!("{}", source_map.filename_for_diagnostics(&file.name)), source_string(file.clone(), &line), diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index da108327ae74e..58be74f887bfd 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1193,7 +1193,7 @@ impl EmitterWriter { let will_be_emitted = |span: Span| { !span.is_dummy() && { let file = sm.lookup_source_file(span.hi()); - sm.ensure_source_file_source_present(file) + sm.ensure_source_file_source_present(&file) } }; @@ -1388,7 +1388,7 @@ impl EmitterWriter { // Print out the annotate source lines that correspond with the error for annotated_file in annotated_files { // we can't annotate anything if the source is unavailable. - if !sm.ensure_source_file_source_present(annotated_file.file.clone()) { + if !sm.ensure_source_file_source_present(&annotated_file.file) { if !self.short_message { // We'll just print an unannotated message. for (annotation_id, line) in annotated_file.lines.iter().enumerate() { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 390bf28df091a..38667c5ff819d 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -558,7 +558,7 @@ impl DiagnosticSpanLine { .span_to_lines(span) .map(|lines| { // We can't get any lines if the source is unavailable. - if !je.sm.ensure_source_file_source_present(lines.file.clone()) { + if !je.sm.ensure_source_file_source_present(&lines.file) { return vec![]; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 55c4ec66cd9ed..6cb6549a00bdb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -273,7 +273,7 @@ impl CodeSuggestion { assert!(!lines.lines.is_empty() || bounding_span.is_dummy()); // We can't splice anything if the source is unavailable. - if !sm.ensure_source_file_source_present(lines.file.clone()) { + if !sm.ensure_source_file_source_present(&lines.file) { return None; } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4f4351633a2ce..bace48cec44d8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -280,8 +280,8 @@ impl<'a, 'tcx> Encodable> for SpanData { // All of this logic ensures that the final result of deserialization is a 'normal' // Span that can be used without any additional trouble. let metadata_index = { - // Introduce a new scope so that we drop the 'lock()' temporary - match &*source_file.external_src.lock() { + // Introduce a new scope so that we drop the 'read()' temporary + match &*source_file.external_src.read() { ExternalSource::Foreign { metadata_index, .. } => *metadata_index, src => panic!("Unexpected external source {src:?}"), } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f1a6e9059d725..8ef17ed671b96 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -64,7 +64,7 @@ pub mod fatal_error; pub mod profiling; use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc}; use std::borrow::Cow; use std::cmp::{self, Ordering}; @@ -1206,7 +1206,6 @@ pub enum ExternalSourceKind { AbsentOk, /// A failed attempt has been made to load the external source. AbsentErr, - Unneeded, } impl ExternalSource { @@ -1343,7 +1342,7 @@ pub struct SourceFile { pub src_hash: SourceFileHash, /// The external source code (used for external crates, which will have a `None` /// value as `self.src`. - pub external_src: Lock, + pub external_src: FreezeLock, /// The start position of this source in the `SourceMap`. pub start_pos: BytePos, /// The byte length of this source. @@ -1368,7 +1367,10 @@ impl Clone for SourceFile { name: self.name.clone(), src: self.src.clone(), src_hash: self.src_hash, - external_src: Lock::new(self.external_src.borrow().clone()), + external_src: { + let lock = self.external_src.read(); + FreezeLock::with(lock.clone(), self.external_src.is_frozen()) + }, start_pos: self.start_pos, source_len: self.source_len, lines: Lock::new(self.lines.borrow().clone()), @@ -1488,7 +1490,7 @@ impl Decodable for SourceFile { src_hash, // Unused - the metadata decoder will construct // a new SourceFile, filling in `external_src` properly - external_src: Lock::new(ExternalSource::Unneeded), + external_src: FreezeLock::frozen(ExternalSource::Unneeded), lines: Lock::new(lines), multibyte_chars, non_narrow_chars, @@ -1530,7 +1532,7 @@ impl SourceFile { name, src: Some(Lrc::new(src)), src_hash, - external_src: Lock::new(ExternalSource::Unneeded), + external_src: FreezeLock::frozen(ExternalSource::Unneeded), start_pos: BytePos::from_u32(0), source_len: RelativeBytePos::from_u32(source_len), lines: Lock::new(SourceFileLines::Lines(lines)), @@ -1612,35 +1614,37 @@ impl SourceFile { where F: FnOnce() -> Option, { - if matches!( - *self.external_src.borrow(), - ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. } - ) { + if !self.external_src.is_frozen() { let src = get_src(); - let mut external_src = self.external_src.borrow_mut(); - // Check that no-one else have provided the source while we were getting it - if let ExternalSource::Foreign { - kind: src_kind @ ExternalSourceKind::AbsentOk, .. - } = &mut *external_src - { - if let Some(mut src) = src { - // The src_hash needs to be computed on the pre-normalized src. - if self.src_hash.matches(&src) { - normalize_src(&mut src); - *src_kind = ExternalSourceKind::Present(Lrc::new(src)); - return true; - } + let src = src.and_then(|mut src| { + // The src_hash needs to be computed on the pre-normalized src. + self.src_hash.matches(&src).then(|| { + normalize_src(&mut src); + src + }) + }); + + self.external_src.try_write().map(|mut external_src| { + if let ExternalSource::Foreign { + kind: src_kind @ ExternalSourceKind::AbsentOk, + .. + } = &mut *external_src + { + *src_kind = if let Some(src) = src { + ExternalSourceKind::Present(Lrc::new(src)) + } else { + ExternalSourceKind::AbsentErr + }; } else { - *src_kind = ExternalSourceKind::AbsentErr; + panic!("unexpected state {:?}", *external_src) } - false - } else { - self.src.is_some() || external_src.get_source().is_some() - } - } else { - self.src.is_some() || self.external_src.borrow().get_source().is_some() + // Freeze this so we don't try to load the source again. + FreezeWriteGuard::freeze(external_src) + }); } + + self.src.is_some() || self.external_src.read().get_source().is_some() } /// Gets a line from the list of pre-computed line-beginnings. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 81730f2f60869..20bd57cae6dae 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -340,7 +340,7 @@ impl SourceMap { name: filename, src: None, src_hash, - external_src: Lock::new(ExternalSource::Foreign { + external_src: FreezeLock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, metadata_index, }), @@ -564,7 +564,7 @@ impl SourceMap { end: (local_end.sf.name.clone(), local_end.sf.start_pos), }))) } else { - self.ensure_source_file_source_present(local_begin.sf.clone()); + self.ensure_source_file_source_present(&local_begin.sf); let start_index = local_begin.pos.to_usize(); let end_index = local_end.pos.to_usize(); @@ -581,7 +581,7 @@ impl SourceMap { if let Some(ref src) = local_begin.sf.src { extract_source(src, start_index, end_index) - } else if let Some(src) = local_begin.sf.external_src.borrow().get_source() { + } else if let Some(src) = local_begin.sf.external_src.read().get_source() { extract_source(src, start_index, end_index) } else { Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() }) @@ -873,7 +873,7 @@ impl SourceMap { let sp = sp.data(); let local_begin = self.lookup_byte_offset(sp.lo); let start_index = local_begin.pos.to_usize(); - let src = local_begin.sf.external_src.borrow(); + let src = local_begin.sf.external_src.read(); let snippet = if let Some(ref src) = local_begin.sf.src { Some(&src[start_index..]) @@ -983,7 +983,7 @@ impl SourceMap { return 1; } - let src = local_begin.sf.external_src.borrow(); + let src = local_begin.sf.external_src.read(); let snippet = if let Some(src) = &local_begin.sf.src { src @@ -1030,7 +1030,7 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { + pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool { source_file.add_external_src(|| { let FileName::Real(ref name) = source_file.name else { return None; From f49382c0508db608aa9c33d6a8c77d2955d8f62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 31 Aug 2023 22:12:47 +0200 Subject: [PATCH 124/217] Use `Freeze` for `SourceFile.lines` --- .../src/debuginfo/line_info.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- .../rustc_data_structures/src/sync/freeze.rs | 12 + .../rustc_middle/src/query/on_disk_cache.rs | 2 +- .../src/ich/impls_syntax.rs | 9 +- compiler/rustc_span/src/lib.rs | 263 ++++++++++-------- compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_span/src/source_map/tests.rs | 4 +- compiler/rustc_span/src/tests.rs | 4 +- .../src/undocumented_unsafe_blocks.rs | 84 +++--- src/tools/clippy/clippy_utils/src/source.rs | 2 +- 11 files changed, 203 insertions(+), 183 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 998263de584fc..b19b935a0fea6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -81,7 +81,7 @@ impl DebugContext { match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; let col = file.relative_position(span.lo()) - line_pos; (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 2301f66dc28dd..487263709e186 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -263,7 +263,7 @@ impl CodegenCx<'_, '_> { pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { let (file, line, col) = match self.sess().source_map().lookup_line(pos) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; // Use 1-based indexing. let line = (line + 1) as u32; diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 88c710e52361f..ad71ae1af5172 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -3,6 +3,7 @@ use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; use crate::sync::{DynSend, DynSync}; use std::{ cell::UnsafeCell, + intrinsics::likely, marker::PhantomData, ops::{Deref, DerefMut}, sync::atomic::Ordering, @@ -49,6 +50,17 @@ impl FreezeLock { self.frozen.load(Ordering::Acquire) } + /// Get the inner value if frozen. + #[inline] + pub fn get(&self) -> Option<&T> { + if likely(self.frozen.load(Ordering::Acquire)) { + // SAFETY: This is frozen so the data cannot be modified. + unsafe { Some(&*self.data.get()) } + } else { + None + } + } + #[inline] pub fn read(&self) -> FreezeReadGuard<'_, T> { FreezeReadGuard { diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 64853bd9612ca..154c930dc0f4c 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -692,7 +692,7 @@ impl<'a, 'tcx> Decodable> for Span { let len = BytePos::decode(decoder); let file_lo = decoder.file_index_to_file(file_lo_index); - let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo); + let lo = file_lo.lines()[line_lo - 1] + col_lo; let lo = file_lo.absolute_position(lo); let hi = lo + len; diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index f2b13f95def29..b2177be0e368c 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -79,15 +79,16 @@ impl<'a> HashStable> for SourceFile { src_hash.hash_stable(hcx, hasher); - // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { + { + // We are always in `Lines` form by the time we reach here. + assert!(self.lines.read().is_lines()); + let lines = self.lines(); // We only hash the relative position within this source_file lines.len().hash_stable(hcx, hasher); for &line in lines.iter() { line.hash_stable(hcx, hasher); } - }); + } // We only hash the relative position within this source_file multibyte_chars.len().hash_stable(hcx, hasher); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8ef17ed671b96..8976ee83c4e76 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -33,7 +33,7 @@ extern crate rustc_macros; #[macro_use] extern crate tracing; -use rustc_data_structures::AtomicRef; +use rustc_data_structures::{cold_path, AtomicRef}; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -1348,7 +1348,7 @@ pub struct SourceFile { /// The byte length of this source. pub source_len: RelativeBytePos, /// Locations of lines beginnings in the source code. - pub lines: Lock, + pub lines: FreezeLock, /// Locations of multi-byte characters in the source code. pub multibyte_chars: Vec, /// Width of characters that are not narrow in the source code. @@ -1373,7 +1373,10 @@ impl Clone for SourceFile { }, start_pos: self.start_pos, source_len: self.source_len, - lines: Lock::new(self.lines.borrow().clone()), + lines: { + let lock = self.lines.read(); + FreezeLock::with(lock.clone(), self.lines.is_frozen()) + }, multibyte_chars: self.multibyte_chars.clone(), non_narrow_chars: self.non_narrow_chars.clone(), normalized_pos: self.normalized_pos.clone(), @@ -1391,64 +1394,63 @@ impl Encodable for SourceFile { self.source_len.encode(s); // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { - // Store the length. - s.emit_u32(lines.len() as u32); - - // Compute and store the difference list. - if lines.len() != 0 { - let max_line_length = if lines.len() == 1 { - 0 - } else { - lines - .array_windows() - .map(|&[fst, snd]| snd - fst) - .map(|bp| bp.to_usize()) - .max() - .unwrap() - }; - - let bytes_per_diff: usize = match max_line_length { - 0..=0xFF => 1, - 0x100..=0xFFFF => 2, - _ => 4, - }; - - // Encode the number of bytes used per diff. - s.emit_u8(bytes_per_diff as u8); - - // Encode the first element. - assert_eq!(lines[0], RelativeBytePos(0)); - - // Encode the difference list. - let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); - let num_diffs = lines.len() - 1; - let mut raw_diffs; - match bytes_per_diff { - 1 => { - raw_diffs = Vec::with_capacity(num_diffs); - for diff in diff_iter { - raw_diffs.push(diff.0 as u8); - } + assert!(self.lines.read().is_lines()); + let lines = self.lines(); + // Store the length. + s.emit_u32(lines.len() as u32); + + // Compute and store the difference list. + if lines.len() != 0 { + let max_line_length = if lines.len() == 1 { + 0 + } else { + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() + }; + + let bytes_per_diff: usize = match max_line_length { + 0..=0xFF => 1, + 0x100..=0xFFFF => 2, + _ => 4, + }; + + // Encode the number of bytes used per diff. + s.emit_u8(bytes_per_diff as u8); + + // Encode the first element. + assert_eq!(lines[0], RelativeBytePos(0)); + + // Encode the difference list. + let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); + let num_diffs = lines.len() - 1; + let mut raw_diffs; + match bytes_per_diff { + 1 => { + raw_diffs = Vec::with_capacity(num_diffs); + for diff in diff_iter { + raw_diffs.push(diff.0 as u8); } - 2 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); - } + } + 2 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); } - 4 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); - } + } + 4 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); } - _ => unreachable!(), } - s.emit_raw_bytes(&raw_diffs); + _ => unreachable!(), } - }); + s.emit_raw_bytes(&raw_diffs); + } self.multibyte_chars.encode(s); self.non_narrow_chars.encode(s); @@ -1491,7 +1493,7 @@ impl Decodable for SourceFile { // Unused - the metadata decoder will construct // a new SourceFile, filling in `external_src` properly external_src: FreezeLock::frozen(ExternalSource::Unneeded), - lines: Lock::new(lines), + lines: FreezeLock::new(lines), multibyte_chars, non_narrow_chars, normalized_pos, @@ -1535,7 +1537,7 @@ impl SourceFile { external_src: FreezeLock::frozen(ExternalSource::Unneeded), start_pos: BytePos::from_u32(0), source_len: RelativeBytePos::from_u32(source_len), - lines: Lock::new(SourceFileLines::Lines(lines)), + lines: FreezeLock::frozen(SourceFileLines::Lines(lines)), multibyte_chars, non_narrow_chars, normalized_pos, @@ -1544,65 +1546,82 @@ impl SourceFile { }) } - pub fn lines(&self, f: F) -> R - where - F: FnOnce(&[RelativeBytePos]) -> R, - { - let mut guard = self.lines.borrow_mut(); - match &*guard { - SourceFileLines::Lines(lines) => f(lines), - SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) => { - // Convert from "diffs" form to "lines" form. - let num_lines = num_diffs + 1; - let mut lines = Vec::with_capacity(num_lines); - let mut line_start = RelativeBytePos(0); - lines.push(line_start); - - assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); - match bytes_per_diff { - 1 => { - lines.extend(raw_diffs.into_iter().map(|&diff| { - line_start = line_start + RelativeBytePos(diff as u32); - line_start - })); - } - 2 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; - let diff = u16::from_le_bytes(bytes); - line_start = line_start + RelativeBytePos(diff as u32); - line_start - })); - } - 4 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [ - raw_diffs[pos], - raw_diffs[pos + 1], - raw_diffs[pos + 2], - raw_diffs[pos + 3], - ]; - let diff = u32::from_le_bytes(bytes); - line_start = line_start + RelativeBytePos(diff); - line_start - })); - } - _ => unreachable!(), - } - let res = f(&lines); - *guard = SourceFileLines::Lines(lines); - res + /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it. + fn convert_diffs_to_lines_frozen(&self) { + let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return }; + + let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard { + SourceFileLines::Diffs(diffs) => diffs, + SourceFileLines::Lines(..) => { + FreezeWriteGuard::freeze(guard); + return; } + }; + + // Convert from "diffs" form to "lines" form. + let num_lines = num_diffs + 1; + let mut lines = Vec::with_capacity(num_lines); + let mut line_start = RelativeBytePos(0); + lines.push(line_start); + + assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); + match bytes_per_diff { + 1 => { + lines.extend(raw_diffs.into_iter().map(|&diff| { + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); + } + 2 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; + let diff = u16::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); + } + 4 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [ + raw_diffs[pos], + raw_diffs[pos + 1], + raw_diffs[pos + 2], + raw_diffs[pos + 3], + ]; + let diff = u32::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff); + line_start + })); + } + _ => unreachable!(), + } + + *guard = SourceFileLines::Lines(lines); + + FreezeWriteGuard::freeze(guard); + } + + pub fn lines(&self) -> &[RelativeBytePos] { + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; } + + cold_path(|| { + self.convert_diffs_to_lines_frozen(); + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; + } + unreachable!() + }) } /// Returns the `BytePos` of the beginning of the current line. pub fn line_begin_pos(&self, pos: BytePos) -> BytePos { let pos = self.relative_position(pos); let line_index = self.lookup_line(pos).unwrap(); - let line_start_pos = self.lines(|lines| lines[line_index]); + let line_start_pos = self.lines()[line_index]; self.absolute_position(line_start_pos) } @@ -1662,7 +1681,7 @@ impl SourceFile { } let begin = { - let line = self.lines(|lines| lines.get(line_number).copied())?; + let line = self.lines().get(line_number).copied()?; line.to_usize() }; @@ -1686,7 +1705,7 @@ impl SourceFile { } pub fn count_lines(&self) -> usize { - self.lines(|lines| lines.len()) + self.lines().len() } #[inline] @@ -1709,7 +1728,7 @@ impl SourceFile { /// number. If the source_file is empty or the position is located before the /// first line, `None` is returned. pub fn lookup_line(&self, pos: RelativeBytePos) -> Option { - self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1)) + self.lines().partition_point(|x| x <= &pos).checked_sub(1) } pub fn line_bounds(&self, line_index: usize) -> Range { @@ -1717,15 +1736,13 @@ impl SourceFile { return self.start_pos..self.start_pos; } - self.lines(|lines| { - assert!(line_index < lines.len()); - if line_index == (lines.len() - 1) { - self.absolute_position(lines[line_index])..self.end_position() - } else { - self.absolute_position(lines[line_index]) - ..self.absolute_position(lines[line_index + 1]) - } - }) + let lines = self.lines(); + assert!(line_index < lines.len()); + if line_index == (lines.len() - 1) { + self.absolute_position(lines[line_index])..self.end_position() + } else { + self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1]) + } } /// Returns whether or not the file contains the given `SourceMap` byte @@ -1811,7 +1828,7 @@ impl SourceFile { match self.lookup_line(pos) { Some(a) => { let line = a + 1; // Line numbers start at 1 - let linebpos = self.lines(|lines| lines[a]); + let linebpos = self.lines()[a]; let linechpos = self.bytepos_to_file_charpos(linebpos); let col = chpos - linechpos; debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); @@ -1831,7 +1848,7 @@ impl SourceFile { let (line, col_or_chpos) = self.lookup_file_pos(pos); if line > 0 { let col = col_or_chpos; - let linebpos = self.lines(|lines| lines[line - 1]); + let linebpos = self.lines()[line - 1]; let col_display = { let start_width_idx = self .non_narrow_chars diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 20bd57cae6dae..68727a6c40ea0 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -328,7 +328,7 @@ impl SourceMap { name_hash: Hash128, source_len: u32, cnum: CrateNum, - file_local_lines: Lock, + file_local_lines: FreezeLock, multibyte_chars: Vec, non_narrow_chars: Vec, normalized_pos: Vec, diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 7689e6afac56b..e393db0206417 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,6 +1,6 @@ use super::*; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{FreezeLock, Lrc}; fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); @@ -246,7 +246,7 @@ fn t10() { name_hash, source_len.to_u32(), CrateNum::new(0), - lines, + FreezeLock::new(lines.read().clone()), multibyte_chars, non_narrow_chars, normalized_pos, diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index a980ee8d9e070..cb88fa89058dc 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -7,9 +7,7 @@ fn test_lookup_line() { SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256) .unwrap(); sf.start_pos = BytePos(3); - sf.lines(|lines| { - assert_eq!(lines, &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]) - }); + assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]); assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0)); assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0)); diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index a1ea3a495eb6a..da8d8ed4c0f2c 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -507,20 +507,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -551,20 +549,18 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -614,20 +610,18 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span && Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - unsafe_line.sf.lines(|lines| { - if macro_line.line < unsafe_line.line { - match text_has_safety_comment( - src, - &lines[macro_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } - } else { - HasSafetyComment::No + if macro_line.line < unsafe_line.line { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }) + } else { + HasSafetyComment::No + } } else { // Problem getting source text. Pretend a comment was found. HasSafetyComment::Maybe @@ -671,13 +665,11 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - unsafe_line.sf.lines(|lines| { - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &lines[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ).is_some() - }) + body_line.line < unsafe_line.line && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ).is_some() } else { // Problem getting source text. Pretend a comment was found. true diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 03416d35ba452..600cd084c19f5 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -118,7 +118,7 @@ fn first_char_in_first_line(cx: &T, span: Span) -> Option(cx: &T, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap(); - let line_start = sf.lines(|lines| lines[line]); + let line_start = sf.lines()[line]; let line_start = sf.absolute_position(line_start); span.with_lo(line_start) } From caf6ce5ea28e7bf3ab0eeac21bfce5e3013e3347 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 28 Jul 2023 20:44:25 +0200 Subject: [PATCH 125/217] Stabilize `PATH` option for `--print KIND=PATH` Description of the `PATH` option: > A filepath may optionally be specified for each requested information > kind, in the format `--print KIND=PATH`, just like for `--emit`. When > a path is specified, information will be written there instead of to > stdout. --- compiler/rustc_session/src/config.rs | 6 ------ src/doc/rustc/src/command-line-arguments.md | 4 ++++ .../unstable-book/src/compiler-flags/path-options.md | 11 ----------- tests/run-make/print-cfg/Makefile | 8 ++++---- tests/ui/feature-gates/print-with-path.cfg.stderr | 2 -- tests/ui/feature-gates/print-with-path.rs | 7 ------- .../feature-gates/print-with-path.target-cpus.stderr | 2 -- .../print-with-path.target-features.stderr | 2 -- 8 files changed, 8 insertions(+), 34 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/path-options.md delete mode 100644 tests/ui/feature-gates/print-with-path.cfg.stderr delete mode 100644 tests/ui/feature-gates/print-with-path.rs delete mode 100644 tests/ui/feature-gates/print-with-path.target-cpus.stderr delete mode 100644 tests/ui/feature-gates/print-with-path.target-features.stderr diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f00472f181d8e..302e4e55d597d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2160,12 +2160,6 @@ fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); - if out.is_some() && !unstable_opts.unstable_options { - handler.early_error( - "the `-Z unstable-options` flag must also be passed to \ - enable the path print option", - ); - } let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 2c7c05c0c4b88..4d32897cc14c7 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -260,6 +260,10 @@ The valid types of print values are: This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the variable's parsed value. +A filepath may optionally be specified for each requested information kind, in +the format `--print KIND=PATH`, just like for `--emit`. When a path is +specified, information will be written there instead of to stdout. + [conditional compilation]: ../reference/conditional-compilation.html [deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html diff --git a/src/doc/unstable-book/src/compiler-flags/path-options.md b/src/doc/unstable-book/src/compiler-flags/path-options.md deleted file mode 100644 index 0786ef1f16612..0000000000000 --- a/src/doc/unstable-book/src/compiler-flags/path-options.md +++ /dev/null @@ -1,11 +0,0 @@ -# `--print` Options - -The behavior of the `--print` flag can be modified by optionally be specifying a filepath -for each requested information kind, in the format `--print KIND=PATH`, just like for -`--emit`. When a path is specified, information will be written there instead of to stdout. - -This is unstable feature, so you have to provide `-Zunstable-options` to enable it. - -## Examples - -`rustc main.rs -Z unstable-options --print cfg=cfgs.txt` diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index 654c303b3e26d..6b153e5b54edd 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -13,19 +13,19 @@ all: default output_to_file output_to_file: # Backend-independent, printed by rustc_driver_impl/src/lib.rs - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt -Z unstable-options + $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt $(CGREP) windows < $(TMPDIR)/cfg.txt # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs - $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt -Z unstable-options + $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt $(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs - $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt $(CGREP) reference-types < $(TMPDIR)/target-features.txt # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp - $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt $(CGREP) generic < $(TMPDIR)/target-cpus.txt ifdef IS_WINDOWS diff --git a/tests/ui/feature-gates/print-with-path.cfg.stderr b/tests/ui/feature-gates/print-with-path.cfg.stderr deleted file mode 100644 index a6c51baa320a0..0000000000000 --- a/tests/ui/feature-gates/print-with-path.cfg.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.rs b/tests/ui/feature-gates/print-with-path.rs deleted file mode 100644 index f929c14c21880..0000000000000 --- a/tests/ui/feature-gates/print-with-path.rs +++ /dev/null @@ -1,7 +0,0 @@ -// check-fail -// revisions: cfg target-features target-cpus -// [cfg]compile-flags: --print cfg=cfg.txt -// [target-cpus]compile-flags: --print target-cpu=target_cpu.txt -// [target-features]compile-flags: --print target-features=target_features.txt - -fn main() {} diff --git a/tests/ui/feature-gates/print-with-path.target-cpus.stderr b/tests/ui/feature-gates/print-with-path.target-cpus.stderr deleted file mode 100644 index a6c51baa320a0..0000000000000 --- a/tests/ui/feature-gates/print-with-path.target-cpus.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.target-features.stderr b/tests/ui/feature-gates/print-with-path.target-features.stderr deleted file mode 100644 index a6c51baa320a0..0000000000000 --- a/tests/ui/feature-gates/print-with-path.target-features.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - From 6e5566cf03340fba678c10c17282b1fcc536c3e1 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 7 Sep 2023 09:48:50 -0400 Subject: [PATCH 126/217] lto: load bitcode sections by name Upstream change llvm/llvm-project@6b539f5eb8ef1d3a3c87873caa2dbd5147e1adbd changed `isSectionBitcode` works and it now only respects `.llvm.lto` sections instead of also `.llvmbc`, which it says was never intended to be used for LTO. We instead load sections by name, and sniff for raw bitcode by hand. r? @nikic @rustbot label: +llvm-main --- compiler/rustc_codegen_llvm/src/back/lto.rs | 27 +++++++++++--- compiler/rustc_codegen_llvm/src/back/write.rs | 36 ++++++++++++------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 ++++ .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 33 +++++++++++++++++ 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index c1d3392386cad..3964039ac2d19 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -1,4 +1,6 @@ -use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers}; +use crate::back::write::{ + self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers, +}; use crate::errors::{ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, }; @@ -120,6 +122,7 @@ fn prepare_lto( info!("adding bitcode from {}", name); match get_bitcode_slice_from_object_data( child.data(&*archive_data).expect("corrupt rlib"), + cgcx, ) { Ok(data) => { let module = SerializedModule::FromRlib(data.to_vec()); @@ -141,10 +144,26 @@ fn prepare_lto( Ok((symbols_below_threshold, upstream_modules)) } -fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> { +fn get_bitcode_slice_from_object_data<'a>( + obj: &'a [u8], + cgcx: &CodegenContext, +) -> Result<&'a [u8], LtoBitcodeFromRlib> { + // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that + // won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff + // the relevant magic strings here and return. + if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") { + return Ok(obj); + } + let section_name = bitcode_section_name(cgcx); let mut len = 0; - let data = - unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) }; + let data = unsafe { + llvm::LLVMRustGetSliceFromObjectDataByName( + obj.as_ptr(), + obj.len(), + section_name.as_ptr(), + &mut len, + ) + }; if !data.is_null() { assert!(len != 0); let bc = unsafe { slice::from_raw_parts(data, len) }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 47cc5bd52e2ac..d73714ef357c4 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -853,6 +853,27 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: asm } +fn target_is_apple(cgcx: &CodegenContext) -> bool { + cgcx.opts.target_triple.triple().contains("-ios") + || cgcx.opts.target_triple.triple().contains("-darwin") + || cgcx.opts.target_triple.triple().contains("-tvos") + || cgcx.opts.target_triple.triple().contains("-watchos") +} + +fn target_is_aix(cgcx: &CodegenContext) -> bool { + cgcx.opts.target_triple.triple().contains("-aix") +} + +pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> &'static str { + if target_is_apple(cgcx) { + "__LLVM,__bitcode\0" + } else if target_is_aix(cgcx) { + ".ipa\0" + } else { + ".llvmbc\0" + } +} + /// Embed the bitcode of an LLVM module in the LLVM module itself. /// /// This is done primarily for iOS where it appears to be standard to compile C @@ -913,11 +934,8 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - let is_aix = cgcx.opts.target_triple.triple().contains("-aix"); - let is_apple = cgcx.opts.target_triple.triple().contains("-ios") - || cgcx.opts.target_triple.triple().contains("-darwin") - || cgcx.opts.target_triple.triple().contains("-tvos") - || cgcx.opts.target_triple.triple().contains("-watchos"); + let is_aix = target_is_aix(cgcx); + let is_apple = target_is_apple(cgcx); if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") @@ -932,13 +950,7 @@ unsafe fn embed_bitcode( ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { - "__LLVM,__bitcode\0" - } else if is_aix { - ".ipa\0" - } else { - ".llvmbc\0" - }; + let section = bitcode_section_name(cgcx); llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 01cbf7d3b11e2..9f16889b953fa 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2319,6 +2319,12 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; + pub fn LLVMRustGetSliceFromObjectDataByName( + data: *const u8, + len: usize, + name: *const u8, + out_len: &mut usize, + ) -> *const u8; pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>; pub fn LLVMRustLinkerAdd( diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8f8f1d8c04feb..bc5163ab13825 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -1511,6 +1512,38 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, return BitcodeOrError->getBufferStart(); } +// Find a section of an object file by name. Fail if the section is missing or +// empty. +extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, + size_t len, + const char *name, + size_t *out_len) { + *out_len = 0; + StringRef Data(data, len); + MemoryBufferRef Buffer(Data, ""); // The id is unused. + file_magic Type = identify_magic(Buffer.getBuffer()); + Expected> ObjFileOrError = + object::ObjectFile::createObjectFile(Buffer, Type); + if (!ObjFileOrError) { + LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str()); + return nullptr; + } + for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) { + Expected Name = Sec.getName(); + if (Name && *Name == name) { + Expected SectionOrError = Sec.getContents(); + if (!SectionOrError) { + LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str()); + return nullptr; + } + *out_len = SectionOrError->size(); + return SectionOrError->data(); + } + } + LLVMRustSetLastError("could not find requested section"); + return nullptr; +} + // Computes the LTO cache key for the provided 'ModId' in the given 'Data', // storing the result in 'KeyOut'. // Currently, this cache key is a SHA-1 hash of anything that could affect From 4ad22b91fc9811e37359a2024b6df04b6b2d5352 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 7 Sep 2023 15:45:25 +0000 Subject: [PATCH 127/217] Correct comment and assumption. --- compiler/rustc_mir_dataflow/src/value_analysis.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index b5f39f1a9d547..299bf692307ab 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -752,7 +752,7 @@ impl Map { let old = self.projections.insert((place, TrackElem::Discriminant), discr); assert!(old.is_none()); - // Allocate a value slot if it doesn't have one. + // Allocate a value slot since it doesn't have one. assert!(self.places[discr].value_index.is_none()); self.places[discr].value_index = Some(self.value_count.into()); self.value_count += 1; @@ -769,11 +769,10 @@ impl Map { let old = self.projections.insert((place, TrackElem::DerefLen), len); assert!(old.is_none()); - // Allocate a value slot if it doesn't have one. - if self.places[len].value_index.is_none() { - self.places[len].value_index = Some(self.value_count.into()); - self.value_count += 1; - } + // Allocate a value slot since it doesn't have one. + assert!( self.places[len].value_index.is_none() ); + self.places[len].value_index = Some(self.value_count.into()); + self.value_count += 1; } // Recurse with all fields of this place. From 0db66022b1e0f057362be1ca8593c3ff1fee1c85 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 7 Sep 2023 11:56:25 -0400 Subject: [PATCH 128/217] lto: handle Apple platforms correctly by eliding __LLVM, from section name --- compiler/rustc_codegen_llvm/src/back/lto.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 3964039ac2d19..5cf83b1accb16 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -154,7 +154,10 @@ fn get_bitcode_slice_from_object_data<'a>( if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") { return Ok(obj); } - let section_name = bitcode_section_name(cgcx); + // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name" + // which in the public API for sections gets treated as part of the section name, but internally + // in MachOObjectFile.cpp gets treated separately. + let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); let mut len = 0; let data = unsafe { llvm::LLVMRustGetSliceFromObjectDataByName( From b7a925a7ce37c5163ce81abec0fdf8d848d34ae5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 7 Sep 2023 15:59:05 +0000 Subject: [PATCH 129/217] Add test where slice is a const. --- ...n.DataflowConstProp.32bit.panic-abort.diff | 37 +++++++++++++++++-- ....DataflowConstProp.32bit.panic-unwind.diff | 37 +++++++++++++++++-- ...n.DataflowConstProp.64bit.panic-abort.diff | 37 +++++++++++++++++-- ....DataflowConstProp.64bit.panic-unwind.diff | 37 +++++++++++++++++-- .../mir-opt/dataflow-const-prop/slice_len.rs | 5 ++- 5 files changed, 136 insertions(+), 17 deletions(-) diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff index 580ac8ea4c092..be55d259dcf63 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -11,15 +11,26 @@ let _6: usize; let mut _7: usize; let mut _8: bool; - let mut _9: &[u32; 3]; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } bb0: { StorageLive(_1); StorageLive(_2); StorageLive(_3); StorageLive(_4); - _9 = const _; - _4 = _9; + _14 = const _; + _4 = _14; _3 = _4; _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); @@ -39,8 +50,26 @@ StorageDead(_6); StorageDead(_4); StorageDead(_2); - StorageDead(_1); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); _0 = const (); + StorageDead(_9); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff index 4792db7ac0c4b..f9a6c509ac8ed 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -11,15 +11,26 @@ let _6: usize; let mut _7: usize; let mut _8: bool; - let mut _9: &[u32; 3]; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } bb0: { StorageLive(_1); StorageLive(_2); StorageLive(_3); StorageLive(_4); - _9 = const _; - _4 = _9; + _14 = const _; + _4 = _14; _3 = _4; _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); @@ -39,8 +50,26 @@ StorageDead(_6); StorageDead(_4); StorageDead(_2); - StorageDead(_1); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); _0 = const (); + StorageDead(_9); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff index 580ac8ea4c092..be55d259dcf63 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -11,15 +11,26 @@ let _6: usize; let mut _7: usize; let mut _8: bool; - let mut _9: &[u32; 3]; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } bb0: { StorageLive(_1); StorageLive(_2); StorageLive(_3); StorageLive(_4); - _9 = const _; - _4 = _9; + _14 = const _; + _4 = _14; _3 = _4; _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); @@ -39,8 +50,26 @@ StorageDead(_6); StorageDead(_4); StorageDead(_2); - StorageDead(_1); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); _0 = const (); + StorageDead(_9); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff index 4792db7ac0c4b..f9a6c509ac8ed 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -11,15 +11,26 @@ let _6: usize; let mut _7: usize; let mut _8: bool; - let mut _9: &[u32; 3]; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } bb0: { StorageLive(_1); StorageLive(_2); StorageLive(_3); StorageLive(_4); - _9 = const _; - _4 = _9; + _14 = const _; + _4 = _14; _3 = _4; _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); @@ -39,8 +50,26 @@ StorageDead(_6); StorageDead(_4); StorageDead(_2); - StorageDead(_1); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); _0 = const (); + StorageDead(_9); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs index 7937e5de7e3e2..41367e48497bd 100644 --- a/tests/mir-opt/dataflow-const-prop/slice_len.rs +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -5,5 +5,8 @@ // EMIT_MIR slice_len.main.DataflowConstProp.diff fn main() { - (&[1u32, 2, 3] as &[u32])[1]; + let local = (&[1u32, 2, 3] as &[u32])[1]; + + const SLICE: &[u32] = &[1, 2, 3]; + let constant = SLICE[1]; } From 320bb8116f136f4748787cf92178da9e7e5b2d91 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Sep 2023 08:54:27 +0000 Subject: [PATCH 130/217] Don't require `Drop` for `[PhantomData; N]` where `N` and `T` are generic, if `T` requires `Drop` --- compiler/rustc_ty_utils/src/needs_drop.rs | 24 +++++++++++++++++++++-- tests/ui/consts/drop-maybe_uninit.rs | 17 ++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ui/consts/drop-maybe_uninit.rs diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 34fd31e49e10d..1fc5d9359a48a 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -19,13 +19,32 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> // needs drop. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = - drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some(); + let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false) + .filter(filter_array_elements(tcx, query.param_env)) + .next() + .is_some(); debug!("needs_drop_raw({:?}) = {:?}", query, res); res } +/// HACK: in order to not mistakenly assume that `[PhantomData; N]` requires drop glue +/// we check the element type for drop glue. The correct fix would be looking at the +/// entirety of the code around `needs_drop_components` and this file and come up with +/// logic that is easier to follow while not repeating any checks that may thus diverge. +fn filter_array_elements<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> impl Fn(&Result, AlwaysRequiresDrop>) -> bool { + move |ty| match ty { + Ok(ty) => match *ty.kind() { + ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)), + _ => true, + }, + Err(AlwaysRequiresDrop) => true, + } +} + fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -37,6 +56,7 @@ fn has_significant_drop_raw<'tcx>( adt_consider_insignificant_dtor(tcx), true, ) + .filter(filter_array_elements(tcx, query.param_env)) .next() .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); diff --git a/tests/ui/consts/drop-maybe_uninit.rs b/tests/ui/consts/drop-maybe_uninit.rs new file mode 100644 index 0000000000000..2fdeae5f1853a --- /dev/null +++ b/tests/ui/consts/drop-maybe_uninit.rs @@ -0,0 +1,17 @@ +// build-pass + +pub const fn f(_: [std::mem::MaybeUninit; N]) {} + +pub struct Blubb(*const T); + +pub const fn g(_: [Blubb; N]) {} + +pub struct Blorb([String; N]); + +pub const fn h(_: Blorb<0>) {} + +pub struct Wrap(Blorb<0>); + +pub const fn i(_: Wrap) {} + +fn main() {} From 31e5dd3a7942b35004f3a154c55728702f3dcb3e Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 7 Sep 2023 11:30:47 -0700 Subject: [PATCH 131/217] diagnostics: add test case for trait bounds diagnostic Closes #82038 It was fixed by b8e5ab20ed7a7677a998a163ccf7853764b195e6, a wide-reaching obligation tracking improvement. This commit adds a test case. --- tests/ui/trait-bounds/issue-82038.rs | 9 +++++++++ tests/ui/trait-bounds/issue-82038.stderr | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/ui/trait-bounds/issue-82038.rs create mode 100644 tests/ui/trait-bounds/issue-82038.stderr diff --git a/tests/ui/trait-bounds/issue-82038.rs b/tests/ui/trait-bounds/issue-82038.rs new file mode 100644 index 0000000000000..11de714faf014 --- /dev/null +++ b/tests/ui/trait-bounds/issue-82038.rs @@ -0,0 +1,9 @@ +// Failed bound `bool: Foo` must not point at the `Self: Clone` line + +trait Foo { + fn my_method() where Self: Clone; +} + +fn main() { + ::my_method(); //~ERROR [E0277] +} diff --git a/tests/ui/trait-bounds/issue-82038.stderr b/tests/ui/trait-bounds/issue-82038.stderr new file mode 100644 index 0000000000000..f37e3286f4bf8 --- /dev/null +++ b/tests/ui/trait-bounds/issue-82038.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `bool: Foo` is not satisfied + --> $DIR/issue-82038.rs:8:6 + | +LL | ::my_method(); + | ^^^^ the trait `Foo` is not implemented for `bool` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 717dc1ce212fb1a21ea037121e2bfa7b860b2854 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 7 Sep 2023 20:13:57 +0000 Subject: [PATCH 132/217] Enable incremental-relative-spans by default. --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_session/src/config.rs | 6 ------ compiler/rustc_session/src/options.rs | 3 --- 5 files changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 41db61d391a13..32046b0febf8d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -770,7 +770,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.tcx.sess.opts.incremental_relative_spans() { + if self.tcx.sess.opts.incremental.is_some() { span.with_parent(Some(self.current_hir_id_owner.def_id)) } else { // Do not make spans relative when not using incremental compilation. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 34d16bf00cd67..f87f4aba2b9ea 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -587,7 +587,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .resolver .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment); - if self.cx.sess.opts.incremental_relative_spans() { + if self.cx.sess.opts.incremental.is_some() { for (invoc, _) in invocations.iter_mut() { let expn_id = invoc.expansion_data.id; let parent_def = self.cx.resolver.invocation_parent(expn_id); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e20a202561ff0..f67f8015c0409 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1206,7 +1206,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.incremental_relative_spans() { + if tcx.sess.opts.incremental.is_some() { let definitions = tcx.untracked().definitions.freeze(); let mut owner_spans: Vec<_> = krate .owners diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 302e4e55d597d..501e7ebdde0f5 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1084,12 +1084,6 @@ impl Options { pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) } - - #[allow(rustc::bad_opt_access)] - pub fn incremental_relative_spans(&self) -> bool { - self.unstable_opts.incremental_relative_spans - || (self.unstable_features.is_nightly_build() && self.incremental.is_some()) - } } impl UnstableOptions { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 40099de707be6..0b7b1ec1e55b0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1524,9 +1524,6 @@ options! { incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof) \ (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")] - incremental_relative_spans: bool = (false, parse_bool, [TRACKED], - "hash spans relative to their parent item for incr. comp. (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify incr. comp. hashes of green query instances (default: no)"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], From 00b7d70710aa34e495a91727fe3e5bd7f97ae55e Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 7 Sep 2023 13:05:30 -0700 Subject: [PATCH 133/217] rustdoc: remove unused ID `mainThemeStyle` This was added in 003b2bc1c65251ec2fc80b78ed91c43fb35402ec and used to build the URL of the theme stylesheets. It isn't used any more, because f9e1f6ffdf03ec33cb29e20c88fc7bcc938c7f42 changed it so that the URL was supplied in a `` tag, which also provides the hashes of the files. --- src/librustdoc/html/markdown.rs | 1 - src/librustdoc/html/templates/page.html | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 98cc38a10d44d..a8d85fb6fb4ef 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1574,7 +1574,6 @@ fn init_id_map() -> FxHashMap, usize> { map.insert("crate-search-div".into(), 1); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). - map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 60ccfe4da4418..8cb43634377dc 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -15,8 +15,7 @@ {# #} {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {# #} {% if !layout.default_settings.is_empty() %}