From 3d90595054e1da5905024098aa15aceb193e5925 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Apr 2024 13:17:57 +0300 Subject: [PATCH 001/189] DependencyList: remove outdated comment --- compiler/rustc_middle/src/middle/dependency_format.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs index e7d0cffc85cfb..e4750147456d1 100644 --- a/compiler/rustc_middle/src/middle/dependency_format.rs +++ b/compiler/rustc_middle/src/middle/dependency_format.rs @@ -10,9 +10,6 @@ use rustc_session::config::CrateType; /// A list of dependencies for a certain crate type. /// /// The length of this vector is the same as the number of external crates used. -/// The value is None if the crate does not need to be linked (it was found -/// statically in another dylib), or Some(kind) if it needs to be linked as -/// `kind` (either static or dynamic). pub type DependencyList = Vec; /// A mapping of all required dependencies for a particular flavor of output. From 9e40b546eb6cd75aaca9bacf39f2463e5b5ffe86 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Apr 2024 13:34:12 +0300 Subject: [PATCH 002/189] add fixme --- compiler/rustc_middle/src/middle/dependency_format.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs index e4750147456d1..a3aff9a110130 100644 --- a/compiler/rustc_middle/src/middle/dependency_format.rs +++ b/compiler/rustc_middle/src/middle/dependency_format.rs @@ -4,6 +4,9 @@ //! For all the gory details, see the provider of the `dependency_formats` //! query. +// FIXME: move this file to rustc_metadata::dependency_format, but +// this will introduce circular dependency between rustc_metadata and rustc_middle + use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_session::config::CrateType; From 994b58fee7e66c25d4b13a8a95feaff650088301 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Apr 2024 10:45:37 -0400 Subject: [PATCH 003/189] Okay actually check only alias TYPES --- compiler/rustc_trait_selection/src/traits/wf.rs | 12 +++--------- tests/ui/higher-ranked/well-formed-aliases.rs | 8 ++++++++ tests/ui/higher-ranked/well-formed-aliases.stderr | 12 ++++++++++++ 3 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 tests/ui/higher-ranked/well-formed-aliases.rs create mode 100644 tests/ui/higher-ranked/well-formed-aliases.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f4189ff090204..57efd2996e409 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -435,12 +435,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } - /// Pushes the obligations required for an alias (except inherent) to be WF - /// into `self.out`. - fn compute_alias_ty(&mut self, data: ty::AliasTy<'tcx>) { - self.compute_alias_term(data.into()); - } - /// Pushes the obligations required for an alias (except inherent) to be WF /// into `self.out`. fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) { @@ -498,7 +492,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); } - self.compute_projection_args(data.args); + data.args.visit_with(self); } fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) { @@ -702,8 +696,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => { - self.compute_alias_ty(data); - return; // Subtree handled by compute_projection. + let obligations = self.nominal_obligations(data.def_id, data.args); + self.out.extend(obligations); } ty::Alias(ty::Inherent, data) => { self.compute_inherent_projection(data); diff --git a/tests/ui/higher-ranked/well-formed-aliases.rs b/tests/ui/higher-ranked/well-formed-aliases.rs new file mode 100644 index 0000000000000..60e013a54bcd5 --- /dev/null +++ b/tests/ui/higher-ranked/well-formed-aliases.rs @@ -0,0 +1,8 @@ +trait Trait { + type Gat; +} + +fn test(f: for<'a> fn(<&'a T as Trait>::Gat<&'a [str]>)) where for<'a> &'a T: Trait {} +//~^ ERROR the size for values of type `str` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/higher-ranked/well-formed-aliases.stderr b/tests/ui/higher-ranked/well-formed-aliases.stderr new file mode 100644 index 0000000000000..4a6f4e961d995 --- /dev/null +++ b/tests/ui/higher-ranked/well-formed-aliases.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/well-formed-aliases.rs:5:52 + | +LL | fn test(f: for<'a> fn(<&'a T as Trait>::Gat<&'a [str]>)) where for<'a> &'a T: Trait {} + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: slice and array elements must have `Sized` type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From d356c6804353f9130189fe72071481120f7bc232 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 7 Apr 2024 04:08:25 -0400 Subject: [PATCH 004/189] Update documentation for `hint::assert_unchecked` Rearrange the sections and add an example to `core::hint::assert_unchecked`. --- library/core/src/hint.rs | 93 +++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 6e2d88c6b8337..b8db4ad8237bd 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -111,36 +111,89 @@ pub const unsafe fn unreachable_unchecked() -> ! { /// Makes a *soundness* promise to the compiler that `cond` holds. /// -/// This may allow the optimizer to simplify things, -/// but it might also make the generated code slower. -/// Either way, calling it will most likely make compilation take longer. +/// This may allow the optimizer to simplify things, but it might also make the generated code +/// slower. Either way, calling it will most likely make compilation take longer. /// -/// This is a situational tool for micro-optimization, and is allowed to do nothing. -/// Any use should come with a repeatable benchmark to show the value -/// and allow removing it later should the optimizer get smarter and no longer need it. +/// You may know this from other places as +/// [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C, +/// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume). /// -/// The more complicated the condition the less likely this is to be fruitful. -/// For example, `assert_unchecked(foo.is_sorted())` is a complex enough value -/// that the compiler is unlikely to be able to take advantage of it. +/// This promotes a correctness requirement to a soundness requirement. Don't do that without +/// very good reason. /// -/// There's also no need to `assert_unchecked` basic properties of things. For -/// example, the compiler already knows the range of `count_ones`, so there's no -/// benefit to `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`. +/// # Usage /// -/// If ever you're tempted to write `assert_unchecked(false)`, then you're -/// actually looking for [`unreachable_unchecked()`]. +/// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use +/// should come with a repeatable benchmark to show the value, with the expectation to drop it +/// later should the optimizer get smarter and no longer need it. /// -/// You may know this from other places -/// as [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) -/// or [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume). +/// The more complicated the condition, the less likely this is to be useful. For example, +/// `assert_unchecked(foo.is_sorted())` is a complex enough value that the compiler is unlikely +/// to be able to take advantage of it. /// -/// This promotes a correctness requirement to a soundness requirement. -/// Don't do that without very good reason. +/// There's also no need to `assert_unchecked` basic properties of things. For example, the +/// compiler already knows the range of `count_ones`, so there is no benefit to +/// `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`. +/// +/// `assert_unchecked` is logically equivalent to `if !cond { unreachable_unchecked(); }`. If +/// ever you are tempted to write `assert_unchecked(false)`, you should instead use +/// [`unreachable_unchecked()`] directly. /// /// # Safety /// -/// `cond` must be `true`. It's immediate UB to call this with `false`. +/// `cond` must be `true`. It is immediate UB to call this with `false`. +/// +/// # Example +/// +/// ``` +/// #![feature(hint_assert_unchecked)] +/// +/// use core::hint; +/// +/// /// # Safety +/// /// +/// /// `p` must be nonnull and valid +/// pub unsafe fn next_value(p: *const i32) -> i32 { +/// // SAFETY: caller invariants guarantee that `p` is not null +/// unsafe { hint::assert_unchecked(!p.is_null()) } +/// +/// if p.is_null() { +/// return -1; +/// } else { +/// // SAFETY: caller invariants guarantee that `p` is valid +/// unsafe { *p + 1 } +/// } +/// } +/// ``` +/// +/// Without the `assert_unchecked`, the above function produces the following with optimizations +/// enabled: +/// +/// ```asm +/// next_value: +/// test rdi, rdi +/// je .LBB0_1 +/// mov eax, dword ptr [rdi] +/// inc eax +/// ret +/// .LBB0_1: +/// mov eax, -1 +/// ret +/// ``` +/// +/// Adding the assertion allows the optimizer to remove the extra check: +/// +/// ```asm +/// next_value: +/// mov eax, dword ptr [rdi] +/// inc eax +/// ret +/// ``` /// +/// This example is quite unlike anything that would be used in the real world: it is redundant +/// to put an an assertion right next to code that checks the same thing, and dereferencing a +/// pointer already has the builtin assumption that it is nonnull. However, it illustrates the +/// kind of changes the optimizer can make even when the behavior is less obviously related. #[inline(always)] #[doc(alias = "assume")] #[track_caller] From 5745c220e65a83436bb0bf855dcf83aebffe8c73 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 7 Apr 2024 04:30:49 -0400 Subject: [PATCH 005/189] Stabilize `hint_assert_unchecked` Make both `hint_assert_unchecked` and `const_hint_assert_unchecked` stable as `hint_assert_unchecked`. --- library/alloc/src/lib.rs | 1 - library/core/src/hint.rs | 8 +++----- library/core/src/intrinsics.rs | 2 +- library/core/src/lib.rs | 1 - library/std/src/lib.rs | 1 - tests/ui/consts/const-assert-unchecked-ub.rs | 6 +----- tests/ui/consts/const-assert-unchecked-ub.stderr | 2 +- 7 files changed, 6 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 895d1b8d59f2c..095e13ee98c98 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -126,7 +126,6 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(hasher_prefixfree_extras)] -#![feature(hint_assert_unchecked)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index b8db4ad8237bd..e637baf826ff2 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -146,8 +146,6 @@ pub const unsafe fn unreachable_unchecked() -> ! { /// # Example /// /// ``` -/// #![feature(hint_assert_unchecked)] -/// /// use core::hint; /// /// /// # Safety @@ -194,11 +192,11 @@ pub const unsafe fn unreachable_unchecked() -> ! { /// to put an an assertion right next to code that checks the same thing, and dereferencing a /// pointer already has the builtin assumption that it is nonnull. However, it illustrates the /// kind of changes the optimizer can make even when the behavior is less obviously related. +#[track_caller] #[inline(always)] #[doc(alias = "assume")] -#[track_caller] -#[unstable(feature = "hint_assert_unchecked", issue = "119131")] -#[rustc_const_unstable(feature = "const_hint_assert_unchecked", issue = "119131")] +#[stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn assert_unchecked(cond: bool) { // SAFETY: The caller promised `cond` is true. unsafe { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 6b5054a9f0612..598b7ac0f82c4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -959,7 +959,7 @@ extern "rust-intrinsic" { /// not be used if the invariant can be discovered by the optimizer on its /// own, or if it does not enable any significant optimizations. /// -/// This intrinsic does not have a stable counterpart. +/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. #[rustc_const_stable(feature = "const_assume", since = "1.77.0")] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ef28bc99c4fc8..abd8e1d1d0b2e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -130,7 +130,6 @@ #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_hint_assert_unchecked)] #![feature(const_index_range_slice_index)] #![feature(const_int_from_str)] #![feature(const_intrinsic_copy)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1c226f9f08f10..1fcfbdcd12dfb 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -335,7 +335,6 @@ #![feature(fmt_internals)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] -#![feature(hint_assert_unchecked)] #![feature(ip)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] diff --git a/tests/ui/consts/const-assert-unchecked-ub.rs b/tests/ui/consts/const-assert-unchecked-ub.rs index 5c05b813048b8..ffc02eedcb7a7 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.rs +++ b/tests/ui/consts/const-assert-unchecked-ub.rs @@ -1,10 +1,6 @@ -#![feature(hint_assert_unchecked)] -#![feature(const_hint_assert_unchecked)] - const _: () = unsafe { let n = u32::MAX.count_ones(); std::hint::assert_unchecked(n < 32); //~ ERROR evaluation of constant value failed }; -fn main() { -} +fn main() {} diff --git a/tests/ui/consts/const-assert-unchecked-ub.stderr b/tests/ui/consts/const-assert-unchecked-ub.stderr index 3957a3b1c246b..468f15f34728f 100644 --- a/tests/ui/consts/const-assert-unchecked-ub.stderr +++ b/tests/ui/consts/const-assert-unchecked-ub.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-assert-unchecked-ub.rs:6:5 + --> $DIR/const-assert-unchecked-ub.rs:3:5 | LL | std::hint::assert_unchecked(n < 32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false` From 5f37433b6cf063cc97356cb791b6f0eeb9200dff Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 23 Jun 2024 14:14:00 -0700 Subject: [PATCH 006/189] Add test of parenthesizing break value by AST pretty-printer --- tests/ui/unpretty/expanded-interpolation.rs | 20 +++++++++++++++++++ .../ui/unpretty/expanded-interpolation.stdout | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs index 8f0e21ce870d3..1dc72c67f511e 100644 --- a/tests/ui/unpretty/expanded-interpolation.rs +++ b/tests/ui/unpretty/expanded-interpolation.rs @@ -18,6 +18,26 @@ macro_rules! stmt { ($stmt:stmt) => { $stmt }; } +fn break_labeled_loop() { + let no_paren = 'outer: loop { + break 'outer expr!('inner: loop { break 'inner 1; } + 1); + }; + + let paren_around_break_value = 'outer: loop { + break expr!('inner: loop { break 'inner 1; } + 1); + }; + + macro_rules! breaking { + ($value:expr) => { + break $value + }; + } + + let paren_around_break_value = loop { + breaking!('inner: loop { break 'inner 1; } + 1); + }; +} + fn if_let() { macro_rules! if_let { ($pat:pat, $expr:expr) => { diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout index 73322b50f2d6e..ed075c9114ce6 100644 --- a/tests/ui/unpretty/expanded-interpolation.stdout +++ b/tests/ui/unpretty/expanded-interpolation.stdout @@ -20,6 +20,19 @@ macro_rules! expr { ($expr:expr) => { $expr }; } macro_rules! stmt { ($stmt:stmt) => { $stmt }; } +fn break_labeled_loop() { + let no_paren = + 'outer: loop { break 'outer 'inner: loop { break 'inner 1; } + 1; }; + + let paren_around_break_value = + 'outer: loop { break 'inner: loop { break 'inner 1; } + 1; }; + + macro_rules! breaking { ($value:expr) => { break $value }; } + + let paren_around_break_value = + loop { break 'inner: loop { break 'inner 1; } + 1; }; +} + fn if_let() { macro_rules! if_let { ($pat:pat, $expr:expr) => { if let $pat = $expr {} }; From 82c5cdc6b1de77634d63faacd6b606c99e816316 Mon Sep 17 00:00:00 2001 From: wooden-worm <93303706+wooden-worm@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:58:30 -0700 Subject: [PATCH 007/189] wasm64 build with target-feature=+simd128,+atomics --- .../crates/core_simd/src/swizzle_dyn.rs | 2 ++ library/std/src/lib.rs | 1 + library/std/src/sys/pal/wasm/atomics/futex.rs | 17 +++++++++-------- library/std/src/sys/pal/wasm/atomics/thread.rs | 8 ++++++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs index 8a1079042f076..3b6388d0f2759 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs @@ -30,6 +30,8 @@ where use core::arch::arm::{uint8x8_t, vtbl1_u8}; #[cfg(target_arch = "wasm32")] use core::arch::wasm32 as wasm; + #[cfg(target_arch = "wasm64")] + use core::arch::wasm64 as wasm; #[cfg(target_arch = "x86")] use core::arch::x86; #[cfg(target_arch = "x86_64")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 80f67838ac002..f67e4a050cfee 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -266,6 +266,7 @@ )] #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))] #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] +#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] #![cfg_attr( all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"), feature(stdarch_x86_has_cpuid) diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs index f4fbe9f48554b..a21b71efbbc69 100644 --- a/library/std/src/sys/pal/wasm/atomics/futex.rs +++ b/library/std/src/sys/pal/wasm/atomics/futex.rs @@ -1,4 +1,8 @@ -use crate::arch::wasm32; +#[cfg(target_arch = "wasm32")] +use core::arch::wasm32 as wasm; +#[cfg(target_arch = "wasm64")] +use core::arch::wasm64 as wasm; + use crate::sync::atomic::AtomicU32; use crate::time::Duration; @@ -10,11 +14,8 @@ use crate::time::Duration; pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool { let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1); unsafe { - wasm32::memory_atomic_wait32( - futex as *const AtomicU32 as *mut i32, - expected as i32, - timeout, - ) < 2 + wasm::memory_atomic_wait32(futex as *const AtomicU32 as *mut i32, expected as i32, timeout) + < 2 } } @@ -23,12 +24,12 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - /// Returns true if this actually woke up such a thread, /// or false if no thread was waiting on this futex. pub fn futex_wake(futex: &AtomicU32) -> bool { - unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 } + unsafe { wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 } } /// Wake up all threads that are waiting on futex_wait on this futex. pub fn futex_wake_all(futex: &AtomicU32) { unsafe { - wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32); + wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32); } } diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index 484bd08495eef..afdb159fe6f8b 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -19,7 +19,11 @@ impl Thread { pub fn set_name(_name: &CStr) {} pub fn sleep(dur: Duration) { - use crate::arch::wasm32; + #[cfg(target_arch = "wasm32")] + use core::arch::wasm32 as wasm; + #[cfg(target_arch = "wasm64")] + use core::arch::wasm64 as wasm; + use crate::cmp; // Use an atomic wait to block the current thread artificially with a @@ -31,7 +35,7 @@ impl Thread { while nanos > 0 { let amt = cmp::min(i64::MAX as u128, nanos); let mut x = 0; - let val = unsafe { wasm32::memory_atomic_wait32(&mut x, 0, amt as i64) }; + let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) }; debug_assert_eq!(val, 2); nanos -= amt; } From a82f70eeee6d79fb4c3417da738279d3d7ff599a Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Tue, 25 Jun 2024 18:04:21 +0800 Subject: [PATCH 008/189] Migrate some rustc_builtin_macros to SessionDiagnostic Signed-off-by: he1pa <18012015693@163.com> --- compiler/rustc_builtin_macros/messages.ftl | 11 +++++ compiler/rustc_builtin_macros/src/asm.rs | 13 +++--- compiler/rustc_builtin_macros/src/errors.rs | 40 +++++++++++++++++++ .../src/proc_macro_harness.rs | 24 +++++------ .../rustc_builtin_macros/src/source_util.rs | 11 +++-- 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 2d1269e1b6ad8..b56bfa98357b3 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -17,6 +17,9 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> *[false] clobber_abi, options }, or additional template string +builtin_macros_asm_expected_string_literal = expected string literal + .label = not a string literal + builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option @@ -25,6 +28,8 @@ builtin_macros_asm_modifier_invalid = asm template modifier must be a single cha builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive +builtin_macros_asm_no_matched_argument_name = there is no argument named `{$name}` + builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided @@ -228,10 +233,16 @@ builtin_macros_only_one_argument = {$name} takes 1 argument builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]` +builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions = the `#[{$path}]` attribute may only be used on bare functions + +builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type + builtin_macros_requires_cfg_pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required +builtin_macros_source_uitls_expected_item = expected item, found `{$token}` + builtin_macros_takes_no_arguments = {$name} takes no arguments builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 64238e81b2666..dd0f9aaf22104 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -390,9 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.dcx().struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); + return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span })); } }; @@ -639,14 +637,13 @@ fn expand_preparsed_asm( match args.named_args.get(&Symbol::intern(name)) { Some(&idx) => Some(idx), None => { - let msg = format!("there is no argument named `{name}`"); let span = arg.position_span; ecx.dcx() - .struct_span_err( - template_span + .create_err(errors::AsmNoMatchedArgumentName { + name: name.to_owned(), + span: template_span .from_inner(InnerSpan::new(span.start, span.end)), - msg, - ) + }) .emit(); None } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ed2f98f2a393c..49d640436c2f3 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -728,6 +728,14 @@ pub(crate) struct AsmExpectedComma { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_expected_string_literal)] +pub(crate) struct AsmExpectedStringLiteral { + #[primary_span] + #[label] + pub(crate) span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_asm_underscore_input)] pub(crate) struct AsmUnderscoreInput { @@ -781,6 +789,14 @@ pub(crate) struct AsmNoReturn { pub(crate) outputs_sp: Vec, } +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_no_matched_argument_name)] +pub(crate) struct AsmNoMatchedArgumentName { + pub(crate) name: String, + #[primary_span] + pub(crate) span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_asm_mayunwind)] pub(crate) struct AsmMayUnwind { @@ -872,3 +888,27 @@ pub(crate) struct TakesNoArguments<'a> { pub span: Span, pub name: &'a str, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions)] +pub(crate) struct AttributeOnlyBeUsedOnBareFunctions<'a> { + #[primary_span] + pub span: Span, + pub path: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_proc_macro_attribute_only_usable_with_crate_type)] +pub(crate) struct AttributeOnlyUsableWithCrateType<'a> { + #[primary_span] + pub span: Span, + pub path: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_source_uitls_expected_item)] +pub(crate) struct ExpectedItem<'a> { + #[primary_span] + pub span: Span, + pub token: &'a str, +} diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 99d0191958d68..a8a595ea5796f 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -214,12 +214,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { }; if !is_fn { - let msg = format!( - "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); + self.dcx + .create_err(errors::AttributeOnlyBeUsedOnBareFunctions { + span: attr.span, + path: &pprust::path_to_string(&attr.get_normal_item().path), + }) + .emit(); return; } @@ -228,12 +228,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { } if !self.is_proc_macro_crate { - let msg = format!( - "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); + self.dcx + .create_err(errors::AttributeOnlyUsableWithCrateType { + span: attr.span, + path: &pprust::path_to_string(&attr.get_normal_item().path), + }) + .emit(); return; } diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index dc1d82df0c395..44db12cf69502 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::util::{ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, }; @@ -165,9 +166,13 @@ pub(crate) fn expand_include<'cx>( Ok(Some(item)) => ret.push(item), Ok(None) => { if self.p.token != token::Eof { - let token = pprust::token_to_string(&self.p.token); - let msg = format!("expected item, found `{token}`"); - self.p.dcx().span_err(self.p.token.span, msg); + self.p + .dcx() + .create_err(errors::ExpectedItem { + span: self.p.token.span, + token: &pprust::token_to_string(&self.p.token), + }) + .emit(); } break; From 6896fa66198a4119dfe7d0350137c5fab99eea8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2024 19:24:32 +0200 Subject: [PATCH 009/189] simd_bitmask intrinsic: add a non-power-of-2 multi-byte example --- library/core/src/intrinsics/simd.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 4be5e62ea5bc6..6054ff8b2ccb5 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -463,7 +463,7 @@ extern "rust-intrinsic" { /// `T` must be an integer vector. /// /// `U` must be either the smallest unsigned integer with at least as many bits as the length - /// of `T`, or the smallest array of `u8` with as many bits as the length of `T`. + /// of `T`, or the smallest array of `u8` with at least as many bits as the length of `T`. /// /// Each element is truncated to a single bit and packed into the result. /// @@ -475,12 +475,19 @@ extern "rust-intrinsic" { /// * On little endian, the least significant bit corresponds to the first vector element. /// * On big endian, the least significant bit corresponds to the last vector element. /// - /// For example, `[!0, 0, !0, !0]` packs to `0b1101` on little endian and `0b1011` on big - /// endian. + /// For example, `[!0, 0, !0, !0]` packs to + /// - `0b1101u8` or `[0b1101]` on little endian, and + /// - `0b1011u8` or `[0b1011]` on big endian. /// - /// To consider a larger example, `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs - /// to `[0b00000001, 0b01000011]` or `0b0100001100000001` on little endian, and `[0b10000000, - /// 0b11000010]` or `0b1000000011000010` on big endian. + /// To consider a larger example, + /// `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs to + /// - `0b0100001100000001u16` or `[0b00000001, 0b01000011]` on little endian, and + /// - `0b1000000011000010u16` or `[0b10000000, 0b11000010]` on big endian. + /// + /// And finally, a non-power-of-2 example with multiple bytes: + /// `[!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]` packs to + /// - `0b0101001011u16` or `[0b01001011, 0b01]` on little endian, and + /// - `0b1101001010u16` or `[0b11, 0b01001010]` on big endian. /// /// # Safety /// `x` must contain only `0` and `!0`. From 372847dd4447bcb5a8c3595f70fd88002a580cbd Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 26 Jun 2024 17:01:04 -0400 Subject: [PATCH 010/189] Implement TC's match ergonomics 2024 proposal Under gate `ref_pat_eat_one_layer_2024_structural`. Enabling `ref_pat_eat_one_layer_2024` at the same time allows the union of what the individual gates allow. --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_typeck/src/pat.rs | 84 ++++++--- compiler/rustc_span/src/symbol.rs | 1 + ...feature-gate-ref_pat_eat_one_layer_2024.rs | 1 + ...ure-gate-ref_pat_eat_one_layer_2024.stderr | 20 +-- .../ref_pat_eat_one_layer_2024.rs | 12 +- ...ef_pat_eat_one_layer_2024_fail.both.stderr | 156 ++++++++++++++++ ...at_eat_one_layer_2024_fail.classic.stderr} | 56 +++--- .../ref_pat_eat_one_layer_2024_fail.rs | 24 ++- ..._eat_one_layer_2024_fail.structural.stderr | 167 ++++++++++++++++++ 11 files changed, 451 insertions(+), 73 deletions(-) create mode 100644 tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr rename tests/ui/match/ref_pat_eat_one_layer_2024/{ref_pat_eat_one_layer_2024_fail.stderr => ref_pat_eat_one_layer_2024_fail.classic.stderr} (76%) create mode 100644 tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4a3ce0e0c3066..9fcc0b25a2634 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -711,6 +711,7 @@ pub enum ByRef { } impl ByRef { + #[must_use] pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self { if let ByRef::Yes(old_mutbl) = &mut self { *old_mutbl = cmp::min(*old_mutbl, mutbl); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f4e20328814d7..f100d3e4ca84e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -573,6 +573,8 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), + /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant + (incomplete, ref_pat_eat_one_layer_2024_structural, "1.79.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index aaf3d3ec34d01..8ce99e204e19f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -328,8 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjust_mode: AdjustMode, max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { - if let ByRef::Yes(Mutability::Mut) = def_br { - debug_assert!(max_ref_mutbl == MutblCap::Mut); + #[cfg(debug_assertions)] + if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut { + span_bug!(pat.span, "Pattern mutability cap violated!"); } match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), @@ -437,7 +438,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if self.tcx.features().ref_pat_eat_one_layer_2024 { + let features = self.tcx.features(); + if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { max_ref_mutbl = MutblCap::Not; @@ -669,7 +671,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if pat.span.at_least_rust_2024() + && (self.tcx.features().ref_pat_eat_one_layer_2024 + || self.tcx.features().ref_pat_eat_one_layer_2024_structural) + { if !self.tcx.features().mut_ref { feature_err( &self.tcx.sess, @@ -2122,7 +2127,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let tcx = self.tcx; + let features = tcx.features(); + let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; + let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; + + let no_ref_mut_behind_and = + ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; let pat_prefix_span = @@ -2137,32 +2148,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info.max_ref_mutbl = MutblCap::Mut; } + expected = self.try_structurally_resolve_type(pat.span, expected); if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - // ref pattern consumes inherited reference - - if pat_mutbl > inh_mut { - // Tried to match inherited `ref` with `&mut`, which is an error - let err_msg = "cannot match inherited `&` with `&mut` pattern"; - let err = if let Some(span) = pat_prefix_span { - let mut err = self.dcx().struct_span_err(span, err_msg); - err.span_suggestion_verbose( - span, - "replace this `&mut` pattern with `&`", - "&", - Applicability::MachineApplicable, - ); - err + if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() { + // Don't attempt to consume inherited reference + pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); + } else { + // ref pattern attempts to consume inherited reference + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut` + if !ref_pat_eat_one_layer_2024_structural { + let err_msg = "mismatched types"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.code(E0308); + err.note("cannot match inherited `&` with `&mut` pattern"); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + + pat_info.binding_mode = ByRef::No; + self.typeck_results + .borrow_mut() + .skipped_ref_pats_mut() + .insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } else { - self.dcx().struct_span_err(pat.span, err_msg) - }; - err.emit(); + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } - - pat_info.binding_mode = ByRef::No; - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; } } else { // Reset binding mode on old editions @@ -2177,8 +2205,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let tcx = self.tcx; - expected = self.try_structurally_resolve_type(pat.span, expected); let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { Ok(()) => { // `demand::subtype` would be good enough, but using `eqtype` turns diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6d4a8c29bc902..7cd5e4f7ce4c1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1502,6 +1502,7 @@ symbols! { recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, + ref_pat_eat_one_layer_2024_structural, ref_pat_everywhere, ref_unwind_safe_trait, reference, diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs index 83f1ee6a77e89..7cbe8e0943ae4 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs @@ -1,5 +1,6 @@ //@ edition: 2024 //@ compile-flags: -Zunstable-options +// gate-test-ref_pat_eat_one_layer_2024_structural pub fn main() { if let Some(Some(&x)) = &Some(&Some(0)) { diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr index 132fe421a18d8..b3ea60252ac47 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:6:22 | LL | if let Some(Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -14,7 +14,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:11:23 | LL | let _: &u32 = x; | ---- ^ expected `&u32`, found integer @@ -27,7 +27,7 @@ LL | let _: &u32 = &x; | + error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:14:23 | LL | if let Some(Some(&&x)) = &Some(Some(&0)) { | ^^ --------------- this expression has type `&Option>` @@ -43,7 +43,7 @@ LL + if let Some(Some(&x)) = &Some(Some(&0)) { | error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:18:17 | LL | if let Some(&Some(x)) = &Some(Some(0)) { | ^^^^^^^^ -------------- this expression has type `&Option>` @@ -54,7 +54,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` @@ -64,7 +64,7 @@ LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ @@ -74,7 +74,7 @@ LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:26:22 | LL | if let Some(Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -89,7 +89,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:30:27 | LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` @@ -104,7 +104,7 @@ LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23 | LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` @@ -114,7 +114,7 @@ LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23 + --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23 | LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { | ^^^^^^ diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs index 829b7f86e2621..0130189b874c6 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs @@ -1,8 +1,10 @@ //@ run-pass //@ edition: 2024 //@ compile-flags: -Zunstable-options +//@ revisions: classic structural both #![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] +#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(Some(&x)) = &Some(&Some(0)) { @@ -53,4 +55,12 @@ pub fn main() { if let Some(&Some(x)) = &mut Some(Some(0)) { let _: u32 = x; } + #[cfg(any(classic, both))] + if let Some(&mut x) = &mut Some(&0) { + let _: &u32 = x; + } + #[cfg(any(structural, both))] + if let Some(&mut x) = &Some(&mut 0) { + let _: &u32 = x; + } } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr new file mode 100644 index 0000000000000..f8931403774a3 --- /dev/null +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr @@ -0,0 +1,156 @@ +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23 + | +LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27 + | +LL | let _: &mut u32 = x; + | -------- ^ types differ in mutability + | | + | expected due to this + | + = note: expected mutable reference `&mut u32` + found reference `&{integer}` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29 + | +LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { + | ^^^^^^ ------------------------- this expression has type `&Option>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9 + | +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9 + | +LL | let &mut _ = &&mut 0; + | ^^^^^^ ------- this expression has type `&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + | ^^^^^^ --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14 + | +LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + | ^^^^^^^^^^^^^^^^ -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&mut &&&mut &mut {integer}` + found mutable reference `&mut _` + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13 + | +LL | let Foo(mut a) = &Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13 + | +LL | let Foo(mut a) = &mut Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr similarity index 76% rename from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr rename to tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr index 26317e43d023e..0010a612c30f1 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr @@ -1,27 +1,29 @@ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(&_)) = &Some(&Some(0)) { | ~ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23 | LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:14:27 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27 | LL | let _: &mut u32 = x; | -------- ^ types differ in mutability @@ -31,52 +33,56 @@ LL | let _: &mut u32 = x; = note: expected mutable reference `&mut u32` found reference `&{integer}` -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { | ~ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29 | LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { | ~ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(x)) = &Some(Some(0)) { | ~ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17 | LL | if let Some(&mut Some(x)) = &Some(Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(x)) = &Some(Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9 | LL | let &mut _ = &&0; | ^^^^^^ --- this expression has type `&&{integer}` @@ -87,7 +93,7 @@ LL | let &mut _ = &&0; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:33:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9 | LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` @@ -97,30 +103,32 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` found mutable reference `&mut _` -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:17 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:38:17 | LL | if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { | ~ -error: cannot match inherited `&` with `&mut` pattern - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:40:22 +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:42:22 | LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { | ^^^^^ | + = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:44:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9 | LL | let &mut _ = &&mut 0; | ^^^^^^ ------- this expression has type `&&mut {integer}` @@ -131,7 +139,7 @@ LL | let &mut _ = &&mut 0; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:47:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9 | LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; | ^^^^^^ --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` @@ -142,7 +150,7 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:50:14 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14 | LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; | ^^^^^^^^^^^^^^^^ -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}` @@ -153,7 +161,7 @@ LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; found mutable reference `&mut _` error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:13 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13 | LL | let Foo(mut a) = &Foo(0); | ^^^^ @@ -163,7 +171,7 @@ LL | let Foo(mut a) = &Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:59:13 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13 | LL | let Foo(mut a) = &mut Foo(0); | ^^^^ diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index 40e8293e24111..4a40060b2ea40 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -1,30 +1,32 @@ //@ edition: 2024 //@ compile-flags: -Zunstable-options +//@ revisions: classic structural both #![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] +#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&mut Some(&_)) = &Some(&Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } if let Some(&Some(x)) = &mut Some(&Some(0)) { let _: &mut u32 = x; //~^ ERROR: mismatched types } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //~^ ERROR: mismatched types } let &mut _ = &&0; @@ -34,11 +36,11 @@ pub fn main() { //~^ ERROR: mismatched types if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //[classic]~^ ERROR: mismatched types } if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - //~^ ERROR: cannot match inherited `&` with `&mut` pattern + //[classic]~^ ERROR: mismatched types } let &mut _ = &&mut 0; @@ -50,6 +52,10 @@ pub fn main() { let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; //~^ ERROR: mismatched types + if let Some(&mut _) = &mut Some(&0) { + //[structural]~^ ERROR + } + struct Foo(u8); let Foo(mut a) = &Foo(0); diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr new file mode 100644 index 0000000000000..379bb6f4eaab3 --- /dev/null +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr @@ -0,0 +1,167 @@ +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23 + | +LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27 + | +LL | let _: &mut u32 = x; + | -------- ^ types differ in mutability + | | + | expected due to this + | + = note: expected mutable reference `&mut u32` + found reference `&{integer}` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29 + | +LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { + | ^^^^^^ ------------------------- this expression has type `&Option>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9 + | +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9 + | +LL | let &mut _ = &&mut 0; + | ^^^^^^ ------- this expression has type `&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + | ^^^^^^ --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14 + | +LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + | ^^^^^^^^^^^^^^^^ -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&mut &&&mut &mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:17 + | +LL | if let Some(&mut _) = &mut Some(&0) { + | ^^^^^^ ------------- this expression has type `&mut Option<&{integer}>` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13 + | +LL | let Foo(mut a) = &Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13 + | +LL | let Foo(mut a) = &mut Foo(0); + | ^^^^ + | + = note: see issue #123076 for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. From 35f6b7b97a7dd5fa21834a35faaa7470a071424a Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 26 Jun 2024 17:29:16 -0400 Subject: [PATCH 011/189] Fix tidy --- src/tools/tidy/src/features.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 3e84bf3c34be5..e8dff2dc26163 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -112,7 +112,7 @@ pub fn check( let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); let filen_underscore = filename.replace('-', "_").replace(".rs", ""); - let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features); + let filename_gate = test_filen_gate(&filen_underscore, &mut features); for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { @@ -128,7 +128,7 @@ pub fn check( }; match features.get_mut(feature_name) { Some(f) => { - if filename_is_gate_test { + if filename_gate == Some(feature_name) { err(&format!( "The file is already marked as gate test \ through its name, no need for a \ @@ -259,18 +259,18 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str()) } -fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { +fn test_filen_gate<'f>(filen_underscore: &'f str, features: &mut Features) -> Option<&'f str> { let prefix = "feature_gate_"; - if filen_underscore.starts_with(prefix) { + if let Some(suffix) = filen_underscore.strip_prefix(prefix) { for (n, f) in features.iter_mut() { // Equivalent to filen_underscore == format!("feature_gate_{n}") - if &filen_underscore[prefix.len()..] == n { + if suffix == n { f.has_gate_test = true; - return true; + return Some(suffix); } } } - false + None } pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features { From cf9bcb26a6582dcc9cceebb455acf330feda28f6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Jun 2024 11:09:20 +0000 Subject: [PATCH 012/189] Remove duplicate of tests/ui/impl-trait/nested-return-type2.rs --- tests/ui/type/subtyping-opaque-type.rs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/ui/type/subtyping-opaque-type.rs diff --git a/tests/ui/type/subtyping-opaque-type.rs b/tests/ui/type/subtyping-opaque-type.rs deleted file mode 100644 index e17114a364768..0000000000000 --- a/tests/ui/type/subtyping-opaque-type.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ check-pass -//@ compile-flags: -Zvalidate-mir -trait Duh {} - -impl Duh for i32 {} - -trait Trait { - type Assoc: Duh; -} - -impl R> Trait for F { - type Assoc = R; -} - -fn foo() -> impl Trait { - || 42 -} - -fn main() {} From 10a513bacc994ebffcd088b798caa52c55064332 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 27 Jun 2024 11:10:55 +0000 Subject: [PATCH 013/189] Remove duplicate of tests/ui/impl-trait/nested-return-type2-tait2.rs --- ...it-in-function-return-type-issue-101903.rs | 29 ------------------- ...n-function-return-type-issue-101903.stderr | 13 --------- 2 files changed, 42 deletions(-) delete mode 100644 tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs delete mode 100644 tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs deleted file mode 100644 index 4f9d54737dc4c..0000000000000 --- a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ check-pass - -// See https://doc.rust-lang.org/1.77.0/nightly-rustc/rustc_lint/opaque_hidden_inferred_bound/static.OPAQUE_HIDDEN_INFERRED_BOUND.html#example - -#![feature(type_alias_impl_trait)] -#![allow(dead_code)] - -trait Duh {} - -impl Duh for i32 {} - -trait Trait { - type Assoc: Duh; -} - -impl R> Trait for F { - type Assoc = R; -} - -type Sendable = impl Send; - -type Foo = impl Trait; - //~^ WARNING opaque type `Foo` does not satisfy its associated type bounds - -fn foo() -> Foo { - || 42 -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr deleted file mode 100644 index 68def454c7fbd..0000000000000 --- a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr +++ /dev/null @@ -1,13 +0,0 @@ -warning: opaque type `Foo` does not satisfy its associated type bounds - --> $DIR/tait-in-function-return-type-issue-101903.rs:22:23 - | -LL | type Assoc: Duh; - | --- this associated type bound is unsatisfied for `Sendable` -... -LL | type Foo = impl Trait; - | ^^^^^^^^^^^^^^^^ - | - = note: `#[warn(opaque_hidden_inferred_bound)]` on by default - -warning: 1 warning emitted - From 71dfbeabc4abe992a42025a5b7341e1ceec22e0b Mon Sep 17 00:00:00 2001 From: Goldstein Date: Mon, 25 Mar 2024 20:44:58 +0300 Subject: [PATCH 014/189] Disable dead variant removal for `#[repr(C)]` enums. See https://github.com/rust-lang/unsafe-code-guidelines/issues/500. --- compiler/rustc_abi/src/layout.rs | 4 +- compiler/rustc_abi/src/lib.rs | 2 +- tests/ui/abi/compatibility.rs | 4 + ...-variants.aarch64-unknown-linux-gnu.stderr | 288 ++++++++++++++++++ ...-c-dead-variants.armebv7r-none-eabi.stderr | 288 ++++++++++++++++++ ...-dead-variants.i686-pc-windows-msvc.stderr | 288 ++++++++++++++++++ tests/ui/repr/repr-c-dead-variants.rs | 63 ++++ ...d-variants.x86_64-unknown-linux-gnu.stderr | 288 ++++++++++++++++++ tests/ui/repr/repr-c-int-dead-variants.rs | 38 +++ tests/ui/repr/repr-c-int-dead-variants.stderr | 288 ++++++++++++++++++ 10 files changed, 1548 insertions(+), 3 deletions(-) create mode 100644 tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr create mode 100644 tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr create mode 100644 tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr create mode 100644 tests/ui/repr/repr-c-dead-variants.rs create mode 100644 tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr create mode 100644 tests/ui/repr/repr-c-int-dead-variants.rs create mode 100644 tests/ui/repr/repr-c-int-dead-variants.stderr diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a95ef4c460f45..aff0d70bf90d9 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -186,7 +186,7 @@ pub trait LayoutCalculator { let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() - .filter_map(|(i, v)| if absent(v) { None } else { Some(i) }); + .filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) }); (present_variants.next(), present_variants.next()) }; let present_first = match present_first { @@ -621,7 +621,7 @@ where let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { continue; } if discr_type.is_signed() { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 5e3f64540e4aa..1e5e391d19b5d 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1401,7 +1401,7 @@ pub enum Variants { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, - /// Enum-likes with more than one inhabited variant: each variant comes with + /// Enum-likes with more than one variant: each variant comes with /// a *discriminant* (usually the same as the variant index but the user can /// assign explicit discriminant values). That discriminant is encoded /// as a *tag* on the machine. The layout of each variant is diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 373d1cce1d73d..086177efb77b9 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -277,6 +277,10 @@ test_abi_compatible!(zst_unit, Zst, ()); test_abi_compatible!(zst_array, Zst, [u8; 0]); test_abi_compatible!(nonzero_int, NonZero, i32); +// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness. +enum Void {} +test_abi_compatible!(repr_c_enum_void, ReprCEnum, ReprCEnum>); + // `DispatchFromDyn` relies on ABI compatibility. // This is interesting since these types are not `repr(transparent)`. So this is not part of our // public ABI guarantees, but is relied on by the compiler. diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr new file mode 100644 index 0000000000000..e2e57fe0e7311 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -0,0 +1,288 @@ +error: layout_of(Univariant) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:38:1 + | +LL | enum Univariant { + | ^^^^^^^^^^^^^^^ + +error: layout_of(TwoVariants) = Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:45:1 + | +LL | enum TwoVariants { + | ^^^^^^^^^^^^^^^^ + +error: layout_of(DeadBranchHasOtherField) = Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + Size(8 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + }, + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + }, + ], + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + } + --> $DIR/repr-c-dead-variants.rs:57:1 + | +LL | enum DeadBranchHasOtherField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr new file mode 100644 index 0000000000000..6ecdab1cc140c --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -0,0 +1,288 @@ +error: layout_of(Univariant) = Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + } + --> $DIR/repr-c-dead-variants.rs:38:1 + | +LL | enum Univariant { + | ^^^^^^^^^^^^^^^ + +error: layout_of(TwoVariants) = Layout { + size: Size(2 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(2 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + } + --> $DIR/repr-c-dead-variants.rs:45:1 + | +LL | enum TwoVariants { + | ^^^^^^^^^^^^^^^^ + +error: layout_of(DeadBranchHasOtherField) = Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + Size(8 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + }, + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + }, + ], + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + } + --> $DIR/repr-c-dead-variants.rs:57:1 + | +LL | enum DeadBranchHasOtherField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr new file mode 100644 index 0000000000000..e2e57fe0e7311 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -0,0 +1,288 @@ +error: layout_of(Univariant) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:38:1 + | +LL | enum Univariant { + | ^^^^^^^^^^^^^^^ + +error: layout_of(TwoVariants) = Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:45:1 + | +LL | enum TwoVariants { + | ^^^^^^^^^^^^^^^^ + +error: layout_of(DeadBranchHasOtherField) = Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + Size(8 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + }, + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + }, + ], + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + } + --> $DIR/repr-c-dead-variants.rs:57:1 + | +LL | enum DeadBranchHasOtherField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs new file mode 100644 index 0000000000000..f113588e83fe9 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.rs @@ -0,0 +1,63 @@ +#![feature(no_core, rustc_attrs, lang_items)] +#![allow(dead_code)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +// See also: repr-c-int-dead-variants.rs + +//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" + +// This test depends on the value of the `c_enum_min_bits` target option. +// As there's no way to actually check it from UI test, we only run this test on a subset of archs. +// Four archs specifically are chosen: one for major architectures (x86_64, i686, aarch64) +// and `armebv7r-none-eabi` that has `c_enum_min_bits` set to 8. + +//@ revisions: aarch64-unknown-linux-gnu +//@[aarch64-unknown-linux-gnu] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64-unknown-linux-gnu] needs-llvm-components: aarch64 + +//@ revisions: i686-pc-windows-msvc +//@[i686-pc-windows-msvc] compile-flags: --target i686-pc-windows-gnu +//@[i686-pc-windows-msvc] needs-llvm-components: x86 + +//@ revisions: x86_64-unknown-linux-gnu +//@[x86_64-unknown-linux-gnu] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-unknown-linux-gnu] needs-llvm-components: x86 +// +//@ revisions: armebv7r-none-eabi +//@[armebv7r-none-eabi] compile-flags: --target armebv7r-none-eabi +//@[armebv7r-none-eabi] needs-llvm-components: arm + +// A simple uninhabited type. +enum Void {} + +// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs. +#[repr(C)] +#[rustc_layout(debug)] +enum Univariant { //~ ERROR layout_of + Variant(Void), +} + +// ADTs with variants that have fields must have space allocated for those fields. +#[repr(C)] +#[rustc_layout(debug)] +enum TwoVariants { //~ ERROR layout_of + Variant1(Void), + Variant2(u8), +} + +// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned. +#[repr(C, align(8))] +struct Align8U64(u64); + +// This one is 2 x u64: we reserve space for fields in a dead branch. +#[repr(C)] +#[rustc_layout(debug)] +enum DeadBranchHasOtherField { //~ ERROR layout_of + Variant1(Void, Align8U64), + Variant2(u8), +} + +#[lang = "sized"] +trait Sized {} diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr new file mode 100644 index 0000000000000..e2e57fe0e7311 --- /dev/null +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -0,0 +1,288 @@ +error: layout_of(Univariant) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:38:1 + | +LL | enum Univariant { + | ^^^^^^^^^^^^^^^ + +error: layout_of(TwoVariants) = Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + Layout { + size: Size(8 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(4 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/repr-c-dead-variants.rs:45:1 + | +LL | enum TwoVariants { + | ^^^^^^^^^^^^^^^^ + +error: layout_of(DeadBranchHasOtherField) = Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + Size(8 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + }, + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + }, + ], + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + } + --> $DIR/repr-c-dead-variants.rs:57:1 + | +LL | enum DeadBranchHasOtherField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs new file mode 100644 index 0000000000000..8d2b39bd6486e --- /dev/null +++ b/tests/ui/repr/repr-c-int-dead-variants.rs @@ -0,0 +1,38 @@ +#![feature(rustc_attrs)] +#![allow(dead_code)] + +// See also: repr-c-dead-variants.rs + +//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" + +// A simple uninhabited type. +enum Void {} + +// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs. +#[repr(C, u8)] +#[rustc_layout(debug)] +enum UnivariantU8 { //~ ERROR layout_of + Variant(Void), +} + +// ADTs with variants that have fields must have space allocated for those fields. +#[repr(C, u8)] +#[rustc_layout(debug)] +enum TwoVariantsU8 { //~ ERROR layout_of + Variant1(Void), + Variant2(u8), +} + +// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned. +#[repr(C, align(8))] +struct Align8U64(u64); + +// This one is 2 x u64: we reserve space for fields in a dead branch. +#[repr(C, u8)] +#[rustc_layout(debug)] +enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of + Variant1(Void, Align8U64), + Variant2(u8), +} + +fn main() {} diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr new file mode 100644 index 0000000000000..f7df576df248b --- /dev/null +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -0,0 +1,288 @@ +error: layout_of(UnivariantU8) = Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + } + --> $DIR/repr-c-int-dead-variants.rs:14:1 + | +LL | enum UnivariantU8 { + | ^^^^^^^^^^^^^^^^^ + +error: layout_of(TwoVariantsU8) = Layout { + size: Size(2 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(2 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: ScalarPair( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + Union { + value: Int( + I8, + false, + ), + }, + ), + fields: Arbitrary { + offsets: [ + Size(1 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + } + --> $DIR/repr-c-int-dead-variants.rs:21:1 + | +LL | enum TwoVariantsU8 { + | ^^^^^^^^^^^^^^^^^^ + +error: layout_of(DeadBranchHasOtherFieldU8) = Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Uninhabited, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + Size(8 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + }, + Layout { + size: Size(16 bytes), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(8 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + }, + ], + }, + max_repr_align: Some( + Align(8 bytes), + ), + unadjusted_abi_align: Align(8 bytes), + } + --> $DIR/repr-c-int-dead-variants.rs:33:1 + | +LL | enum DeadBranchHasOtherFieldU8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 8a3c07afbe94ff892b9fef982dea3ba1af7c7a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20=E2=80=9CGoldstein=E2=80=9D=20Siling?= Date: Sun, 5 May 2024 13:13:55 +0300 Subject: [PATCH 015/189] Clarify guarantees about ABI compatibility Co-authored-by: Ralf Jung --- tests/ui/abi/compatibility.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 086177efb77b9..1bff3baaf7dca 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -278,6 +278,7 @@ test_abi_compatible!(zst_array, Zst, [u8; 0]); test_abi_compatible!(nonzero_int, NonZero, i32); // `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness. +// (However, this is *not* a guarantee. We only guarantee same layout, not same ABI.) enum Void {} test_abi_compatible!(repr_c_enum_void, ReprCEnum, ReprCEnum>); From b1a0c0b1231a554d4ae699221a80a6e2f81bac4d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 11:49:16 -0400 Subject: [PATCH 016/189] Change RTN to use .. again --- compiler/rustc_ast/src/ast.rs | 5 +++- compiler/rustc_ast/src/mut_visit.rs | 1 + compiler/rustc_ast/src/util/classify.rs | 2 +- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/messages.ftl | 3 ++ compiler/rustc_ast_lowering/src/errors.rs | 6 ++++ compiler/rustc_ast_lowering/src/lib.rs | 25 +++++++---------- compiler/rustc_ast_lowering/src/path.rs | 3 ++ .../rustc_ast_passes/src/ast_validation.rs | 7 +++-- compiler/rustc_ast_passes/src/feature_gate.rs | 24 ++-------------- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 ++++ compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_parse/messages.ftl | 4 --- compiler/rustc_parse/src/errors.rs | 8 ------ compiler/rustc_parse/src/parser/path.rs | 27 ++++-------------- compiler/rustc_passes/src/hir_stats.rs | 2 +- compiler/rustc_resolve/src/late.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + src/librustdoc/clean/types.rs | 2 +- tests/crashes/125249.rs | 2 +- .../bad-inputs-and-output.rs | 4 +-- .../bad-inputs-and-output.stderr | 12 ++++---- .../return-type-notation/basic.rs | 2 +- .../return-type-notation/equality.rs | 2 +- .../return-type-notation/equality.stderr | 4 +-- .../issue-120208-higher-ranked-const.rs | 2 +- .../issue-120208-higher-ranked-const.stderr | 4 +-- .../return-type-notation/missing.rs | 2 +- .../return-type-notation/missing.stderr | 2 +- .../return-type-notation/non-rpitit.rs | 2 +- .../return-type-notation/non-rpitit.stderr | 4 +-- .../issue-110963-early.rs | 2 +- .../return-type-notation/issue-110963-late.rs | 2 +- ...ormalizing-self-auto-trait-issue-109924.rs | 2 +- .../rtn-implied-in-supertrait.rs | 2 +- .../rtn-in-impl-signature.rs | 2 +- .../rtn-in-impl-signature.stderr | 12 ++++---- .../super-method-bound-ambig.rs | 2 +- .../super-method-bound-ambig.stderr | 4 +-- .../super-method-bound.rs | 2 +- .../return-type-notation/supertrait-bound.rs | 2 +- .../return-type-notation/ty-or-ct-params.rs | 2 +- .../ty-or-ct-params.stderr | 10 +++---- .../ui/borrowck/alias-liveness/rtn-static.rs | 4 +-- ...ature-gate-return_type_notation.cfg.stderr | 28 +++---------------- ...eature-gate-return_type_notation.no.stderr | 13 ++++----- .../feature-gate-return_type_notation.rs | 12 ++------ 47 files changed, 109 insertions(+), 163 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f5e79c04d784f..dbbc4980050de 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -176,6 +176,8 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), + /// `(..)` in return type notation + ParenthesizedElided(Span), } impl GenericArgs { @@ -187,6 +189,7 @@ impl GenericArgs { match self { AngleBracketed(data) => data.span, Parenthesized(data) => data.span, + ParenthesizedElided(span) => *span, } } } @@ -2051,7 +2054,7 @@ impl UintTy { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Clone, Encodable, Decodable, Debug)] pub struct AssocItemConstraint { pub id: NodeId, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 27e781a5a6385..f816375b912d6 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -582,6 +582,7 @@ fn noop_visit_generic_args(generic_args: &mut GenericArgs, vis: & match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), + GenericArgs::ParenthesizedElided(span) => vis.visit_span(span), } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 4b2544ac47ed8..ed64f44f726fc 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -234,6 +234,6 @@ fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> { ast::FnRetTy::Default(_) => None, ast::FnRetTy::Ty(ret) => Some(ret), }, - ast::GenericArgs::AngleBracketed(_) => None, + ast::GenericArgs::AngleBracketed(_) | ast::GenericArgs::ParenthesizedElided(_) => None, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 26cb04d4d47fc..f6929057bed13 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -609,6 +609,7 @@ where walk_list!(visitor, visit_ty, inputs); try_visit!(visitor.visit_fn_ret_ty(output)); } + GenericArgs::ParenthesizedElided(_span) => {} } V::Result::output() } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 58f65f1257fc7..d6eb344fd1dbb 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -36,6 +36,9 @@ ast_lowering_bad_return_type_notation_inputs = argument types not allowed with return type notation .suggestion = remove the input types +ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..` + .suggestion = add `..` + ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 3d4b6a1f033fb..6699c6e75f5ea 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -393,6 +393,12 @@ pub enum BadReturnTypeNotation { #[suggestion(code = "", applicability = "maybe-incorrect")] span: Span, }, + #[diag(ast_lowering_bad_return_type_notation_needs_dots)] + NeedsDots { + #[primary_span] + #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0a06304fcecfa..92fb5b3c2eb90 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -979,20 +979,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0 } GenericArgs::Parenthesized(data) => { - if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) { - let parenthesized = if self.tcx.features().return_type_notation { - hir::GenericArgsParentheses::ReturnTypeNotation - } else { - self.emit_bad_parenthesized_trait_in_assoc_ty(data); - hir::GenericArgsParentheses::No - }; - GenericArgsCtor { - args: Default::default(), - constraints: &[], - parenthesized, - span: data.inputs_span, - } - } else if let Some(first_char) = constraint.ident.as_str().chars().next() + if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { let mut err = if !data.inputs.is_empty() { @@ -1004,7 +991,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span.shrink_to_hi().to(ty.span), }) } else { - unreachable!("inputs are empty and return type is not provided") + self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + }) }; if !self.tcx.features().return_type_notation && self.tcx.sess.is_nightly_build() @@ -1034,6 +1023,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .0 } } + GenericArgs::ParenthesizedElided(span) => GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: *span, + }, }; gen_args_ctor.into_generic_args(self) } else { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 9d38e1e678471..1efa5bd3c4c6f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -276,6 +276,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } }, + GenericArgs::ParenthesizedElided(_span) => { + todo!() + } } } else { ( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba4b6130b60c8..c0e8c4bf97789 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1289,6 +1289,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_impl_trait(None, |this| this.visit_ty(ty)); } } + GenericArgs::ParenthesizedElided(_span) => {} } } @@ -1445,7 +1446,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { span: args.span, }); } - None => {} + Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {} } } } @@ -1693,7 +1694,9 @@ fn deny_equality_constraints( // Add `` to `Foo`. match &mut assoc_path.segments[len].args { Some(args) => match args.deref_mut() { - GenericArgs::Parenthesized(_) => continue, + GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => { + continue; + } GenericArgs::AngleBracketed(args) => { args.args.push(arg); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e1c1a027a30a7..9cf3182daea59 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{attr, AssocItemConstraint, AssocItemConstraintKind, NodeId}; +use rustc_ast::{attr, NodeId}; use rustc_ast::{token, PatKind}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; @@ -445,23 +445,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind) } - fn visit_assoc_item_constraint(&mut self, constraint: &'a AssocItemConstraint) { - if let AssocItemConstraintKind::Bound { .. } = constraint.kind - && let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref() - && args.inputs.is_empty() - && let ast::FnRetTy::Default(..) = args.output - { - gate!( - &self, - return_type_notation, - constraint.span, - "return type notation is experimental" - ); - } - - visit::walk_assoc_item_constraint(self, constraint) - } - fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match &i.kind { ast::AssocItemKind::Fn(_) => true, @@ -566,6 +549,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { unsafe_extern_blocks, "`unsafe extern {}` blocks and `safe` keyword are experimental" ); + gate_all!(return_type_notation, "return type notation is experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { @@ -611,10 +595,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); - // Despite being a new feature, `where T: Trait`, which is RTN syntax now, - // used to be gated under associated_type_bounds, which are right above, so RTN needs to - // be too. - gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental"); gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental"); gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable"); gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0225c95dca8e3..0568d368d8c4c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1060,6 +1060,11 @@ impl<'a> PrintState<'a> for State<'a> { self.word(")"); self.print_fn_ret_ty(&data.output); } + ast::GenericArgs::ParenthesizedElided(_) => { + self.word("("); + self.word(".."); + self.word(")"); + } } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 22a6c06bba323..5b126d37ed645 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2413,7 +2413,7 @@ pub enum ImplItemKind<'hir> { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct AssocItemConstraint<'hir> { pub hir_id: HirId, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f08efe60d96b8..e4c75ac11454a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -45,10 +45,6 @@ parse_bad_assoc_type_bounds = bounds on associated types do not belong here parse_bad_item_kind = {$descr} is not supported in {$ctx} .help = consider moving the {$descr} out to a nearby module scope -parse_bad_return_type_notation_dotdot = - return type notation uses `()` instead of `(..)` for elided arguments - .suggestion = remove the `..` - parse_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8d49887f16441..6894f470d88fd 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2567,14 +2567,6 @@ pub(crate) struct BadReturnTypeNotationOutput { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_bad_return_type_notation_dotdot)] -pub(crate) struct BadReturnTypeNotationDotDot { - #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_bad_assoc_type_bounds)] pub(crate) struct BadAssocTypeBounds { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index da8d1194325b4..03c647dd5278e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -353,18 +353,17 @@ impl<'a> Parser<'a> { })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() - } else if self.may_recover() - && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) // FIXME(return_type_notation): Could also recover `...` here. && self.look_ahead(1, |tok| tok.kind == token::DotDot) { - self.bump(); - self.dcx() - .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span }); - self.bump(); + self.bump(); // ( + self.bump(); // .. self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::return_type_notation, span); + if self.eat_noexpect(&token::RArrow) { let lo = self.prev_token.span; let ty = self.parse_ty()?; @@ -372,13 +371,7 @@ impl<'a> Parser<'a> { .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); } - ParenthesizedArgs { - span, - inputs: ThinVec::new(), - inputs_span: span, - output: ast::FnRetTy::Default(self.prev_token.span.shrink_to_hi()), - } - .into() + P(ast::GenericArgs::ParenthesizedElided(span)) } else { // `(T, U) -> R` @@ -733,14 +726,6 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); - if let AssocItemConstraintKind::Bound { .. } = kind - && let Some(ast::GenericArgs::Parenthesized(args)) = &gen_args - && args.inputs.is_empty() - && let ast::FnRetTy::Default(..) = args.output - { - self.psess.gated_spans.gate(sym::return_type_notation, span); - } - let constraint = AssocItemConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; Ok(Some(AngleBracketedArg::Constraint(constraint))) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 0ba61f8e8b40f..0720efebf9721 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -695,7 +695,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) { record_variants!( (self, g, g, Id::None, ast, GenericArgs, GenericArgs), - [AngleBracketed, Parenthesized] + [AngleBracketed, Parenthesized, ParenthesizedElided] ); ast_visit::walk_generic_args(self, g) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 66a1c05289b7d..ad4e222f4deda 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1221,6 +1221,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } } } + GenericArgs::ParenthesizedElided(_) => {} } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 94cdce1025fe5..38963ef4ef092 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -350,6 +350,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { (args.span, found_lifetimes) } GenericArgs::Parenthesized(args) => (args.span, true), + GenericArgs::ParenthesizedElided(span) => (*span, true), } } else { (DUMMY_SP, false) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c4020f2a450bc..ddc3dd4270f7f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2557,7 +2557,7 @@ pub(crate) struct ProcMacro { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct AssocItemConstraint { pub(crate) assoc: PathSegment, diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs index 18196d7b34fe8..1cf6338a0d622 100644 --- a/tests/crashes/125249.rs +++ b/tests/crashes/125249.rs @@ -2,7 +2,7 @@ #![feature(return_position_impl_trait_in_trait, return_type_notation)] trait IntFactory { - fn stream(&self) -> impl IntFactory + Send>; + fn stream(&self) -> impl IntFactory + Send>; } pub fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index c23eff79ce2e5..a8c8a85c5aa68 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -13,7 +13,7 @@ fn foo>() {} fn bar (): Send>>() {} //~^ ERROR return type not allowed with return type notation -fn baz>() {} -//~^ ERROR return type notation uses `()` instead of `(..)` for elided arguments +fn baz>() {} +//~^ ERROR return type notation arguments must be elided with `..` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index d95249efe4049..7e1695984f1c3 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,9 +1,3 @@ -error: return type notation uses `()` instead of `(..)` for elided arguments - --> $DIR/bad-inputs-and-output.rs:16:24 - | -LL | fn baz>() {} - | ^^ help: remove the `..` - warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | @@ -25,5 +19,11 @@ error: return type not allowed with return type notation LL | fn bar (): Send>>() {} | ^^^^^^ help: remove the return type +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:16:23 + | +LL | fn baz>() {} + | ^^ help: add `..`: `(..)` + error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index 9755fd01c9764..be489a19a7ad2 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -17,7 +17,7 @@ async fn foo() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo, + #[cfg(with)] T: Foo, #[cfg(without)] T: Foo, >() { is_send(foo::()); diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index ae38dce1818c9..95c16fa1e3f84 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -9,7 +9,7 @@ trait Trait { async fn method() {} } -fn test>>>() {} +fn test>>>() {} //~^ ERROR return type notation is not allowed to use type equality fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index d432e95773541..d76b1bd1c0510 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -10,8 +10,8 @@ LL | #![feature(return_type_notation)] error: return type notation is not allowed to use type equality --> $DIR/equality.rs:12:18 | -LL | fn test>>>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn test>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs index 11728b879900e..4d026b7d1d859 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs @@ -9,7 +9,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, //~^ ERROR return type notation is not allowed for functions that have const parameters { } diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr index 8a3f037d00321..12f32a75eda32 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr @@ -13,8 +13,8 @@ error: return type notation is not allowed for functions that have const paramet LL | async fn check() -> bool; | -------------- const parameter declared here ... -LL | HC: HealthCheck + Send + 'static, - | ^^^^^^^^^^^^^ +LL | HC: HealthCheck + Send + 'static, + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index 9a8b77d00b714..3a04a56339ba5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -7,7 +7,7 @@ trait Trait { async fn method() {} } -fn bar>() {} +fn bar>() {} //~^ ERROR associated function `methid` not found for `Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index db9cb9f49a305..5cb8e2642f51c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -10,7 +10,7 @@ LL | #![feature(return_type_notation)] error[E0220]: associated function `methid` not found for `Trait` --> $DIR/missing.rs:10:17 | -LL | fn bar>() {} +LL | fn bar>() {} | ^^^^^^ help: there is an associated function with a similar name: `method` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index db5f6fe389ea7..d283c6eab370d 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,7 @@ trait Trait { fn method() {} } -fn test>() {} +fn test>() {} //~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 3e307c5f42ca4..79ced3c96ed5c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -13,8 +13,8 @@ error: return type notation used on function that is not `async` and does not re LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^ +LL | fn test>() {} + | ^^^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 4090912f528c4..46b8fbf6f86e3 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -9,7 +9,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, { spawn(async move { let mut hc = hc; diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index e0e59b6c6adb2..cb9c0b97f1e99 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -10,7 +10,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, { spawn(async move { let mut hc = hc; 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 index bee9ad2516ee2..24041ed080752 100644 --- 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 @@ -16,7 +16,7 @@ impl Foo for Bar { async fn bar(&self) {} } -fn build(_: T) where T: Foo {} +fn build(_: T) where T: Foo {} fn main() { build(Bar); diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs index 365ca57400652..2f6e04c385384 100644 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs @@ -16,7 +16,7 @@ trait Foo { async fn bar(&self) -> i32; } -trait SendFoo: Foo + Send {} +trait SendFoo: Foo + Send {} fn foobar(foo: impl SendFoo) -> JoinHandle { spawn(async move { diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs index 637678692bd1f..1e971d0aea71d 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs @@ -7,7 +7,7 @@ trait Super1<'a> { fn bar<'b>() -> bool; } -impl Super1<'_, bar(): Send> for () {} +impl Super1<'_, bar(..): Send> for () {} //~^ ERROR associated item constraints are not allowed here //~| ERROR not all trait items implemented diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index 54960ae60bcca..b23dbc37a55cc 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -10,13 +10,13 @@ LL | #![feature(return_type_notation)] error[E0229]: associated item constraints are not allowed here --> $DIR/rtn-in-impl-signature.rs:10:17 | -LL | impl Super1<'_, bar(): Send> for () {} - | ^^^^^^^^^^^ associated item constraint not allowed here +LL | impl Super1<'_, bar(..): Send> for () {} + | ^^^^^^^^^^^^^ associated item constraint not allowed here | help: consider removing this associated item constraint | -LL | impl Super1<'_, bar(): Send> for () {} - | ~~~~~~~~~~~~~ +LL | impl Super1<'_, bar(..): Send> for () {} + | ~~~~~~~~~~~~~~~ error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/rtn-in-impl-signature.rs:10:1 @@ -24,8 +24,8 @@ error[E0046]: not all trait items implemented, missing: `bar` LL | fn bar<'b>() -> bool; | --------------------- `bar` from trait ... -LL | impl Super1<'_, bar(): Send> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation +LL | impl Super1<'_, bar(..): Send> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs index fa647ea0bc781..452568f3e4695 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs @@ -22,7 +22,7 @@ impl Foo for () {} fn test() where - T: Foo, + T: Foo, //~^ ERROR ambiguous associated function `test` in bounds of `Foo` { } diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr index 4003aad6d03c3..9a6fdd7f2ac6b 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr @@ -16,8 +16,8 @@ LL | async fn test(); LL | async fn test(); | ---------------- ambiguous `test` from `Super2` ... -LL | T: Foo, - | ^^^^^^^^^^^^ ambiguous associated function `test` +LL | T: Foo, + | ^^^^^^^^^^^^^^ ambiguous associated function `test` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index ad7ed5b283cf1..1aa8258a09b7d 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -16,7 +16,7 @@ impl Foo for () {} fn test() where - T: Foo, + T: Foo, { } diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index adb286a21d216..9c74c10b33319 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -6,6 +6,6 @@ trait IntFactory { fn stream(&self) -> impl Iterator; } -trait SendIntFactory: IntFactory + Send {} +trait SendIntFactory: IntFactory + Send {} fn main() {} diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 328cd8d2ad02e..06a966df4451a 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -11,7 +11,7 @@ trait Foo { fn test() where - T: Foo, + T: Foo, //~^ ERROR return type notation is not allowed for functions that have const parameters //~| ERROR return type notation is not allowed for functions that have type parameters { diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr index da94d9d1e6da4..1c000bc6c3318 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr @@ -13,17 +13,17 @@ error: return type notation is not allowed for functions that have type paramete LL | async fn bar() {} | - type parameter declared here ... -LL | T: Foo, - | ^^^^^^^^^^^ +LL | T: Foo, + | ^^^^^^^^^^^^^ error: return type notation is not allowed for functions that have const parameters - --> $DIR/ty-or-ct-params.rs:14:25 + --> $DIR/ty-or-ct-params.rs:14:27 | LL | async fn baz() {} | -------------- const parameter declared here ... -LL | T: Foo, - | ^^^^^^^^^^^ +LL | T: Foo, + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/borrowck/alias-liveness/rtn-static.rs b/tests/ui/borrowck/alias-liveness/rtn-static.rs index 37f634a8e23cd..6aa5d8fc7a107 100644 --- a/tests/ui/borrowck/alias-liveness/rtn-static.rs +++ b/tests/ui/borrowck/alias-liveness/rtn-static.rs @@ -7,7 +7,7 @@ trait Foo { fn borrow(&mut self) -> impl Sized + '_; } -fn live_past_borrow>(mut t: T) { +fn live_past_borrow>(mut t: T) { let x = t.borrow(); drop(t); drop(x); @@ -15,7 +15,7 @@ fn live_past_borrow>(mut t: T) { // Test that the `'_` item bound in `borrow` does not cause us to // overlook the `'static` RTN bound. -fn overlapping_mut>(mut t: T) { +fn overlapping_mut>(mut t: T) { let x = t.borrow(); let x = t.borrow(); } diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index 41bd66b13e70d..18f46928fab54 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -1,33 +1,13 @@ error[E0658]: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:14:17 + --> $DIR/feature-gate-return_type_notation.rs:10:18 | -LL | fn foo>() {} - | ^^^^^^^^^ +LL | fn foo>() {} + | ^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/feature-gate-return_type_notation.rs:14:17 - | -LL | fn foo>() {} - | ^-- - | | - | help: remove these parentheses - -error: expected type, found function - --> $DIR/feature-gate-return_type_notation.rs:14:17 - | -LL | fn foo>() {} - | ^ unexpected function - | -note: the associated function is defined here - --> $DIR/feature-gate-return_type_notation.rs:10:5 - | -LL | async fn m(); - | ^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr index 79c626cef35dc..18f46928fab54 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr @@ -1,14 +1,13 @@ -warning: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:14:17 +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:10:18 | -LL | fn foo>() {} - | ^^^^^^^^^ +LL | fn foo>() {} + | ^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = warning: unstable syntax can change at any point in the future, causing a hard error! - = note: for more information, see issue #65860 -warning: 1 warning emitted +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index 7ae6cd0234be3..254b794e431e9 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,21 +1,13 @@ //@ edition: 2021 //@ revisions: cfg no -//@ [no] check-pass -// Since we're not adding new syntax, `cfg`'d out RTN must pass. - - trait Trait { #[allow(async_fn_in_trait)] async fn m(); } #[cfg(cfg)] -fn foo>() {} -//[cfg]~^ ERROR return type notation is experimental -//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints -//[cfg]~| ERROR expected type, found function -//[no]~^^^^ WARN return type notation is experimental -//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error! +fn foo>() {} +//~^ ERROR return type notation is experimental fn main() {} From 82b4af7511a430e53d2ed554771754552e5ecca8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 14:10:32 -0400 Subject: [PATCH 017/189] Make sure we deny unimplemented RTN on qpath segments --- compiler/rustc_ast_lowering/messages.ftl | 2 + compiler/rustc_ast_lowering/src/errors.rs | 5 ++ compiler/rustc_ast_lowering/src/path.rs | 16 ++++- .../return-type-notation/bare-path.rs | 26 ++++++++ .../return-type-notation/bare-path.stderr | 66 +++++++++++++++++++ 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bare-path.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index d6eb344fd1dbb..9ed93d481e773 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -43,6 +43,8 @@ ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type +ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet + ast_lowering_base_expression_double_dot = base expression required after `..` .suggestion = add a base expression here diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6699c6e75f5ea..4c77892a6b753 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -399,6 +399,11 @@ pub enum BadReturnTypeNotation { #[suggestion(code = "(..)", applicability = "maybe-incorrect")] span: Span, }, + #[diag(ast_lowering_bad_return_type_notation_position)] + Position { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 1efa5bd3c4c6f..c6c08649374dd 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,7 +1,8 @@ use crate::ImplTraitPosition; use super::errors::{ - AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets, + AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, + GenericTypeWithParentheses, UseAngleBrackets, }; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; @@ -276,8 +277,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } }, - GenericArgs::ParenthesizedElided(_span) => { - todo!() + GenericArgs::ParenthesizedElided(span) => { + self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + ( + GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: *span, + }, + false, + ) } } } else { diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs new file mode 100644 index 0000000000000..f507d82afec2f --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs @@ -0,0 +1,26 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Tr { + const CONST: usize; + + fn method() -> impl Sized; +} + +fn foo() +where + T::method(..): Send, + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected type, found function + ::method(..): Send, + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected associated type, found associated function `Tr::method` +{ + let _ = T::CONST::(..); + //~^ ERROR return type notation not allowed in this position yet + let _: T::method(..); + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected type, found function +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr new file mode 100644 index 0000000000000..cb45de59c7e23 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr @@ -0,0 +1,66 @@ +error[E0575]: expected associated type, found associated function `Tr::method` + --> $DIR/bare-path.rs:15:5 + | +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^ not a associated type + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bare-path.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:19:23 + | +LL | let _ = T::CONST::(..); + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:21:21 + | +LL | let _: T::method(..); + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:12:14 + | +LL | T::method(..): Send, + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:15:22 + | +LL | ::method(..): Send, + | ^^^^ + +error: expected type, found function + --> $DIR/bare-path.rs:12:8 + | +LL | T::method(..): Send, + | ^^^^^^ unexpected function + | +note: the associated function is defined here + --> $DIR/bare-path.rs:7:5 + | +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected type, found function + --> $DIR/bare-path.rs:21:15 + | +LL | let _: T::method(..); + | ^^^^^^ unexpected function + | +note: the associated function is defined here + --> $DIR/bare-path.rs:7:5 + | +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0575`. From 99365a5a7ace1092852784c2fa71b7fd5ef25e5d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 14:18:36 -0400 Subject: [PATCH 018/189] Implement RTN support in rustfmt --- src/tools/rustfmt/src/types.rs | 34 +++++++++++-------- .../tests/target/return-type-notation.rs | 10 ++++++ 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 src/tools/rustfmt/tests/target/return-type-notation.rs diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index c0bf9482b1143..c826547e9d001 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -484,21 +484,25 @@ fn rewrite_generic_args( span: Span, ) -> Option { match gen_args { - ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => { - let args = data - .args - .iter() - .map(|x| match x { - ast::AngleBracketedArg::Arg(generic_arg) => { - SegmentParam::from_generic_arg(generic_arg) - } - ast::AngleBracketedArg::Constraint(constraint) => { - SegmentParam::Binding(constraint) - } - }) - .collect::>(); + ast::GenericArgs::AngleBracketed(ref data) => { + if data.args.is_empty() { + Some("".to_owned()) + } else { + let args = data + .args + .iter() + .map(|x| match x { + ast::AngleBracketedArg::Arg(generic_arg) => { + SegmentParam::from_generic_arg(generic_arg) + } + ast::AngleBracketedArg::Constraint(constraint) => { + SegmentParam::Binding(constraint) + } + }) + .collect::>(); - overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span) + overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span) + } } ast::GenericArgs::Parenthesized(ref data) => format_function_type( data.inputs.iter().map(|x| &**x), @@ -508,7 +512,7 @@ fn rewrite_generic_args( context, shape, ), - _ => Some("".to_owned()), + ast::GenericArgs::ParenthesizedElided(..) => Some("(..)".to_owned()), } } diff --git a/src/tools/rustfmt/tests/target/return-type-notation.rs b/src/tools/rustfmt/tests/target/return-type-notation.rs new file mode 100644 index 0000000000000..0f26e7e272b8b --- /dev/null +++ b/src/tools/rustfmt/tests/target/return-type-notation.rs @@ -0,0 +1,10 @@ +fn rtn() +where + T: Trait, + T::method(..): Send + 'static, +{ +} + +fn test() { + let x: T::method(..); +} From cf6f6ca441e2efd3e196f45f36da253c49cec4c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2024 12:02:44 +0200 Subject: [PATCH 019/189] unreferenced-used-static: run test everywhere --- .../linkage-attr/unreferenced-used-static-issue-127052.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs index aa8236b74315c..0d34bf988efe6 100644 --- a/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs +++ b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs @@ -1,9 +1,10 @@ -// This is a non-regression test for issue #127052 where unreferenced `#[used]` statics couldn't be -// removed by the MSVC linker, causing linking errors. +// This is a non-regression test for issue #127052 where unreferenced `#[used]` statics in the +// binary crate would be marked as "exported", but not be present in the binary, causing linking +// errors with the MSVC linker. //@ build-pass: needs linking -//@ only-msvc #[used] static FOO: u32 = 0; + fn main() {} From c54a2a53f83d9eb4fec161ecc304164d0303fbfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Jun 2024 19:03:47 +0200 Subject: [PATCH 020/189] Make mtime of reproducible tarball dependent on git commit --- src/bootstrap/src/utils/tarball.rs | 26 ++++++++++++++++++++++- src/tools/rust-installer/src/tarballer.rs | 18 ++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 5cc319826dbf3..3c15bb296f39a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -9,9 +9,9 @@ use std::path::{Path, PathBuf}; use crate::core::builder::Builder; use crate::core::{build_steps::dist::distdir, builder::Kind}; -use crate::utils::channel; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{move_file, t}; +use crate::utils::{channel, helpers}; #[derive(Copy, Clone)] pub(crate) enum OverlayKind { @@ -351,6 +351,30 @@ impl<'a> Tarball<'a> { }; cmd.args(["--compression-profile", compression_profile]); + + // We want to use a pinned modification time for files in the archive + // to achieve better reproducibility. However, using the same mtime for all + // releases is not ideal, because it can break e.g. Cargo mtime checking + // (https://github.com/rust-lang/rust/issues/125578). + // Therefore, we set mtime to the date of the latest commit (if we're managed + // by git). In this way, the archive will still be always the same for a given commit + // (achieving reproducibility), but it will also change between different commits and + // Rust versions, so that it won't break mtime-based caches. + // + // Note that this only overrides the mtime of files, not directories, due to the + // limitations of the tarballer tool. Directories will have their mtime set to 2006. + + // Get the UTC timestamp of the last git commit, if we're under git. + // We need to use UTC, so that anyone who tries to rebuild from the same commit + // gets the same timestamp. + if self.builder.rust_info().is_managed_git_subrepository() { + // %ct means committer date + let timestamp = helpers::output( + helpers::git(Some(&self.builder.src)).arg("log").arg("-1").arg("--format=%ct"), + ); + cmd.args(["--override-file-mtime", timestamp.trim()]); + } + self.builder.run(cmd); // Ensure there are no symbolic links in the tarball. In particular, diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index 2f093e7ad17fd..b5e87a66ffc39 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -32,6 +32,12 @@ actor! { /// The formats used to compress the tarball. #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -65,6 +71,8 @@ impl Tarballer { let buf = BufWriter::with_capacity(1024 * 1024, encoder); let mut builder = Builder::new(buf); // Make uid, gid and mtime deterministic to improve reproducibility + // The modification time of directories will be set to the date of the first Rust commit. + // The modification time of files will be set to `override_file_mtime` (see `append_path`). builder.mode(HeaderMode::Deterministic); let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap(); @@ -77,7 +85,7 @@ impl Tarballer { } for path in files { let src = Path::new(&self.work_dir).join(&path); - append_path(&mut builder, &src, &path) + append_path(&mut builder, &src, &path, self.override_file_mtime) .with_context(|| format!("failed to tar file '{}'", src.display()))?; } builder @@ -93,10 +101,16 @@ impl Tarballer { } } -fn append_path(builder: &mut Builder, src: &Path, path: &String) -> Result<()> { +fn append_path( + builder: &mut Builder, + src: &Path, + path: &String, + override_file_mtime: u64, +) -> Result<()> { let stat = symlink_metadata(src)?; let mut header = Header::new_gnu(); header.set_metadata_in_mode(&stat, HeaderMode::Deterministic); + header.set_mtime(override_file_mtime); if stat.file_type().is_symlink() { let link = read_link(src)?; From e1999f9a0815c891d71588045b96a76e8e2c45a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 29 Jun 2024 23:30:57 +0200 Subject: [PATCH 021/189] Add support for mtime override to `generate` and `combine` rust-installer commands --- src/tools/rust-installer/src/combiner.rs | 9 ++++++++- src/tools/rust-installer/src/generator.rs | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index 565d19d863f64..c211b34850a07 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -55,6 +55,12 @@ actor! { /// The formats used to compress the tarball #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -145,7 +151,8 @@ impl Combiner { .input(self.package_name) .output(path_to_str(&output)?.into()) .compression_profile(self.compression_profile) - .compression_formats(self.compression_formats); + .compression_formats(self.compression_formats) + .override_file_mtime(self.override_file_mtime); tarballer.run()?; Ok(()) diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs index b101e67d8df7f..035a394deebe6 100644 --- a/src/tools/rust-installer/src/generator.rs +++ b/src/tools/rust-installer/src/generator.rs @@ -61,6 +61,12 @@ actor! { /// The formats used to compress the tarball #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -114,7 +120,8 @@ impl Generator { .input(self.package_name) .output(path_to_str(&output)?.into()) .compression_profile(self.compression_profile) - .compression_formats(self.compression_formats); + .compression_formats(self.compression_formats) + .override_file_mtime(self.override_file_mtime); tarballer.run()?; Ok(()) From 294436d27371d77967c77d93e31a34362f7c3cd0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 15:25:14 -0400 Subject: [PATCH 022/189] Make all tests in async dir build-pass, adjust implements-fnmut test to begin ICEing during codegen --- .../async-closures/constrained-but-no-upvars-yet.rs | 2 +- .../force-move-due-to-actually-fnonce.rs | 2 +- .../async-closures/force-move-due-to-inferred-kind.rs | 2 +- .../ui/async-await/async-closures/implements-fnmut.rs | 10 +++++++--- .../async-await/async-closures/signature-deduction.rs | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs index a43906d01e538..3b222d00baeaf 100644 --- a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs +++ b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ check-pass +//@ build-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver diff --git a/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs b/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs index ce49f55e3e304..7244a29673b98 100644 --- a/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs +++ b/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs @@ -1,6 +1,6 @@ //@ aux-build:block-on.rs //@ edition:2021 -//@ check-pass +//@ build-pass #![feature(async_closure)] diff --git a/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs b/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs index 803c990ef93f1..7ce210a33c3e5 100644 --- a/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs +++ b/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs @@ -1,6 +1,6 @@ //@ aux-build:block-on.rs //@ edition:2021 -//@ check-pass +//@ build-pass #![feature(async_closure)] diff --git a/tests/ui/async-await/async-closures/implements-fnmut.rs b/tests/ui/async-await/async-closures/implements-fnmut.rs index 1ed326cd0618b..8e780ce9889ab 100644 --- a/tests/ui/async-await/async-closures/implements-fnmut.rs +++ b/tests/ui/async-await/async-closures/implements-fnmut.rs @@ -1,4 +1,4 @@ -//@ check-pass +//@ build-pass //@ edition: 2021 // Demonstrates that an async closure may implement `FnMut` (not just `async FnMut`!) @@ -9,9 +9,13 @@ #![feature(async_closure)] -fn main() {} +fn main() { + hello(&Ty); +} -fn needs_fn_mut(x: impl FnMut() -> T) {} +fn needs_fn_mut(mut x: impl FnMut() -> T) { + x(); +} fn hello(x: &Ty) { needs_fn_mut(async || { x.hello(); }); diff --git a/tests/ui/async-await/async-closures/signature-deduction.rs b/tests/ui/async-await/async-closures/signature-deduction.rs index 031dab1029658..856f3963ee6a9 100644 --- a/tests/ui/async-await/async-closures/signature-deduction.rs +++ b/tests/ui/async-await/async-closures/signature-deduction.rs @@ -1,4 +1,4 @@ -//@ check-pass +//@ build-pass //@ edition: 2021 #![feature(async_closure)] From 90143b0be814ea70303906a81d8329b5b655c437 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 17:25:44 -0400 Subject: [PATCH 023/189] Fix FnMut/Fn shim for coroutine-closures that capture references --- compiler/rustc_codegen_ssa/src/mir/locals.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 49 ++++++++++++------- compiler/rustc_symbol_mangling/src/legacy.rs | 10 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 11 ++++- compiler/rustc_ty_utils/src/abi.rs | 4 +- src/tools/miri/tests/pass/async-closure.rs | 21 +++++--- .../miri/tests/pass/async-closure.stdout | 6 ++- ...ure#0}.coroutine_by_move.0.panic-abort.mir | 2 +- ...re#0}.coroutine_by_move.0.panic-unwind.mir | 2 +- ...oroutine_closure_by_move.0.panic-abort.mir | 6 +-- ...routine_closure_by_move.0.panic-unwind.mir | 6 +-- ...ure#0}.coroutine_by_move.0.panic-abort.mir | 47 ++++++++++++++++++ ...re#0}.coroutine_by_move.0.panic-unwind.mir | 47 ++++++++++++++++++ ...oroutine_closure_by_move.0.panic-abort.mir | 10 ++++ ...routine_closure_by_move.0.panic-unwind.mir | 10 ++++ ...coroutine_closure_by_ref.0.panic-abort.mir | 6 +-- ...oroutine_closure_by_ref.0.panic-unwind.mir | 6 +-- tests/mir-opt/async_closure_shims.rs | 20 +++++++- 18 files changed, 214 insertions(+), 51 deletions(-) create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir create mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs index a6c873e195eb1..5190021c005b4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/locals.rs +++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let expected_ty = self.monomorphize(self.mir.local_decls[local].ty); if expected_ty != op.layout.ty { warn!( - "Unexpected initial operand type: expected {expected_ty:?}, found {:?}.\ + "Unexpected initial operand type:\nexpected {expected_ty:?},\nfound {:?}.\n\ See .", op.layout.ty ); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 25577e88e2831..6835a39cf3624 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1,18 +1,17 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; - -use rustc_index::{Idx, IndexVec}; - use rustc_span::{source_map::Spanned, Span, DUMMY_SP}; +use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::Abi; +use std::assert_matches::assert_matches; use std::fmt; use std::iter; @@ -1020,21 +1019,19 @@ fn build_construct_coroutine_by_move_shim<'tcx>( receiver_by_ref: bool, ) -> Body<'tcx> { let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let mut self_local: Place<'tcx> = Local::from_usize(1).into(); let ty::CoroutineClosure(_, args) = *self_ty.kind() else { bug!(); }; - // We use `&mut Self` here because we only need to emit an ABI-compatible shim body, - // rather than match the signature exactly (which might take `&self` instead). + // We use `&Self` here because we only need to emit an ABI-compatible shim body, + // rather than match the signature exactly (which might take `&mut self` instead). // - // The self type here is a coroutine-closure, not a coroutine, and we never read from - // it because it never has any captures, because this is only true in the Fn/FnMut - // implementation, not the AsyncFn/AsyncFnMut implementation, which is implemented only - // if the coroutine-closure has no captures. + // We adjust the `self_local` to be a deref since we want to copy fields out of + // a reference to the closure. if receiver_by_ref { - // Triple-check that there's no captures here. - assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit); - self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty); + self_local = tcx.mk_place_deref(self_local); + self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty); } let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { @@ -1067,11 +1064,27 @@ fn build_construct_coroutine_by_move_shim<'tcx>( fields.push(Operand::Move(Local::from_usize(idx + 1).into())); } for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { - fields.push(Operand::Move(tcx.mk_place_field( - Local::from_usize(1).into(), - FieldIdx::from_usize(idx), - ty, - ))); + if receiver_by_ref { + // The only situation where it's possible is when we capture immuatable references, + // since those don't need to be reborrowed with the closure's env lifetime. Since + // references are always `Copy`, just emit a copy. + assert_matches!( + ty.kind(), + ty::Ref(_, _, hir::Mutability::Not), + "field should be captured by immutable ref if we have an `Fn` instance" + ); + fields.push(Operand::Copy(tcx.mk_place_field( + self_local, + FieldIdx::from_usize(idx), + ty, + ))); + } else { + fields.push(Operand::Move(tcx.mk_place_field( + self_local, + FieldIdx::from_usize(idx), + ty, + ))); + } } let source_info = SourceInfo::outermost(span); diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 9edd2ff9b1a53..5aa46cc0deae0 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -85,9 +85,13 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::CoroutineKindShim { .. } => { - printer.write_str("{{fn-once-shim}}").unwrap(); + ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } => { + printer + .write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" }) + .unwrap(); + } + ty::InstanceKind::CoroutineKindShim { .. } => { + printer.write_str("{{by-move-body-shim}}").unwrap(); } _ => {} } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 42c4fa83d1bf0..5f8029af02044 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -49,8 +49,15 @@ pub(super) fn mangle<'tcx>( ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), - ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::CoroutineKindShim { .. } => Some("fn_once"), + // FIXME(async_closures): This shouldn't be needed when we fix + // `Instance::ty`/`Instance::def_id`. + ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: true, .. } => { + Some("by_move") + } + ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: false, .. } => { + Some("by_ref") + } + ty::InstanceKind::CoroutineKindShim { .. } => Some("by_move_body"), _ => None, }; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f1dd94839fe1e..f078cfe1b2505 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -127,9 +127,9 @@ fn fn_sig_for_fn_abi<'tcx>( coroutine_kind = ty::ClosureKind::FnOnce; // Implementations of `FnMut` and `Fn` for coroutine-closures - // still take their receiver by (mut) ref. + // still take their receiver by ref. if receiver_by_ref { - Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty) + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty) } else { coroutine_ty } diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs index 2f7ec2b9e6f86..721af57888384 100644 --- a/src/tools/miri/tests/pass/async-closure.rs +++ b/src/tools/miri/tests/pass/async-closure.rs @@ -1,7 +1,8 @@ #![feature(async_closure, noop_waker, async_fn_traits)] +#![allow(unused)] use std::future::Future; -use std::ops::{AsyncFnMut, AsyncFnOnce}; +use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use std::pin::pin; use std::task::*; @@ -17,6 +18,10 @@ pub fn block_on(fut: impl Future) -> T { } } +async fn call(f: &mut impl AsyncFn(i32)) { + f(0).await; +} + async fn call_mut(f: &mut impl AsyncFnMut(i32)) { f(0).await; } @@ -26,10 +31,10 @@ async fn call_once(f: impl AsyncFnOnce(i32)) { } async fn call_normal>(f: &impl Fn(i32) -> F) { - f(0).await; + f(1).await; } -async fn call_normal_once>(f: impl FnOnce(i32) -> F) { +async fn call_normal_mut>(f: &mut impl FnMut(i32) -> F) { f(1).await; } @@ -39,14 +44,16 @@ pub fn main() { let mut async_closure = async move |a: i32| { println!("{a} {b}"); }; + call(&mut async_closure).await; call_mut(&mut async_closure).await; call_once(async_closure).await; - // No-capture closures implement `Fn`. - let async_closure = async move |a: i32| { - println!("{a}"); + let b = 2i32; + let mut async_closure = async |a: i32| { + println!("{a} {b}"); }; call_normal(&async_closure).await; - call_normal_once(async_closure).await; + call_normal_mut(&mut async_closure).await; + call_once(async_closure).await; }); } diff --git a/src/tools/miri/tests/pass/async-closure.stdout b/src/tools/miri/tests/pass/async-closure.stdout index 7baae1aa94f8d..217944c84a2d3 100644 --- a/src/tools/miri/tests/pass/async-closure.stdout +++ b/src/tools/miri/tests/pass/async-closure.stdout @@ -1,4 +1,6 @@ 0 2 +0 2 +1 2 +1 2 +1 2 1 2 -0 -1 diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir index 06028487d0178..1c34955a8d9da 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir index 06028487d0178..1c34955a8d9da 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir index 93447b1388dea..a984845fd2c11 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move -fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}; +fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:53:33: 53:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + _0 = {coroutine@$DIR/async_closure_shims.rs:53:53: 56:10 (#0)} { a: move _2, b: move (_1.0: i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir index 93447b1388dea..a984845fd2c11 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move -fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}; +fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:53:33: 53:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + _0 = {coroutine@$DIR/async_closure_shims.rs:53:53: 56:10 (#0)} { a: move _2, b: move (_1.0: i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..516908144a641 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..516908144a641 --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir @@ -0,0 +1,47 @@ +// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move + +fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug a => (_1.0: i32); + debug b => (*(_1.1: &i32)); + let mut _0: (); + let _3: i32; + scope 1 { + debug a => _3; + let _4: &i32; + scope 2 { + debug a => _4; + let _5: &i32; + scope 3 { + debug b => _5; + } + } + } + + bb0: { + StorageLive(_3); + _3 = (_1.0: i32); + FakeRead(ForLet(None), _3); + StorageLive(_4); + _4 = &_3; + FakeRead(ForLet(None), _4); + StorageLive(_5); + _5 = &(*(_1.1: &i32)); + FakeRead(ForLet(None), _5); + _0 = const (); + StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + drop(_1) -> [return: bb1, unwind: bb2]; + } + + bb1: { + return; + } + + bb2 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir new file mode 100644 index 0000000000000..aab9f7b03b9ab --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: move (_1.0: &i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir new file mode 100644 index 0000000000000..aab9f7b03b9ab --- /dev/null +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir @@ -0,0 +1,10 @@ +// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_move + +fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}; + + bb0: { + _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: move (_1.0: &i32) }; + return; + } +} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir index cab7bdb7e3cbf..ba20c28cd0147 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref -fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10}; +fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 }; + _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: ((*_1).0: &i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir index cab7bdb7e3cbf..ba20c28cd0147 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref -fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10}; +fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 }; + _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: ((*_1).0: &i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs index 7d226df686654..57c55ef055cd7 100644 --- a/tests/mir-opt/async_closure_shims.rs +++ b/tests/mir-opt/async_closure_shims.rs @@ -3,9 +3,10 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![feature(async_closure, noop_waker, async_fn_traits)] +#![allow(unused)] use std::future::Future; -use std::ops::{AsyncFnMut, AsyncFnOnce}; +use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use std::pin::pin; use std::task::*; @@ -21,6 +22,10 @@ pub fn block_on(fut: impl Future) -> T { } } +async fn call(f: &mut impl AsyncFn(i32)) { + f(0).await; +} + async fn call_mut(f: &mut impl AsyncFnMut(i32)) { f(0).await; } @@ -33,9 +38,15 @@ async fn call_normal>(f: &impl Fn(i32) -> F) { f(1).await; } +async fn call_normal_mut>(f: &mut impl FnMut(i32) -> F) { + f(1).await; +} + // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.mir +// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.mir pub fn main() { block_on(async { let b = 2i32; @@ -43,12 +54,17 @@ pub fn main() { let a = &a; let b = &b; }; + call(&mut async_closure).await; call_mut(&mut async_closure).await; call_once(async_closure).await; - let async_closure = async move |a: i32| { + let b = 2i32; + let mut async_closure = async |a: i32| { let a = &a; + let b = &b; }; call_normal(&async_closure).await; + call_normal_mut(&mut async_closure).await; + call_once(async_closure).await; }); } From 53db64168f7556bc57355a635b19e6b005e87876 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 22:35:17 -0400 Subject: [PATCH 024/189] Uplift fast rejection to new solver --- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 11 - compiler/rustc_middle/src/ty/fast_reject.rs | 368 +--------------- compiler/rustc_middle/src/ty/impls_ty.rs | 13 - .../src/solve/normalizes_to/mod.rs | 3 +- .../src/solve/trait_goals.rs | 4 +- .../src/traits/coherence.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 2 +- compiler/rustc_type_ir/src/fast_reject.rs | 397 ++++++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 8 + compiler/rustc_type_ir/src/interner.rs | 7 - compiler/rustc_type_ir/src/lib.rs | 1 + src/librustdoc/html/render/write_shared.rs | 3 +- 13 files changed, 419 insertions(+), 402 deletions(-) create mode 100644 compiler/rustc_type_ir/src/fast_reject.rs diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a385bc70e359b..57f0da195c71d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2129,7 +2129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let target_ty = self .autoderef(sugg_span, rcvr_ty) .find(|(rcvr_ty, _)| { - DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey } + DeepRejectCtxt::new(self.tcx, TreatParams::ForLookup) .types_may_unify(*rcvr_ty, impl_ty) }) .map_or(impl_ty, |(ty, _)| ty) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ed1ec55bc8ed1..7fd2f4c9105cc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -373,17 +373,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { .map(|assoc_item| assoc_item.def_id) } - fn args_may_unify_deep( - self, - obligation_args: ty::GenericArgsRef<'tcx>, - impl_args: ty::GenericArgsRef<'tcx>, - ) -> bool { - ty::fast_reject::DeepRejectCtxt { - treat_obligation_params: ty::fast_reject::TreatParams::ForLookup, - } - .args_may_unify(obligation_args, impl_args) - } - // This implementation is a bit different from `TyCtxt::for_each_relevant_impl`, // since we want to skip over blanket impls for non-rigid aliases, and also we // only want to consider types that *actually* unify with float/int vars. diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 923667e609be4..0413cfa5a63c5 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,369 +1,9 @@ -use crate::mir::Mutability; -use crate::ty::GenericArgKind; -use crate::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use std::fmt::Debug; -use std::hash::Hash; -use std::iter; -/// See `simplify_type`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -pub enum SimplifiedType { - Bool, - Char, - Int(ty::IntTy), - Uint(ty::UintTy), - Float(ty::FloatTy), - Adt(DefId), - Foreign(DefId), - Str, - Array, - Slice, - Ref(Mutability), - Ptr(Mutability), - Never, - Tuple(usize), - /// A trait object, all of whose components are markers - /// (e.g., `dyn Send + Sync`). - MarkerTraitObject, - Trait(DefId), - Closure(DefId), - Coroutine(DefId), - CoroutineWitness(DefId), - Function(usize), - Placeholder, - Error, -} +use super::TyCtxt; -/// Generic parameters are pretty much just bound variables, e.g. -/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as -/// `for<'a, T> fn(&'a T) -> u32`. -/// -/// Typecheck of `foo` has to succeed for all possible generic arguments, so -/// during typeck, we have to treat its generic parameters as if they -/// were placeholders. -/// -/// But when calling `foo` we only have to provide a specific generic argument. -/// In that case the generic parameters are instantiated with inference variables. -/// As we use `simplify_type` before that instantiation happens, we just treat -/// generic parameters as if they were inference variables in that case. -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum TreatParams { - /// Treat parameters as infer vars. This is the correct mode for caching - /// an impl's type for lookup. - AsCandidateKey, - /// Treat parameters as placeholders in the given environment. This is the - /// correct mode for *lookup*, as during candidate selection. - /// - /// This also treats projections with inference variables as infer vars - /// since they could be further normalized. - ForLookup, -} +pub use rustc_type_ir::fast_reject::*; -/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. -/// -/// **This function should only be used if you need to store or retrieve the type from some -/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt] -/// instead.** -/// -/// The idea is to get something simple that we can use to quickly decide if two types could unify, -/// for example during method lookup. If this function returns `Some(x)` it can only unify with -/// types for which this method returns either `Some(x)` as well or `None`. -/// -/// A special case here are parameters and projections, which are only injective -/// if they are treated as placeholders. -/// -/// For example when storing impls based on their simplified self type, we treat -/// generic parameters as if they were inference variables. We must not simplify them here, -/// as they can unify with any other type. -/// -/// With projections we have to be even more careful, as treating them as placeholders -/// is only correct if they are fully normalized. -/// -/// ¹ meaning that if the outermost layers are different, then the whole types are also different. -pub fn simplify_type<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - treat_params: TreatParams, -) -> Option { - match *ty.kind() { - ty::Bool => Some(SimplifiedType::Bool), - ty::Char => Some(SimplifiedType::Char), - ty::Int(int_type) => Some(SimplifiedType::Int(int_type)), - ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)), - ty::Float(float_type) => Some(SimplifiedType::Float(float_type)), - ty::Adt(def, _) => Some(SimplifiedType::Adt(def.did())), - ty::Str => Some(SimplifiedType::Str), - ty::Array(..) => Some(SimplifiedType::Array), - ty::Slice(..) => Some(SimplifiedType::Slice), - ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), - ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), - ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { - Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { - Some(SimplifiedType::Trait(principal_def_id)) - } - _ => Some(SimplifiedType::MarkerTraitObject), - }, - ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), - ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { - Some(SimplifiedType::Closure(def_id)) - } - ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)), - ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)), - ty::Never => Some(SimplifiedType::Never), - ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())), - ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), - ty::Placeholder(..) => Some(SimplifiedType::Placeholder), - ty::Param(_) => match treat_params { - TreatParams::ForLookup => Some(SimplifiedType::Placeholder), - TreatParams::AsCandidateKey => None, - }, - ty::Alias(..) => match treat_params { - // When treating `ty::Param` as a placeholder, projections also - // don't unify with anything else as long as they are fully normalized. - // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` - // when the new solver is enabled by default. - TreatParams::ForLookup if !ty.has_non_region_infer() => { - Some(SimplifiedType::Placeholder) - } - TreatParams::ForLookup | TreatParams::AsCandidateKey => None, - }, - ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), - ty::Error(_) => Some(SimplifiedType::Error), - ty::Bound(..) | ty::Infer(_) => None, - } -} +pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt>; -impl SimplifiedType { - pub fn def(self) -> Option { - match self { - SimplifiedType::Adt(d) - | SimplifiedType::Foreign(d) - | SimplifiedType::Trait(d) - | SimplifiedType::Closure(d) - | SimplifiedType::Coroutine(d) - | SimplifiedType::CoroutineWitness(d) => Some(d), - _ => None, - } - } -} - -/// Given generic arguments from an obligation and an impl, -/// could these two be unified after replacing parameters in the -/// the impl with inference variables. -/// -/// For obligations, parameters won't be replaced by inference -/// variables and only unify with themselves. We treat them -/// the same way we treat placeholders. -/// -/// We also use this function during coherence. For coherence the -/// impls only have to overlap for some value, so we treat parameters -/// on both sides like inference variables. This behavior is toggled -/// using the `treat_obligation_params` field. -#[derive(Debug, Clone, Copy)] -pub struct DeepRejectCtxt { - pub treat_obligation_params: TreatParams, -} - -impl DeepRejectCtxt { - pub fn args_may_unify<'tcx>( - self, - obligation_args: GenericArgsRef<'tcx>, - impl_args: GenericArgsRef<'tcx>, - ) -> bool { - iter::zip(obligation_args, impl_args).all(|(obl, imp)| { - match (obl.unpack(), imp.unpack()) { - // We don't fast reject based on regions. - (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, - (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { - self.types_may_unify(obl, imp) - } - (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { - self.consts_may_unify(obl, imp) - } - _ => bug!("kind mismatch: {obl} {imp}"), - } - }) - } - - pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool { - match impl_ty.kind() { - // Start by checking whether the type in the impl may unify with - // pretty much everything. Just return `true` in that case. - ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true, - // These types only unify with inference variables or their own - // variant. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(..) - | ty::Str - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Dynamic(..) - | ty::Pat(..) - | ty::Ref(..) - | ty::Never - | ty::Tuple(..) - | ty::FnPtr(..) - | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), - ty::FnDef(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), - } - - let k = impl_ty.kind(); - match *obligation_ty.kind() { - // Purely rigid types, use structural equivalence. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never - | ty::Foreign(_) => obligation_ty == impl_ty, - ty::Ref(_, obl_ty, obl_mutbl) => match k { - &ty::Ref(_, impl_ty, impl_mutbl) => { - obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) - } - _ => false, - }, - ty::Adt(obl_def, obl_args) => match k { - &ty::Adt(impl_def, impl_args) => { - obl_def == impl_def && self.args_may_unify(obl_args, impl_args) - } - _ => false, - }, - ty::Pat(obl_ty, _) => { - // FIXME(pattern_types): take pattern into account - matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) - } - ty::Slice(obl_ty) => { - matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) - } - ty::Array(obl_ty, obl_len) => match k { - &ty::Array(impl_ty, impl_len) => { - self.types_may_unify(obl_ty, impl_ty) - && self.consts_may_unify(obl_len, impl_len) - } - _ => false, - }, - ty::Tuple(obl) => match k { - &ty::Tuple(imp) => { - obl.len() == imp.len() - && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp)) - } - _ => false, - }, - ty::RawPtr(obl_ty, obl_mutbl) => match *k { - ty::RawPtr(imp_ty, imp_mutbl) => { - obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty) - } - _ => false, - }, - ty::Dynamic(obl_preds, ..) => { - // Ideally we would walk the existential predicates here or at least - // compare their length. But considering that the relevant `Relate` impl - // actually sorts and deduplicates these, that doesn't work. - matches!(k, ty::Dynamic(impl_preds, ..) if - obl_preds.principal_def_id() == impl_preds.principal_def_id() - ) - } - ty::FnPtr(obl_sig) => match k { - ty::FnPtr(impl_sig) => { - let ty::FnSig { inputs_and_output, c_variadic, safety, abi } = - obl_sig.skip_binder(); - let impl_sig = impl_sig.skip_binder(); - - abi == impl_sig.abi - && c_variadic == impl_sig.c_variadic - && safety == impl_sig.safety - && inputs_and_output.len() == impl_sig.inputs_and_output.len() - && iter::zip(inputs_and_output, impl_sig.inputs_and_output) - .all(|(obl, imp)| self.types_may_unify(obl, imp)) - } - _ => false, - }, - - // Impls cannot contain these types as these cannot be named directly. - ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false, - - // Placeholder types don't unify with anything on their own - ty::Placeholder(..) | ty::Bound(..) => false, - - // Depending on the value of `treat_obligation_params`, we either - // treat generic parameters like placeholders or like inference variables. - ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, - TreatParams::AsCandidateKey => true, - }, - - ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(), - - ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(), - - ty::Infer(_) => true, - - // As we're walking the whole type, it may encounter projections - // inside of binders and what not, so we're just going to assume that - // projections can unify with other stuff. - // - // Looking forward to lazy normalization this is the safer strategy anyways. - ty::Alias(..) => true, - - ty::Error(_) => true, - - ty::CoroutineWitness(..) => { - bug!("unexpected obligation type: {:?}", obligation_ty) - } - } - } - - pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool { - let impl_val = match impl_ct.kind() { - ty::ConstKind::Expr(_) - | ty::ConstKind::Param(_) - | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Error(_) => { - return true; - } - ty::ConstKind::Value(_, impl_val) => impl_val, - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - bug!("unexpected impl arg: {:?}", impl_ct) - } - }; - - match obligation_ct.kind() { - ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, - TreatParams::AsCandidateKey => true, - }, - - // Placeholder consts don't unify with anything on their own - ty::ConstKind::Placeholder(_) => false, - - // As we don't necessarily eagerly evaluate constants, - // they might unify with any value. - ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { - true - } - ty::ConstKind::Value(_, obl_val) => obl_val == impl_val, - - ty::ConstKind::Infer(_) => true, - - ty::ConstKind::Bound(..) => { - bug!("unexpected obl const: {:?}", obligation_ct) - } - } - } -} +pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType; diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index efcf428c2136f..9be7370a1c21c 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -4,7 +4,6 @@ use crate::middle::region; use crate::mir; use crate::ty; -use crate::ty::fast_reject::SimplifiedType; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::HashingControls; @@ -57,18 +56,6 @@ where } } -impl<'a> ToStableHashKey> for SimplifiedType { - type KeyType = Fingerprint; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { - let mut hasher = StableHasher::new(); - let mut hcx: StableHashingContext<'a> = hcx.clone(); - self.hash_stable(&mut hcx, &mut hasher); - hasher.finish() - } -} - impl<'a, 'tcx> HashStable> for ty::GenericArg<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.unpack().hash_stable(hcx, hasher); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 4e8cb4384f462..69219c06e5775 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -3,6 +3,7 @@ mod inherent; mod opaque_types; mod weak_types; +use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::Upcast as _; @@ -144,7 +145,7 @@ where let goal_trait_ref = goal.predicate.alias.trait_ref(cx); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !ecx.cx().args_may_unify_deep( + if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup).args_may_unify( goal.predicate.alias.trait_ref(cx).args, impl_trait_ref.skip_binder().args, ) { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2bc9d35c2b020..33050e5c01936 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -2,6 +2,7 @@ use rustc_ast_ir::Movability; use rustc_type_ir::data_structures::IndexSet; +use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; @@ -46,7 +47,8 @@ where let cx = ecx.cx(); let impl_trait_ref = cx.impl_trait_ref(impl_def_id); - if !cx.args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup) + .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) { return Err(NoSolution); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index a4177d8a93f47..9f0d84e7d4526 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -121,7 +121,7 @@ pub fn overlapping_impls( // Before doing expensive operations like entering an inference context, do // a quick check via fast_reject to tell if the impl headers could possibly // unify. - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }; + let drcx = DeepRejectCtxt::new(tcx, TreatParams::AsCandidateKey); let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e36a9ca8bd1c2..4c3d833b0f90f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -571,7 +571,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; + let drcx = DeepRejectCtxt::new(self.tcx(), TreatParams::ForLookup); let obligation_args = obligation.predicate.skip_binder().trait_ref.args; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs new file mode 100644 index 0000000000000..0810fa5c55832 --- /dev/null +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -0,0 +1,397 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::iter; +use std::marker::PhantomData; + +use rustc_ast_ir::Mutability; +#[cfg(feature = "nightly")] +use rustc_data_structures::fingerprint::Fingerprint; +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +#[cfg(feature = "nightly")] +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; + +use crate::inherent::*; +use crate::visit::TypeVisitableExt as _; +use crate::{self as ty, Interner}; + +/// See `simplify_type`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum SimplifiedType { + Bool, + Char, + Int(ty::IntTy), + Uint(ty::UintTy), + Float(ty::FloatTy), + Adt(DefId), + Foreign(DefId), + Str, + Array, + Slice, + Ref(Mutability), + Ptr(Mutability), + Never, + Tuple(usize), + /// A trait object, all of whose components are markers + /// (e.g., `dyn Send + Sync`). + MarkerTraitObject, + Trait(DefId), + Closure(DefId), + Coroutine(DefId), + CoroutineWitness(DefId), + Function(usize), + Placeholder, + Error, +} + +#[cfg(feature = "nightly")] +impl> ToStableHashKey for SimplifiedType { + type KeyType = Fingerprint; + + #[inline] + fn to_stable_hash_key(&self, hcx: &HCX) -> Fingerprint { + let mut hasher = StableHasher::new(); + let mut hcx: HCX = hcx.clone(); + self.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + } +} + +/// Generic parameters are pretty much just bound variables, e.g. +/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as +/// `for<'a, T> fn(&'a T) -> u32`. +/// +/// Typecheck of `foo` has to succeed for all possible generic arguments, so +/// during typeck, we have to treat its generic parameters as if they +/// were placeholders. +/// +/// But when calling `foo` we only have to provide a specific generic argument. +/// In that case the generic parameters are instantiated with inference variables. +/// As we use `simplify_type` before that instantiation happens, we just treat +/// generic parameters as if they were inference variables in that case. +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub enum TreatParams { + /// Treat parameters as infer vars. This is the correct mode for caching + /// an impl's type for lookup. + AsCandidateKey, + /// Treat parameters as placeholders in the given environment. This is the + /// correct mode for *lookup*, as during candidate selection. + /// + /// This also treats projections with inference variables as infer vars + /// since they could be further normalized. + ForLookup, +} + +/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. +/// +/// **This function should only be used if you need to store or retrieve the type from some +/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt] +/// instead.** +/// +/// The idea is to get something simple that we can use to quickly decide if two types could unify, +/// for example during method lookup. If this function returns `Some(x)` it can only unify with +/// types for which this method returns either `Some(x)` as well or `None`. +/// +/// A special case here are parameters and projections, which are only injective +/// if they are treated as placeholders. +/// +/// For example when storing impls based on their simplified self type, we treat +/// generic parameters as if they were inference variables. We must not simplify them here, +/// as they can unify with any other type. +/// +/// With projections we have to be even more careful, as treating them as placeholders +/// is only correct if they are fully normalized. +/// +/// ¹ meaning that if the outermost layers are different, then the whole types are also different. +pub fn simplify_type( + tcx: I, + ty: I::Ty, + treat_params: TreatParams, +) -> Option> { + match ty.kind() { + ty::Bool => Some(SimplifiedType::Bool), + ty::Char => Some(SimplifiedType::Char), + ty::Int(int_type) => Some(SimplifiedType::Int(int_type)), + ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)), + ty::Float(float_type) => Some(SimplifiedType::Float(float_type)), + ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())), + ty::Str => Some(SimplifiedType::Str), + ty::Array(..) => Some(SimplifiedType::Array), + ty::Slice(..) => Some(SimplifiedType::Slice), + ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), + ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), + ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { + Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { + Some(SimplifiedType::Trait(principal_def_id)) + } + _ => Some(SimplifiedType::MarkerTraitObject), + }, + ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), + ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { + Some(SimplifiedType::Closure(def_id)) + } + ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)), + ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)), + ty::Never => Some(SimplifiedType::Never), + ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())), + ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), + ty::Placeholder(..) => Some(SimplifiedType::Placeholder), + ty::Param(_) => match treat_params { + TreatParams::ForLookup => Some(SimplifiedType::Placeholder), + TreatParams::AsCandidateKey => None, + }, + ty::Alias(..) => match treat_params { + // When treating `ty::Param` as a placeholder, projections also + // don't unify with anything else as long as they are fully normalized. + // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` + // when the new solver is enabled by default. + TreatParams::ForLookup if !ty.has_non_region_infer() => { + Some(SimplifiedType::Placeholder) + } + TreatParams::ForLookup | TreatParams::AsCandidateKey => None, + }, + ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), + ty::Error(_) => Some(SimplifiedType::Error), + ty::Bound(..) | ty::Infer(_) => None, + } +} + +impl SimplifiedType { + pub fn def(self) -> Option { + match self { + SimplifiedType::Adt(d) + | SimplifiedType::Foreign(d) + | SimplifiedType::Trait(d) + | SimplifiedType::Closure(d) + | SimplifiedType::Coroutine(d) + | SimplifiedType::CoroutineWitness(d) => Some(d), + _ => None, + } + } +} + +/// Given generic arguments from an obligation and an impl, +/// could these two be unified after replacing parameters in the +/// the impl with inference variables. +/// +/// For obligations, parameters won't be replaced by inference +/// variables and only unify with themselves. We treat them +/// the same way we treat placeholders. +/// +/// We also use this function during coherence. For coherence the +/// impls only have to overlap for some value, so we treat parameters +/// on both sides like inference variables. This behavior is toggled +/// using the `treat_obligation_params` field. +#[derive(Debug, Clone, Copy)] +pub struct DeepRejectCtxt { + treat_obligation_params: TreatParams, + _interner: PhantomData, +} + +impl DeepRejectCtxt { + pub fn new(_interner: I, treat_obligation_params: TreatParams) -> Self { + DeepRejectCtxt { treat_obligation_params, _interner: PhantomData } + } + + pub fn args_may_unify( + self, + obligation_args: I::GenericArgs, + impl_args: I::GenericArgs, + ) -> bool { + iter::zip(obligation_args.iter(), impl_args.iter()).all(|(obl, imp)| { + match (obl.kind(), imp.kind()) { + // We don't fast reject based on regions. + (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true, + (ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => { + self.types_may_unify(obl, imp) + } + (ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => { + self.consts_may_unify(obl, imp) + } + _ => panic!("kind mismatch: {obl:?} {imp:?}"), + } + }) + } + + pub fn types_may_unify(self, obligation_ty: I::Ty, impl_ty: I::Ty) -> bool { + match impl_ty.kind() { + // Start by checking whether the type in the impl may unify with + // pretty much everything. Just return `true` in that case. + ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true, + // These types only unify with inference variables or their own + // variant. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Str + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Dynamic(..) + | ty::Pat(..) + | ty::Ref(..) + | ty::Never + | ty::Tuple(..) + | ty::FnPtr(..) + | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), + ty::FnDef(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(_) => panic!("unexpected impl_ty: {impl_ty:?}"), + } + + let k = impl_ty.kind(); + match obligation_ty.kind() { + // Purely rigid types, use structural equivalence. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Foreign(_) => obligation_ty == impl_ty, + ty::Ref(_, obl_ty, obl_mutbl) => match k { + ty::Ref(_, impl_ty, impl_mutbl) => { + obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) + } + _ => false, + }, + ty::Adt(obl_def, obl_args) => match k { + ty::Adt(impl_def, impl_args) => { + obl_def == impl_def && self.args_may_unify(obl_args, impl_args) + } + _ => false, + }, + ty::Pat(obl_ty, _) => { + // FIXME(pattern_types): take pattern into account + matches!(k, ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) + } + ty::Slice(obl_ty) => { + matches!(k, ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) + } + ty::Array(obl_ty, obl_len) => match k { + ty::Array(impl_ty, impl_len) => { + self.types_may_unify(obl_ty, impl_ty) + && self.consts_may_unify(obl_len, impl_len) + } + _ => false, + }, + ty::Tuple(obl) => match k { + ty::Tuple(imp) => { + obl.len() == imp.len() + && iter::zip(obl.iter(), imp.iter()) + .all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + ty::RawPtr(obl_ty, obl_mutbl) => match k { + ty::RawPtr(imp_ty, imp_mutbl) => { + obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty) + } + _ => false, + }, + ty::Dynamic(obl_preds, ..) => { + // Ideally we would walk the existential predicates here or at least + // compare their length. But considering that the relevant `Relate` impl + // actually sorts and deduplicates these, that doesn't work. + matches!(k, ty::Dynamic(impl_preds, ..) if + obl_preds.principal_def_id() == impl_preds.principal_def_id() + ) + } + ty::FnPtr(obl_sig) => match k { + ty::FnPtr(impl_sig) => { + let ty::FnSig { inputs_and_output, c_variadic, safety, abi } = + obl_sig.skip_binder(); + let impl_sig = impl_sig.skip_binder(); + + abi == impl_sig.abi + && c_variadic == impl_sig.c_variadic + && safety == impl_sig.safety + && inputs_and_output.len() == impl_sig.inputs_and_output.len() + && iter::zip(inputs_and_output.iter(), impl_sig.inputs_and_output.iter()) + .all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + + // Impls cannot contain these types as these cannot be named directly. + ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false, + + // Placeholder types don't unify with anything on their own + ty::Placeholder(..) | ty::Bound(..) => false, + + // Depending on the value of `treat_obligation_params`, we either + // treat generic parameters like placeholders or like inference variables. + ty::Param(_) => match self.treat_obligation_params { + TreatParams::ForLookup => false, + TreatParams::AsCandidateKey => true, + }, + + ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(), + + ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(), + + ty::Infer(_) => true, + + // As we're walking the whole type, it may encounter projections + // inside of binders and what not, so we're just going to assume that + // projections can unify with other stuff. + // + // Looking forward to lazy normalization this is the safer strategy anyways. + ty::Alias(..) => true, + + ty::Error(_) => true, + + ty::CoroutineWitness(..) => { + panic!("unexpected obligation type: {:?}", obligation_ty) + } + } + } + + pub fn consts_may_unify(self, obligation_ct: I::Const, impl_ct: I::Const) -> bool { + let impl_val = match impl_ct.kind() { + ty::ConstKind::Expr(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Unevaluated(_) + | ty::ConstKind::Error(_) => { + return true; + } + ty::ConstKind::Value(_, impl_val) => impl_val, + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + panic!("unexpected impl arg: {:?}", impl_ct) + } + }; + + match obligation_ct.kind() { + ty::ConstKind::Param(_) => match self.treat_obligation_params { + TreatParams::ForLookup => false, + TreatParams::AsCandidateKey => true, + }, + + // Placeholder consts don't unify with anything on their own + ty::ConstKind::Placeholder(_) => false, + + // As we don't necessarily eagerly evaluate constants, + // they might unify with any value. + ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { + true + } + ty::ConstKind::Value(_, obl_val) => obl_val == impl_val, + + ty::ConstKind::Infer(_) => true, + + ty::ConstKind::Bound(..) => { + panic!("unexpected obl const: {:?}", obligation_ct) + } + } + } +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index a4e1a97d50587..ffe16964ae515 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -120,6 +120,14 @@ pub trait Ty>: matches!(self.kind(), ty::Infer(ty::TyVar(_))) } + fn is_floating_point(self) -> bool { + matches!(self.kind(), ty::Float(_) | ty::Infer(ty::FloatVar(_))) + } + + fn is_integral(self) -> bool { + matches!(self.kind(), ty::Infer(ty::IntVar(_)) | ty::Int(_) | ty::Uint(_)) + } + fn is_fn_ptr(self) -> bool { matches!(self.kind(), ty::FnPtr(_)) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6665158c7cd34..eaa3ab7ce4383 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -222,13 +222,6 @@ pub trait Interner: fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; - // FIXME: move `fast_reject` into `rustc_type_ir`. - fn args_may_unify_deep( - self, - obligation_args: Self::GenericArgs, - impl_args: Self::GenericArgs, - ) -> bool; - fn for_each_relevant_impl( self, trait_def_id: Self::DefId, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9b8ca5efdda82..960ebf78cfe9d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -21,6 +21,7 @@ pub mod visit; pub mod codec; pub mod data_structures; pub mod error; +pub mod fast_reject; pub mod fold; pub mod inherent; pub mod ir_print; diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index c806bf1cc66f3..8fd56eae37ffc 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -507,8 +507,7 @@ else if (window.initSearch) window.initSearch(searchIndex); // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. let Some(impl_did) = impl_item_id.as_def_id() else { continue }; let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); - let reject_cx = - DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }; + let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey); if !reject_cx.types_may_unify(aliased_ty, for_ty) { continue; } From 3d6cc605356f0919ae0bd024aba6cec5a9981ea7 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 30 Jun 2024 08:21:20 +0000 Subject: [PATCH 025/189] Try renaming the file if removing fails --- src/bootstrap/src/lib.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 730d0ae5f3d7c..6d00ff9982d96 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -26,6 +26,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::str; use std::sync::OnceLock; +use std::time::SystemTime; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; @@ -1676,7 +1677,14 @@ impl Build { if src == dst { return; } - let _ = fs::remove_file(dst); + if let Err(e) = fs::remove_file(dst) { + if e.kind() != io::ErrorKind::NotFound { + // workaround for https://github.com/rust-lang/rust/issues/127126 + // if removing the file fails, attempt to rename it instead. + let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)); + let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos())); + } + } let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); let mut src = src.to_path_buf(); if metadata.file_type().is_symlink() { From e09815f0efdf6a91f96974284b9e5129029da45f Mon Sep 17 00:00:00 2001 From: Guillaume Boisseau Date: Sun, 30 Jun 2024 14:26:28 +0200 Subject: [PATCH 026/189] New features gates mustn't specify a version by hand --- compiler/rustc_feature/src/unstable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f100d3e4ca84e..8c30006e292b9 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -574,7 +574,7 @@ declare_features! ( /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant - (incomplete, ref_pat_eat_one_layer_2024_structural, "1.79.0", Some(123076)), + (incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. From f23c1fdaeba6a1c8237996ae2efecaf938ba9ef8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Dec 2023 18:35:49 +0000 Subject: [PATCH 027/189] Remove usage of specialization from newtype_index! --- compiler/rustc_index/src/lib.rs | 5 +---- compiler/rustc_index_macros/src/lib.rs | 5 +---- compiler/rustc_index_macros/src/newtype.rs | 4 ---- compiler/rustc_type_ir/src/lib.rs | 2 +- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index db6b250467e56..b775ae1f5e944 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,10 +1,7 @@ // tidy-alphabetical-start #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] -#![cfg_attr( - feature = "nightly", - feature(extend_one, min_specialization, new_uninit, step_trait, test) -)] #![cfg_attr(feature = "nightly", allow(internal_features))] +#![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))] // tidy-alphabetical-end pub mod bit_set; diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs index 3e55dd82a6e80..2b444932f8548 100644 --- a/compiler/rustc_index_macros/src/lib.rs +++ b/compiler/rustc_index_macros/src/lib.rs @@ -34,10 +34,7 @@ mod newtype; /// optimizations. The default max value is 0xFFFF_FF00. /// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only. #[proc_macro] -#[cfg_attr( - feature = "nightly", - allow_internal_unstable(step_trait, rustc_attrs, trusted_step, min_specialization) -)] +#[cfg_attr(feature = "nightly", allow_internal_unstable(step_trait, rustc_attrs, trusted_step))] pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index 41863f7b15f98..1ac2c44e9dca1 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -139,10 +139,6 @@ impl Parse for Newtype { Self::index(start).checked_sub(u).map(Self::from_usize) } } - - // Safety: The implementation of `Step` upholds all invariants. - #gate_rustc_only - unsafe impl ::std::iter::TrustedStep for #name {} } } else { quote! {} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d7442e7c89c4a..3913d996a6b96 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -2,7 +2,7 @@ #![allow(rustc::usage_of_ty_tykind)] #![cfg_attr( feature = "nightly", - feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls) + feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] // tidy-alphabetical-end From 449581d89bd8361d6eaa2d0e91c2197831658b1a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 15:10:34 +0000 Subject: [PATCH 028/189] Remove usage of specialization from rustc_borrowck --- compiler/rustc_borrowck/src/facts.rs | 28 ++++++++++++++++++++++++++-- compiler/rustc_borrowck/src/lib.rs | 1 - 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 51ea59e2092a5..af96f11538503 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -213,8 +213,32 @@ trait FactCell { fn to_string(&self, location_table: &LocationTable) -> String; } -impl FactCell for A { - default fn to_string(&self, _location_table: &LocationTable) -> String { +impl FactCell for BorrowIndex { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for Local { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for MovePathIndex { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for PoloniusRegionVid { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for RegionVid { + fn to_string(&self, _location_table: &LocationTable) -> String { format!("{self:?}") } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 69efee2fbdc14..91c0a39073863 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -7,7 +7,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_chains)] -#![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] From 8127461b0ed54dea8ca9cf430b1d231611e1b477 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:01:55 +0000 Subject: [PATCH 029/189] Move -Zprint-type-sizes and -Zprint-vtable-sizes into codegen_and_build_linker --- compiler/rustc_driver_impl/src/lib.rs | 17 +---------------- compiler/rustc_interface/src/queries.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bbe9741bf444e..3780e575b9352 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -41,7 +41,6 @@ use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::collect_crate_types; use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -448,21 +447,7 @@ fn run_compiler( return early_exit(); } - let linker = queries.codegen_and_build_linker()?; - - // This must run after monomorphization so that all generic types - // have been instantiated. - if sess.opts.unstable_opts.print_type_sizes { - sess.code_stats.print_type_sizes(); - } - - if sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = queries.global_ctxt()?.enter(|tcx| tcx.crate_name(LOCAL_CRATE)); - - sess.code_stats.print_vtable_sizes(crate_name); - } - - Ok(Some(linker)) + Ok(Some(queries.codegen_and_build_linker()?)) })?; // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index cfd4304e89303..5f00d7a76b29b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -121,6 +121,18 @@ impl<'tcx> Queries<'tcx> { self.global_ctxt()?.enter(|tcx| { let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?; + // This must run after monomorphization so that all generic types + // have been instantiated. + if tcx.sess.opts.unstable_opts.print_type_sizes { + tcx.sess.code_stats.print_type_sizes(); + } + + if tcx.sess.opts.unstable_opts.print_vtable_sizes { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + tcx.sess.code_stats.print_vtable_sizes(crate_name); + } + Ok(Linker { dep_graph: tcx.dep_graph.clone(), output_filenames: tcx.output_filenames(()).clone(), From da81d0d940481827fb2bdd164ea0038832e3779e Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 1 Jul 2024 06:03:08 +0800 Subject: [PATCH 030/189] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 5a5152f653959..e6a6470d1eb4c 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 5a5152f653959d14d68613a3a8a033fb65eec021 +Subproject commit e6a6470d1eb4c88fee4b1ea98cd8e0ac4a181c16 From 15fbe618a14ddde520561c4cf1b85d4e4c9005f8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 09:34:52 -0700 Subject: [PATCH 031/189] rustdoc: update to pulldown-cmark 0.11 --- Cargo.lock | 21 ++-- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_resolve/src/rustdoc.rs | 14 ++- src/librustdoc/html/markdown.rs | 111 +++++++++--------- src/librustdoc/passes/lint/bare_urls.rs | 4 +- src/librustdoc/passes/lint/html_tags.rs | 6 +- .../passes/lint/redundant_explicit_links.rs | 16 ++- src/tools/tidy/src/deps.rs | 1 + 8 files changed, 94 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94d70a020a4dc..3af90a252aea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3123,25 +3123,26 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.6" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ "bitflags 2.5.0", + "getopts", "memchr", + "pulldown-cmark-escape 0.10.1", "unicase", ] [[package]] name = "pulldown-cmark" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0" dependencies = [ "bitflags 2.5.0", - "getopts", "memchr", - "pulldown-cmark-escape", + "pulldown-cmark-escape 0.11.0", "unicase", ] @@ -3151,6 +3152,12 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "pulldown-cmark-to-cmark" version = "13.0.0" @@ -4604,7 +4611,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "pulldown-cmark 0.9.6", + "pulldown-cmark 0.11.0", "rustc_arena", "rustc_ast", "rustc_ast_pretty", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index b6ae54010c242..b71853b871dc5 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -pulldown-cmark = { version = "0.9.6", default-features = false } +pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 66b4981eb55ba..594608153211d 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,4 +1,6 @@ -use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; +use pulldown_cmark::{ + BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, Options, Parser, Tag, +}; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; @@ -427,7 +429,9 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { while let Some(event) = event_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + Event::Start(Tag::Link { link_type, dest_url, title: _, id: _ }) + if may_be_doc_link(link_type) => + { if matches!( link_type, LinkType::Inline @@ -441,7 +445,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } } - links.push(preprocess_link(&dest)); + links.push(preprocess_link(&dest_url)); } _ => {} } @@ -451,8 +455,8 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } /// Collects additional data of link. -fn collect_link_data<'input, 'callback>( - event_iter: &mut Parser<'input, 'callback>, +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + event_iter: &mut Parser<'input, F>, ) -> Option> { let mut display_text: Option = None; let mut append_text = |text: CowStr<'_>| { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bae929c64eab2..a7f0df5afa98f 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -54,7 +54,8 @@ use crate::html::render::small_url_encode; use crate::html::toc::TocBuilder; use pulldown_cmark::{ - html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag, + html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, + Options, Parser, Tag, TagEnd, }; #[cfg(test)] @@ -230,7 +231,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let mut original_text = String::new(); for event in &mut self.inner { match event { - Event::End(Tag::CodeBlock(..)) => break, + Event::End(TagEnd::CodeBlock) => break, Event::Text(ref s) => { original_text.push_str(s); } @@ -359,16 +360,17 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { match &mut event { // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` // Remove any disambiguator. - Some(Event::Start(Tag::Link( + Some(Event::Start(Tag::Link { // [fn@f] or [fn@f][] - LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, - dest, + link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest_url, title, - ))) => { - debug!("saw start of shortcut link to {dest} with title {title}"); + .. + })) => { + debug!("saw start of shortcut link to {dest_url} with title {title}"); // If this is a shortcut link, it was resolved by the broken_link_callback. // So the URL will already be updated properly. - let link = self.links.iter().find(|&link| *link.href == **dest); + let link = self.links.iter().find(|&link| *link.href == **dest_url); // Since this is an external iterator, we can't replace the inner text just yet. // Store that we saw a link so we know to replace it later. if let Some(link) = link { @@ -381,16 +383,9 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } } // Now that we're done with the shortcut link, don't replace any more text. - Some(Event::End(Tag::Link( - LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, - dest, - _, - ))) => { - debug!("saw end of shortcut link to {dest}"); - if self.links.iter().any(|link| *link.href == **dest) { - assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); - self.shortcut_link = None; - } + Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => { + debug!("saw end of shortcut link"); + self.shortcut_link = None; } // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. // [`fn@f`] @@ -433,9 +428,11 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } // If this is a link, but not a shortcut link, // replace the URL, since the broken_link_callback was not called. - Some(Event::Start(Tag::Link(_, dest, title))) => { - if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { - *dest = CowStr::Borrowed(link.href.as_ref()); + Some(Event::Start(Tag::Link { dest_url, title, .. })) => { + if let Some(link) = + self.links.iter().find(|&link| *link.original_text == **dest_url) + { + *dest_url = CowStr::Borrowed(link.href.as_ref()); if title.is_empty() && !link.tooltip.is_empty() { *title = CowStr::Borrowed(link.tooltip.as_ref()); } @@ -477,9 +474,9 @@ impl<'a, I: Iterator>> Iterator for TableWrapper<'a, I> { self.stored_events.push_back(Event::Start(Tag::Table(t))); Event::Html(CowStr::Borrowed("
")) } - Event::End(Tag::Table(t)) => { + Event::End(TagEnd::Table) => { self.stored_events.push_back(Event::Html(CowStr::Borrowed("
"))); - Event::End(Tag::Table(t)) + Event::End(TagEnd::Table) } e => e, }) @@ -519,11 +516,11 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator } let event = self.inner.next(); - if let Some((Event::Start(Tag::Heading(level, _, _)), _)) = event { + if let Some((Event::Start(Tag::Heading { level, .. }), _)) = event { let mut id = String::new(); for event in &mut self.inner { match &event.0 { - Event::End(Tag::Heading(..)) => break, + Event::End(TagEnd::Heading(_)) => break, Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); self.buf.push_back(event); @@ -566,27 +563,27 @@ impl<'a, I: Iterator>> SummaryLine<'a, I> { } } -fn check_if_allowed_tag(t: &Tag<'_>) -> bool { +fn check_if_allowed_tag(t: &TagEnd) -> bool { matches!( t, - Tag::Paragraph - | Tag::Emphasis - | Tag::Strong - | Tag::Strikethrough - | Tag::Link(..) - | Tag::BlockQuote + TagEnd::Paragraph + | TagEnd::Emphasis + | TagEnd::Strong + | TagEnd::Strikethrough + | TagEnd::Link + | TagEnd::BlockQuote ) } -fn is_forbidden_tag(t: &Tag<'_>) -> bool { +fn is_forbidden_tag(t: &TagEnd) -> bool { matches!( t, - Tag::CodeBlock(_) - | Tag::Table(_) - | Tag::TableHead - | Tag::TableRow - | Tag::TableCell - | Tag::FootnoteDefinition(_) + TagEnd::CodeBlock + | TagEnd::Table + | TagEnd::TableHead + | TagEnd::TableRow + | TagEnd::TableCell + | TagEnd::FootnoteDefinition ) } @@ -604,12 +601,12 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { let mut is_start = true; let is_allowed_tag = match event { Event::Start(ref c) => { - if is_forbidden_tag(c) { + if is_forbidden_tag(&c.to_end()) { self.skipped_tags += 1; return None; } self.depth += 1; - check_if_allowed_tag(c) + check_if_allowed_tag(&c.to_end()) } Event::End(ref c) => { if is_forbidden_tag(c) { @@ -633,7 +630,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { if is_start { Some(Event::Start(Tag::Paragraph)) } else { - Some(Event::End(Tag::Paragraph)) + Some(Event::End(TagEnd::Paragraph)) } } else { Some(event) @@ -679,7 +676,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => { let mut content = Vec::new(); for (event, _) in &mut self.inner { - if let Event::End(Tag::FootnoteDefinition(..)) = event { + if let Event::End(TagEnd::FootnoteDefinition) = event { break; } content.push(event); @@ -696,7 +693,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { for (mut content, id) in v { write!(ret, "
  • ").unwrap(); let mut is_paragraph = false; - if let Some(&Event::End(Tag::Paragraph)) = content.last() { + if let Some(&Event::End(TagEnd::Paragraph)) = content.last() { content.pop(); is_paragraph = true; } @@ -806,7 +803,7 @@ pub(crate) fn find_codes( tests.visit_test(text, block_info, line); prev_offset = offset.start; } - Event::Start(Tag::Heading(level, _, _)) => { + Event::Start(Tag::Heading { level, .. }) => { register_header = Some(level as u32); } Event::Text(ref s) if register_header.is_some() => { @@ -1432,7 +1429,7 @@ impl MarkdownItemInfo<'_> { // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { - Event::Html(text) => (Event::Text(text), event.1), + Event::Html(text) | Event::InlineHtml(text) => (Event::Text(text), event.1), _ => event, }); @@ -1442,7 +1439,7 @@ impl MarkdownItemInfo<'_> { let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = p.filter(|event| { - !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) + !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph)) }); html::push_html(&mut s, p); @@ -1472,7 +1469,7 @@ impl MarkdownSummaryLine<'_> { let mut s = String::new(); let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| { - !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) + !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph)) }); html::push_html(&mut s, without_paragraphs); @@ -1544,8 +1541,8 @@ fn markdown_summary_with_limit( _ => {} }, Event::End(tag) => match tag { - Tag::Emphasis | Tag::Strong => buf.close_tag(), - Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()), + TagEnd::Emphasis | TagEnd::Strong => buf.close_tag(), + TagEnd::Paragraph | TagEnd::Heading(_) => return ControlFlow::Break(()), _ => {} }, Event::HardBreak | Event::SoftBreak => buf.push(" ")?, @@ -1605,8 +1602,8 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin } Event::HardBreak | Event::SoftBreak => s.push(' '), Event::Start(Tag::CodeBlock(..)) => break, - Event::End(Tag::Paragraph) => break, - Event::End(Tag::Heading(..)) => break, + Event::End(TagEnd::Paragraph) => break, + Event::End(TagEnd::Heading(..)) => break, _ => (), } } @@ -1765,7 +1762,7 @@ pub(crate) fn markdown_links<'md, R>( while let Some((event, span)) = event_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => { let range = match link_type { // Link is pulled from the link itself. LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { @@ -1775,7 +1772,7 @@ pub(crate) fn markdown_links<'md, R>( LinkType::Inline => span_for_offset_backward(span, b'(', b')'), // Link is pulled from elsewhere in the document. LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { - span_for_link(&dest, span) + span_for_link(&dest_url, span) } LinkType::Autolink | LinkType::Email => unreachable!(), }; @@ -1795,7 +1792,7 @@ pub(crate) fn markdown_links<'md, R>( if let Some(link) = preprocess_link(MarkdownLink { kind: link_type, - link: dest.into_string(), + link: dest_url.into_string(), display_text, range, }) { @@ -1810,8 +1807,8 @@ pub(crate) fn markdown_links<'md, R>( } /// Collects additional data of link. -fn collect_link_data<'input, 'callback>( - event_iter: &mut OffsetIter<'input, 'callback>, +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + event_iter: &mut OffsetIter<'input, F>, ) -> Option { let mut display_text: Option = None; let mut append_text = |text: CowStr<'_>| { diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 8f68f6ff4764a..4b2d3092837e1 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -42,11 +42,11 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { match event { Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag), // We don't want to check the text inside code blocks or links. - Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => { + Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => { while let Some((event, _)) = p.next() { match event { Event::End(end) - if mem::discriminant(&end) == mem::discriminant(&tag) => + if mem::discriminant(&end) == mem::discriminant(&tag.to_end()) => { break; } diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index a0064a9011254..87dfa5d5389d7 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -4,7 +4,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag}; +use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use std::iter::Peekable; @@ -140,10 +140,10 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { for (event, range) in p { match event { Event::Start(Tag::CodeBlock(_)) => in_code_block = true, - Event::Html(text) if !in_code_block => { + Event::Html(text) | Event::InlineHtml(text) if !in_code_block => { extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) } - Event::End(Tag::CodeBlock(_)) => in_code_block = false, + Event::End(TagEnd::CodeBlock) => in_code_block = false, _ => {} } } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 7ab974046b9c7..b36b41c9f2d2e 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -1,6 +1,8 @@ use std::ops::Range; -use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag}; +use pulldown_cmark::{ + BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag, +}; use rustc_ast::NodeId; use rustc_errors::SuggestionStyle; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; @@ -95,7 +97,7 @@ fn check_redundant_explicit_link<'md>( while let Some((event, link_range)) = offset_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) => { + Event::Start(Tag::Link { link_type, dest_url, .. }) => { let link_data = collect_link_data(&mut offset_iter); if let Some(resolvable_link) = link_data.resolvable_link.as_ref() { @@ -108,7 +110,7 @@ fn check_redundant_explicit_link<'md>( } } - let explicit_link = dest.to_string(); + let explicit_link = dest_url.to_string(); let display_link = link_data.resolvable_link.clone()?; if explicit_link.ends_with(&display_link) || display_link.ends_with(&explicit_link) @@ -122,7 +124,7 @@ fn check_redundant_explicit_link<'md>( doc, resolutions, link_range, - dest.to_string(), + dest_url.to_string(), link_data, if link_type == LinkType::Inline { (b'(', b')') @@ -139,7 +141,7 @@ fn check_redundant_explicit_link<'md>( doc, resolutions, link_range, - &dest, + &dest_url, link_data, ); } @@ -259,7 +261,9 @@ fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option) -> LinkData { +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + offset_iter: &mut OffsetIter<'input, F>, +) -> LinkData { let mut resolvable_link = None; let mut resolvable_link_range = None; let mut display_link = String::new(); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index aa119819aaa26..82fa43f581fde 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -335,6 +335,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "proc-macro2", "psm", "pulldown-cmark", + "pulldown-cmark-escape", "punycode", "quote", "r-efi", From 9732251e5f36772bb030ec4e3b8f6fc4f8371eec Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Mon, 1 Jul 2024 11:13:30 +0530 Subject: [PATCH 032/189] Remove unqualified import io:: Error for vxworks as all Error references are qualified in process_vxworks.rs --- library/std/src/sys/pal/unix/process/process_vxworks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 76179e0910d9e..5007dbd34b4ab 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, Error, ErrorKind}; +use crate::io::{self, ErrorKind}; use crate::num::NonZero; use crate::sys; use crate::sys::cvt; From b3ef0e8487286b90e60261b9ac8d26dbb91b7e99 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Thu, 13 Jun 2024 16:35:29 +0200 Subject: [PATCH 033/189] Handle universe leaks by rewriting the constraint graph This version is a squash-rebased version of a series of exiermental commits, since large parts of them were broken out into PR #125069. It explicitly handles universe violations in higher-kinded outlives constraints by adding extra outlives static constraints. --- .../rustc_borrowck/src/constraints/mod.rs | 84 +++++++++++++++++ .../src/diagnostics/region_errors.rs | 3 +- .../rustc_borrowck/src/region_infer/mod.rs | 89 +++++-------------- compiler/rustc_middle/src/mir/query.rs | 3 + 4 files changed, 111 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index b54e05b2b34a4..9a76539f57998 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,4 +1,6 @@ +use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker}; use crate::type_check::Locations; +use crate::universal_regions::UniversalRegions; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; @@ -48,6 +50,88 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { ) -> &IndexSlice> { &self.outlives } + + /// Computes cycles (SCCs) in the graph of regions. In particular, + /// find all regions R1, R2 such that R1: R2 and R2: R1 and group + /// them into an SCC, and find the relationships between SCCs. + pub(crate) fn compute_sccs( + &self, + static_region: RegionVid, + definitions: &IndexVec>, + ) -> ConstraintSccs { + let constraint_graph = self.graph(definitions.len()); + let region_graph = &constraint_graph.region_graph(self, static_region); + ConstraintSccs::new_with_annotation(®ion_graph, |r| { + RegionTracker::new(r, &definitions[r]) + }) + } + + /// This method handles universe errors by rewriting the constraint + /// graph. For each strongly connected component in the constraint + /// graph such that there is a series of constraints + /// A: B: C: ... : X where + /// A's universe is smaller than X's and A is a placeholder, + /// add A: 'static. + /// + /// For a more precise definition, see the documentation for + /// [`RegionTracker::has_incompatible_universes()`]. + /// + /// Every constraint added by this method is an + /// `IllegalUniverse` constraint. + #[instrument(skip(self, universal_regions, definitions))] + pub(crate) fn add_outlives_static( + &mut self, + universal_regions: &UniversalRegions<'tcx>, + definitions: &IndexVec>, + ) -> ConstraintSccs { + let fr_static = universal_regions.fr_static; + let sccs = self.compute_sccs(fr_static, definitions); + + // Changed to `true` if we added any constraints to `self` and need to + // recompute SCCs. + let mut added_constraints = false; + + for scc in sccs.all_sccs() { + // No point in adding 'static: 'static! + // This micro-optimisation makes somewhat sense + // because static outlives *everything*. + if scc == sccs.scc(fr_static) { + continue; + } + + let annotation = sccs.annotation(scc); + + // If this SCC participates in a universe violation, + // e.g. if it reaches a region with a universe smaller than + // the largest region reached, add a requirement that it must + // outlive `'static`. + if annotation.has_incompatible_universes() { + // Optimisation opportunity: this will add more constraints than + // needed for correctness, since an SCC upstream of another with + // a universe violation will "infect" its downstream SCCs to also + // outlive static. + added_constraints = true; + let scc_representative_outlives_static = OutlivesConstraint { + sup: annotation.representative, + sub: fr_static, + category: ConstraintCategory::IllegalUniverse, + locations: Locations::All(rustc_span::DUMMY_SP), + span: rustc_span::DUMMY_SP, + variance_info: VarianceDiagInfo::None, + from_closure: false, + }; + self.push(scc_representative_outlives_static); + } + } + + if added_constraints { + // We changed the constraint set and so must recompute SCCs. + self.compute_sccs(fr_static, definitions) + } else { + // If we didn't add any back-edges; no more work needs doing + sccs + } + } } impl<'tcx> Index for OutlivesConstraintSet<'tcx> { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index db78edc45b9de..61f107db784ad 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -66,7 +66,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::Predicate(_) | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => "", + | ConstraintCategory::Internal + | ConstraintCategory::IllegalUniverse => "", } } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c56eaaff076ce..78e0b4783c3aa 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -62,7 +62,7 @@ pub struct RegionTracker { /// The representative Region Variable Id for this SCC. We prefer /// placeholders over existentially quantified variables, otherwise /// it's the one with the smallest Region Variable ID. - representative: RegionVid, + pub(crate) representative: RegionVid, /// Is the current representative a placeholder? representative_is_placeholder: bool, @@ -97,7 +97,7 @@ impl scc::Annotation for RegionTracker { } impl RegionTracker { - fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { + pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { let (representative_is_placeholder, representative_is_existential) = match definition.origin { rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false), @@ -132,7 +132,7 @@ impl RegionTracker { /// Returns `true` if during the annotated SCC reaches a placeholder /// with a universe larger than the smallest reachable one, `false` otherwise. - pub fn has_incompatible_universes(&self) -> bool { + pub(crate) fn has_incompatible_universes(&self) -> bool { self.universe().cannot_name(self.max_placeholder_universe_reached) } } @@ -163,7 +163,7 @@ pub struct RegionInferenceContext<'tcx> { /// The SCC computed from `constraints` and the constraint /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to /// compute the values of each region. - constraint_sccs: Rc, + constraint_sccs: ConstraintSccs, /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required @@ -401,7 +401,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_regions: Rc>, placeholder_indices: Rc, universal_region_relations: Frozen>, - outlives_constraints: OutlivesConstraintSet<'tcx>, + mut outlives_constraints: OutlivesConstraintSet<'tcx>, member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, universe_causes: FxIndexMap>, type_tests: Vec>, @@ -419,17 +419,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|info| RegionDefinition::new(info.universe, info.origin)) .collect(); - let fr_static = universal_regions.fr_static; + let constraint_sccs = + outlives_constraints.add_outlives_static(&universal_regions, &definitions); let constraints = Frozen::freeze(outlives_constraints); let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); - let constraint_sccs = { - let constraint_graph = constraints.graph(definitions.len()); - let region_graph = &constraint_graph.region_graph(&constraints, fr_static); - let sccs = ConstraintSccs::new_with_annotation(®ion_graph, |r| { - RegionTracker::new(r, &definitions[r]) - }); - Rc::new(sccs) - }; if cfg!(debug_assertions) { sccs_info(infcx, &constraint_sccs); @@ -548,21 +541,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } NllRegionVariableOrigin::Placeholder(placeholder) => { - // Each placeholder region is only visible from - // its universe `ui` and its extensions. So we - // can't just add it into `scc` unless the - // universe of the scc can name this region. - let scc_universe = self.scc_universe(scc); - if scc_universe.can_name(placeholder.universe) { - self.scc_values.add_element(scc, placeholder); - } else { - debug!( - "init_free_and_bound_regions: placeholder {:?} is \ - not compatible with universe {:?} of its SCC {:?}", - placeholder, scc_universe, scc, - ); - self.add_incompatible_universe(scc); - } + self.scc_values.add_element(scc, placeholder); } NllRegionVariableOrigin::Existential { .. } => { @@ -744,23 +723,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// (which is assured by iterating over SCCs in dependency order). #[instrument(skip(self), level = "debug")] fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { - let constraint_sccs = self.constraint_sccs.clone(); - // Walk each SCC `B` such that `A: B`... - for &scc_b in constraint_sccs.successors(scc_a) { + for &scc_b in self.constraint_sccs.successors(scc_a) { debug!(?scc_b); - - // ...and add elements from `B` into `A`. One complication - // arises because of universes: If `B` contains something - // that `A` cannot name, then `A` can only contain `B` if - // it outlives static. - if self.universe_compatible(scc_b, scc_a) { - // `A` can name everything that is in `B`, so just - // merge the bits. - self.scc_values.add_region(scc_a, scc_b); - } else { - self.add_incompatible_universe(scc_a); - } + self.scc_values.add_region(scc_a, scc_b); } // Now take member constraints into account. @@ -886,35 +852,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let universe_a = self.constraint_sccs().annotation(scc_a).universe(); - let universe_b = self.constraint_sccs().annotation(scc_b).universe(); + let a_annotation = self.constraint_sccs().annotation(scc_a); + let b_annotation = self.constraint_sccs().annotation(scc_b); + let a_universe = a_annotation.universe(); - // Quick check: if scc_b's declared universe is a subset of + // If scc_b's declared universe is a subset of // scc_a's declared universe (typically, both are ROOT), then // it cannot contain any problematic universe elements. - if universe_a.can_name(universe_b) { + if a_universe.can_name(b_annotation.universe()) { return true; } - // Otherwise, we have to iterate over the universe elements in - // B's value, and check whether all of them are nameable - // from universe_a - self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) - } - - /// Extend `scc` so that it can outlive some placeholder region - /// from a universe it can't name; at present, the only way for - /// this to be true is if `scc` outlives `'static`. This is - /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b>` that might then allow us to approximate - /// `'a` with `'b` and not `'static`. But it will have to do for - /// now. - fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { - debug!("add_incompatible_universe(scc={:?})", scc); - - let fr_static = self.universal_regions.fr_static; - self.scc_values.add_all_points(scc); - self.scc_values.add_element(scc, fr_static); + // Otherwise, there can be no placeholder in `b` with a too high + // universe index to name from `a`. + a_universe.can_name(b_annotation.max_placeholder_universe_reached) } /// Once regions have been propagated, this method is used to see @@ -1896,6 +1847,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // This loop can be hot. for constraint in outgoing_edges_from_graph { + if matches!(constraint.category, ConstraintCategory::IllegalUniverse) { + debug!("Ignoring illegal universe constraint: {constraint:?}"); + continue; + } handle_constraint(constraint); } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 46b38e4a6a60c..cd8e28522ecfb 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -274,6 +274,9 @@ pub enum ConstraintCategory<'tcx> { /// A constraint that doesn't correspond to anything the user sees. Internal, + + /// An internal constraint derived from an illegal universe relation. + IllegalUniverse, } #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] From eea5cf87b29c1ab4b2dc50a1a6dca87ec3628b19 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Mon, 1 Jul 2024 11:32:45 +0200 Subject: [PATCH 034/189] Code review: rename the method `min_universe()` --- compiler/rustc_borrowck/src/region_infer/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 78e0b4783c3aa..44a84fb9d7f1a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -116,7 +116,9 @@ impl RegionTracker { representative_is_existential, } } - fn universe(self) -> UniverseIndex { + + /// The smallest-indexed universe reachable from and/or in this SCC. + fn min_universe(self) -> UniverseIndex { self.min_reachable_universe } @@ -133,7 +135,7 @@ impl RegionTracker { /// Returns `true` if during the annotated SCC reaches a placeholder /// with a universe larger than the smallest reachable one, `false` otherwise. pub(crate) fn has_incompatible_universes(&self) -> bool { - self.universe().cannot_name(self.max_placeholder_universe_reached) + self.min_universe().cannot_name(self.max_placeholder_universe_reached) } } @@ -780,7 +782,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.constraint_sccs().annotation(scc).universe().is_root() { + if !self.constraint_sccs().annotation(scc).min_universe().is_root() { return; } @@ -854,12 +856,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { let a_annotation = self.constraint_sccs().annotation(scc_a); let b_annotation = self.constraint_sccs().annotation(scc_b); - let a_universe = a_annotation.universe(); + let a_universe = a_annotation.min_universe(); // If scc_b's declared universe is a subset of // scc_a's declared universe (typically, both are ROOT), then // it cannot contain any problematic universe elements. - if a_universe.can_name(b_annotation.universe()) { + if a_universe.can_name(b_annotation.min_universe()) { return true; } @@ -973,7 +975,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "lower_bound = {:?} r_scc={:?} universe={:?}", lower_bound, r_scc, - self.constraint_sccs.annotation(r_scc).universe() + self.constraint_sccs.annotation(r_scc).min_universe() ); // If the type test requires that `T: 'a` where `'a` is a @@ -1490,7 +1492,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The minimum universe of any variable reachable from this /// SCC, inside or outside of it. fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.constraint_sccs().annotation(scc).universe() + self.constraint_sccs().annotation(scc).min_universe() } /// Checks the final value for the free region `fr` to see if it /// grew too large. In particular, examine what `end(X)` points From 9be3a3d761060a047667226bd742346f8c25c6cf Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Mon, 1 Jul 2024 11:51:28 +0200 Subject: [PATCH 035/189] Add description for why this PR was made --- .../rustc_borrowck/src/constraints/mod.rs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 9a76539f57998..bb2fc3b67e9d0 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -66,18 +66,40 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { }) } - /// This method handles universe errors by rewriting the constraint + /// This method handles Universe errors by rewriting the constraint /// graph. For each strongly connected component in the constraint /// graph such that there is a series of constraints /// A: B: C: ... : X where /// A's universe is smaller than X's and A is a placeholder, - /// add A: 'static. + /// add a constraint that A: 'static. This is a safe upper bound + /// in the face of borrow checker/trait solver limitations that will + /// eventually go away. /// /// For a more precise definition, see the documentation for /// [`RegionTracker::has_incompatible_universes()`]. /// + /// This edge case used to be handled during constraint propagation + /// by iterating over the strongly connected components in the constraint + /// graph while maintaining a set of bookkeeping mappings similar + /// to what is stored in `RegionTracker` and manually adding 'sttaic as + /// needed. + /// + /// It was rewritten as part of the Polonius project with the goal of moving + /// higher-kindedness concerns out of the path of the borrow checker, + /// for two reasons: + /// + /// 1. Implementing Polonius is difficult enough without also + /// handling them. + /// 2. The long-term goal is to handle higher-kinded concerns + /// in the trait solver, where they belong. This avoids + /// logic duplication and allows future trait solvers + /// to compute better bounds than for example our + /// "must outlive 'static" here. + /// + /// This code is a stop-gap measure in preparation for the future trait solver. + /// /// Every constraint added by this method is an - /// `IllegalUniverse` constraint. + /// internal `IllegalUniverse` constraint. #[instrument(skip(self, universal_regions, definitions))] pub(crate) fn add_outlives_static( &mut self, From 61963fabdf2eaf9a68be970dfad7eb470a0fc0d5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:14:42 +0000 Subject: [PATCH 036/189] Avoid an ICE reachable through const eval shenanigans --- .../rustc_hir_typeck/src/method/confirm.rs | 9 ++-- .../arbitrary-self-from-method-substs-ice.rs | 29 ++++++++++++ ...bitrary-self-from-method-substs-ice.stderr | 46 +++++++++++++++++++ ...ary-self-from-method-substs.default.stderr | 1 - 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 tests/ui/self/arbitrary-self-from-method-substs-ice.rs create mode 100644 tests/ui/self/arbitrary-self-from-method-substs-ice.stderr diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 120e3239d1f1b..02844bcadac6e 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -510,9 +510,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { .report_mismatched_types(&cause, method_self_ty, self_ty, terr) .emit(); } else { - error!("{self_ty} was a subtype of {method_self_ty} but now is not?"); - // This must already have errored elsewhere. - self.dcx().has_errors().unwrap(); + // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions + // may run before wfcheck if the function is used in const eval. + self.dcx().span_delayed_bug( + cause.span(), + format!("{self_ty} was a subtype of {method_self_ty} but now is not?"), + ); } } } diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs new file mode 100644 index 0000000000000..8bf9f97e0b91d --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -0,0 +1,29 @@ +//! The same as the non-ICE test, but const eval will run typeck of +//! `get` before running wfcheck (as that may in itself trigger const +//! eval again, and thus cause bogus cycles). This used to ICE because +//! we asserted that an error had already been emitted. + +use std::ops::Deref; + +struct Foo(u32); +impl Foo { + const fn get>(self: R) -> u32 { + //~^ ERROR: `R` cannot be used as the type of `self` + //~| ERROR destructor of `R` cannot be evaluated at compile-time + self.0 + //~^ ERROR cannot borrow here, since the borrowed element may contain interior mutability + //~| ERROR cannot call non-const fn `::deref` in constant function + } +} + +const FOO: () = { + let foo = Foo(1); + foo.get::<&Foo>(); +}; + +const BAR: [(); { + FOO; + 0 +}] = []; + +fn main() {} diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr new file mode 100644 index 0000000000000..9e3851f9a6e72 --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -0,0 +1,46 @@ +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 + | +LL | self.0 + | ^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0015]: cannot call non-const fn `::deref` in constant functions + --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 + | +LL | self.0 + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error[E0493]: destructor of `R` cannot be evaluated at compile-time + --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43 + | +LL | const fn get>(self: R) -> u32 { + | ^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 + | +LL | const fn get>(self: R) -> u32 { + | ^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0015, E0493, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr index 6fff086a89c2e..4cc69666b8876 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr @@ -9,7 +9,6 @@ LL | fn get>(self: R) -> u32 { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) - ERROR rustc_hir_typeck::method::confirm Foo was a subtype of &Foo but now is not? error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. From 9d5da39b3a4d3155dca12db9eb7ea6be6234e8a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:26:27 +0000 Subject: [PATCH 037/189] Revert some ICE avoiding logic that is not necessary anymore --- compiler/rustc_hir_typeck/src/writeback.rs | 25 +++------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index aea0114167eb9..ceb7480686d90 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -219,28 +219,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) { if let hir::ExprKind::Index(ref base, ref index, _) = e.kind { // All valid indexing looks like this; might encounter non-valid indexes at this point. - let base_ty = self.typeck_results.expr_ty_adjusted_opt(base); - if base_ty.is_none() { - // When encountering `return [0][0]` outside of a `fn` body we can encounter a base - // that isn't in the type table. We assume more relevant errors have already been - // emitted. (#64638) - assert!(self.tcx().dcx().has_errors().is_some(), "bad base: `{base:?}`"); - } - if let Some(base_ty) = base_ty - && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() - { - let index_ty = - self.typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| { - // When encountering `return [0][0]` outside of a `fn` body we would attempt - // to access an nonexistent index. We assume that more relevant errors will - // already have been emitted, so we only gate on this with an ICE if no - // error has been emitted. (#64638) - Ty::new_error_with_message( - self.fcx.tcx, - e.span, - format!("bad index {index:?} for base: `{base:?}`"), - ) - }); + let base_ty = self.typeck_results.expr_ty_adjusted(base); + if let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() { + let index_ty = self.typeck_results.expr_ty_adjusted(index); if self.is_builtin_index(e, base_ty_inner, index_ty) { // Remove the method call record self.typeck_results.type_dependent_defs_mut().remove(e.hir_id); From a5d37238a1171ddcf0bbf37f5900bcb442678ffd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:31:41 +0000 Subject: [PATCH 038/189] Prefer item-local tainting checks over global error count checks --- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2fbc8a3f146a1..f3aece4e1d8aa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -708,7 +708,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // else an error would have been flagged by the // `loops` pass for using break with an expression // where you are not supposed to. - assert!(expr_opt.is_none() || self.dcx().has_errors().is_some()); + assert!(expr_opt.is_none() || self.tainted_by_errors().is_some()); } // If we encountered a `break`, then (no surprise) it may be possible to break from the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 430e12ff7b87b..ba7719bbb4e6d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1652,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); - // Hide the outer diverging and `has_errors` flags. + // Hide the outer diverging flags. let old_diverges = self.diverges.replace(Diverges::Maybe); match stmt.kind { From 814bfe9335fd7c941169e0ef15ae2cffeacc78eb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:35:16 +0000 Subject: [PATCH 039/189] This check should now be unreachable --- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 9a353bfe49d0e..c8ab0429ffc70 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,9 +734,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - if self.cx.tcx().dcx().has_errors().is_none() { - span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); - } + span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); } } From bd2ff518cefe1dc9e1dcd328319eead618eed67a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:44:11 +0000 Subject: [PATCH 040/189] Move codegen_and_build_linker from Queries to Linker --- compiler/rustc_driver_impl/src/lib.rs | 6 ++- compiler/rustc_interface/src/lib.rs | 2 +- compiler/rustc_interface/src/queries.rs | 59 +++++++++++++------------ tests/ui-fulldeps/run-compiler-twice.rs | 7 ++- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 3780e575b9352..ad2acb03b3f67 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -30,7 +30,7 @@ use rustc_errors::{ }; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{interface, passes, Queries}; +use rustc_interface::{interface, passes, Linker, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; @@ -447,7 +447,9 @@ fn run_compiler( return early_exit(); } - Ok(Some(queries.codegen_and_build_linker()?)) + queries.global_ctxt()?.enter(|tcx| { + Ok(Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)?)) + }) })?; // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 38f64ebb04e7b..e37b30749ab30 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -16,7 +16,7 @@ pub mod util; pub use callbacks::setup_callbacks; pub use interface::{run_compiler, Config}; pub use passes::DEFAULT_QUERY_PROVIDERS; -pub use queries::Queries; +pub use queries::{Linker, Queries}; #[cfg(test)] mod tests; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 5f00d7a76b29b..e78576c8e4301 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -116,35 +116,6 @@ impl<'tcx> Queries<'tcx> { ) }) } - - pub fn codegen_and_build_linker(&'tcx self) -> Result { - self.global_ctxt()?.enter(|tcx| { - let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?; - - // This must run after monomorphization so that all generic types - // have been instantiated. - if tcx.sess.opts.unstable_opts.print_type_sizes { - tcx.sess.code_stats.print_type_sizes(); - } - - if tcx.sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = tcx.crate_name(LOCAL_CRATE); - - tcx.sess.code_stats.print_vtable_sizes(crate_name); - } - - Ok(Linker { - dep_graph: tcx.dep_graph.clone(), - output_filenames: tcx.output_filenames(()).clone(), - crate_hash: if tcx.needs_crate_hash() { - Some(tcx.crate_hash(LOCAL_CRATE)) - } else { - None - }, - ongoing_codegen, - }) - }) - } } pub struct Linker { @@ -156,6 +127,36 @@ pub struct Linker { } impl Linker { + pub fn codegen_and_build_linker( + tcx: TyCtxt<'_>, + codegen_backend: &dyn CodegenBackend, + ) -> Result { + let ongoing_codegen = passes::start_codegen(codegen_backend, tcx)?; + + // This must run after monomorphization so that all generic types + // have been instantiated. + if tcx.sess.opts.unstable_opts.print_type_sizes { + tcx.sess.code_stats.print_type_sizes(); + } + + if tcx.sess.opts.unstable_opts.print_vtable_sizes { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + tcx.sess.code_stats.print_vtable_sizes(crate_name); + } + + Ok(Linker { + dep_graph: tcx.dep_graph.clone(), + output_filenames: tcx.output_filenames(()).clone(), + crate_hash: if tcx.needs_crate_hash() { + Some(tcx.crate_hash(LOCAL_CRATE)) + } else { + None + }, + ongoing_codegen, + }) + } + pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> { let (codegen_results, work_products) = codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames); diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index 02748626723d9..720fc42cc5700 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -17,6 +17,7 @@ extern crate rustc_span; use std::path::{Path, PathBuf}; +use rustc_interface::Linker; use rustc_interface::interface; use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes}; use rustc_span::FileName; @@ -78,8 +79,10 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path interface::run_compiler(config, |compiler| { let linker = compiler.enter(|queries| { - queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; - queries.codegen_and_build_linker() + queries.global_ctxt()?.enter(|tcx| { + tcx.analysis(())?; + Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend) + }) }); linker.unwrap().link(&compiler.sess, &*compiler.codegen_backend).unwrap(); }); From ec2d1b0ed2f62d0d1da2ce1d5fbffc2eea4ff7b8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 19:29:25 +0000 Subject: [PATCH 041/189] Minor change --- compiler/rustc_interface/src/queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index e78576c8e4301..370c06c22a7de 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -210,7 +210,7 @@ impl Compiler { F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, { // Must declare `_timer` first so that it is dropped after `queries`. - let mut _timer = None; + let _timer; let queries = Queries::new(self); let ret = f(&queries); @@ -233,7 +233,7 @@ impl Compiler { // The timer's lifetime spans the dropping of `queries`, which contains // the global context. - _timer = Some(self.sess.timer("free_global_ctxt")); + _timer = self.sess.timer("free_global_ctxt"); if let Err((path, error)) = queries.finish() { self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error }); } From f27645927c15c8f643242101ced25492bacf0cce Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 19:40:54 +0000 Subject: [PATCH 042/189] Inline Query::default() --- compiler/rustc_interface/src/queries.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 370c06c22a7de..821e8ee7ba589 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -65,12 +65,6 @@ impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> { } } -impl Default for Query { - fn default() -> Self { - Query { result: RefCell::new(None) } - } -} - pub struct Queries<'tcx> { compiler: &'tcx Compiler, gcx_cell: OnceLock>, @@ -90,8 +84,8 @@ impl<'tcx> Queries<'tcx> { gcx_cell: OnceLock::new(), arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), - parse: Default::default(), - gcx: Default::default(), + parse: Query { result: RefCell::new(None) }, + gcx: Query { result: RefCell::new(None) }, } } From 8cc1ed81dfd9e6eeb50d3621e0c862e9d3b4fe92 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 1 Jul 2024 13:05:23 +0800 Subject: [PATCH 043/189] Fix import suggestion error when failed not from starting --- compiler/rustc_resolve/src/diagnostics.rs | 12 +++++++++- .../ui/imports/suggest-import-issue-120074.rs | 11 +++++++++ .../suggest-import-issue-120074.stderr | 23 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/suggest-import-issue-120074.rs create mode 100644 tests/ui/imports/suggest-import-issue-120074.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 263daa11ec316..50a4e03d233a7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1987,10 +1987,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { candidates .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path))); if let Some(candidate) = candidates.get(0) { + let path = { + // remove the possible common prefix of the path + let start_index = (0..failed_segment_idx) + .find(|&i| path[i].ident != candidate.path.segments[i].ident) + .unwrap_or_default(); + let segments = (start_index..=failed_segment_idx) + .map(|s| candidate.path.segments[s].clone()) + .collect(); + Path { segments, span: Span::default(), tokens: None } + }; ( String::from("unresolved import"), Some(( - vec![(ident.span, pprust::path_to_string(&candidate.path))], + vec![(ident.span, pprust::path_to_string(&path))], String::from("a similar path exists"), Applicability::MaybeIncorrect, )), diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs new file mode 100644 index 0000000000000..a798e9eeeb809 --- /dev/null +++ b/tests/ui/imports/suggest-import-issue-120074.rs @@ -0,0 +1,11 @@ +pub mod foo { + pub mod bar { + pub fn do_the_thing() -> usize { + 42 + } + } +} + +fn main() { + println!("Hello, {}!", crate::bar::do_the_thing); //~ ERROR failed to resolve: unresolved import +} diff --git a/tests/ui/imports/suggest-import-issue-120074.stderr b/tests/ui/imports/suggest-import-issue-120074.stderr new file mode 100644 index 0000000000000..c1dff93bbdbff --- /dev/null +++ b/tests/ui/imports/suggest-import-issue-120074.stderr @@ -0,0 +1,23 @@ +error[E0433]: failed to resolve: unresolved import + --> $DIR/suggest-import-issue-120074.rs:10:35 + | +LL | println!("Hello, {}!", crate::bar::do_the_thing); + | ^^^ unresolved import + | +help: a similar path exists + | +LL | println!("Hello, {}!", crate::foo::bar::do_the_thing); + | ~~~~~~~~ +help: consider importing this module + | +LL + use foo::bar; + | +help: if you import `bar`, refer to it directly + | +LL - println!("Hello, {}!", crate::bar::do_the_thing); +LL + println!("Hello, {}!", bar::do_the_thing); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. From 860729ea39bc568aa57ce8cb152647138cfda995 Mon Sep 17 00:00:00 2001 From: dimi Date: Mon, 1 Jul 2024 14:14:22 +0200 Subject: [PATCH 044/189] Stabilize atomic_bool_fetch_not --- library/core/src/sync/atomic.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index df108f5e0e4e5..efc07f38f68e0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1069,7 +1069,6 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_bool_fetch_not)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let foo = AtomicBool::new(true); @@ -1081,7 +1080,7 @@ impl AtomicBool { /// assert_eq!(foo.load(Ordering::SeqCst), true); /// ``` #[inline] - #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")] + #[stable(feature = "atomic_bool_fetch_not", since = "CURRENT_RUSTC_VERSION")] #[cfg(target_has_atomic = "8")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_not(&self, order: Ordering) -> bool { From ccc50b21c149686e7620253b10936e79665404f1 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 24 Jun 2024 14:40:04 +0800 Subject: [PATCH 045/189] add syscall `dup()` --- src/tools/miri/src/shims/unix/fd.rs | 28 +++++++++++++++++++ .../miri/src/shims/unix/foreign_items.rs | 13 +++++++++ src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 26 +++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 599f78e712a2a..87e20954a70a1 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -273,6 +273,34 @@ impl FdTable { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + match this.machine.fds.dup(old_fd) { + Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)), + None => this.fd_not_found(), + } + } + + fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + match this.machine.fds.dup(old_fd) { + Some(dup_fd) => { + if new_fd != old_fd { + // Close new_fd if it is previously opened. + // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive. + if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) { + // Ignore close error (not interpreter's) according to dup2() doc. + file_descriptor.close(this.machine.communicate())?.ok(); + } + } + Ok(new_fd) + } + None => this.fd_not_found(), + } + } + fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 53ad40cfd2ccc..2421f9244f367 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -115,6 +115,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "dup" => { + let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let old_fd = this.read_scalar(old_fd)?.to_i32()?; + let new_fd = this.dup(old_fd)?; + this.write_scalar(Scalar::from_i32(new_fd), dest)?; + } + "dup2" => { + let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let old_fd = this.read_scalar(old_fd)?.to_i32()?; + let new_fd = this.read_scalar(new_fd)?.to_i32()?; + let result = this.dup2(old_fd, new_fd)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // File and file system access "open" | "open64" => { diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 80c9757e9c956..da685e5c6b7dc 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -15,6 +15,7 @@ use std::path::PathBuf; mod utils; fn main() { + test_dup(); test_dup_stdout_stderr(); test_canonicalize_too_long(); test_rename(); @@ -74,6 +75,31 @@ fn test_dup_stdout_stderr() { } } +fn test_dup() { + let bytes = b"dup and dup2"; + let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + unsafe { + let fd = libc::open(name_ptr, libc::O_RDONLY); + let mut first_buf = [0u8; 4]; + libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4); + assert_eq!(&first_buf, b"dup "); + + let new_fd = libc::dup(fd); + let mut second_buf = [0u8; 4]; + libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4); + assert_eq!(&second_buf, b"and "); + + let new_fd2 = libc::dup2(fd, 8); + let mut third_buf = [0u8; 4]; + libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4); + assert_eq!(&third_buf, b"dup2"); + } +} + fn test_canonicalize_too_long() { // Make sure we get an error for long paths. let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap()); From 294c3dda881ae65d528ee0380b7628deaf33ae96 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 11:24:36 -0700 Subject: [PATCH 046/189] rustdoc: add usable lint for pulldown-cmark-0.11 parsing changes --- Cargo.lock | 12 ++ src/librustdoc/Cargo.toml | 1 + src/librustdoc/lint.rs | 9 ++ src/librustdoc/passes/lint.rs | 2 + .../passes/lint/unportable_markdown.rs | 152 ++++++++++++++++++ tests/rustdoc-ui/unportable-markdown.rs | 63 ++++++++ tests/rustdoc-ui/unportable-markdown.stderr | 39 +++++ 7 files changed, 278 insertions(+) create mode 100644 src/librustdoc/passes/lint/unportable_markdown.rs create mode 100644 tests/rustdoc-ui/unportable-markdown.rs create mode 100644 tests/rustdoc-ui/unportable-markdown.stderr diff --git a/Cargo.lock b/Cargo.lock index 3af90a252aea7..96cef9070842e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3121,6 +3121,17 @@ dependencies = [ "cc", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.5.0", + "memchr", + "unicase", +] + [[package]] name = "pulldown-cmark" version = "0.10.3" @@ -4890,6 +4901,7 @@ dependencies = [ "indexmap", "itertools", "minifier", + "pulldown-cmark 0.9.6", "regex", "rustdoc-json-types", "serde", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 31222f213d800..51fb126cb3407 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,6 +13,7 @@ base64 = "0.21.7" itertools = "0.12" indexmap = "2" minifier = "0.3.0" +pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde_json = "1.0" diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index dd2bb47e5926b..8eaca70eaff48 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -196,6 +196,14 @@ declare_rustdoc_lint! { "detects redundant explicit links in doc comments" } +declare_rustdoc_lint! { + /// This compatibility lint checks for Markdown syntax that works in the old engine but not + /// the new one. + UNPORTABLE_MARKDOWN, + Warn, + "detects markdown that is interpreted differently in different parser" +} + pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -209,6 +217,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { MISSING_CRATE_LEVEL_DOCS, UNESCAPED_BACKTICKS, REDUNDANT_EXPLICIT_LINKS, + UNPORTABLE_MARKDOWN, ] }); diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index c6d5b7bd346d4..bc804a340bf2c 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -6,6 +6,7 @@ mod check_code_block_syntax; mod html_tags; mod redundant_explicit_links; mod unescaped_backticks; +mod unportable_markdown; use super::Pass; use crate::clean::*; @@ -31,6 +32,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> { html_tags::visit_item(self.cx, item); unescaped_backticks::visit_item(self.cx, item); redundant_explicit_links::visit_item(self.cx, item); + unportable_markdown::visit_item(self.cx, item); self.visit_item_recur(item) } diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs new file mode 100644 index 0000000000000..5f18537763441 --- /dev/null +++ b/src/librustdoc/passes/lint/unportable_markdown.rs @@ -0,0 +1,152 @@ +//! Detects specific markdown syntax that's different between pulldown-cmark +//! 0.9 and 0.11. +//! +//! This is a mitigation for old parser bugs that affected some +//! real crates' docs. The old parser claimed to comply with CommonMark, +//! but it did not. These warnings will eventually be removed, +//! though some of them may become Clippy lints. +//! +//! +//! +//! + +use crate::clean::Item; +use crate::core::DocContext; +use pulldown_cmark as cmarkn; +use pulldown_cmark_old as cmarko; +use rustc_lint_defs::Applicability; +use rustc_resolve::rustdoc::source_span_for_markdown_range; +use std::collections::{BTreeMap, BTreeSet}; + +pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { + let tcx = cx.tcx; + let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { + // If non-local, no need to check anything. + return; + }; + + let dox = item.doc_value(); + if dox.is_empty() { + return; + } + + // P1: unintended strikethrough was fixed by requiring single-tildes to flank + // the same way underscores do, so nothing is done here + + // P2: block quotes without following space parsed wrong + // + // This is the set of starting points for block quotes with no space after + // the `>`. It is populated by the new parser, and if the old parser fails to + // clear it out, it'll produce a warning. + let mut spaceless_block_quotes = BTreeSet::new(); + + // P3: missing footnote references + // + // This is populated by listening for FootnoteReference from + // the new parser and old parser. + let mut missing_footnote_references = BTreeMap::new(); + let mut found_footnote_references = BTreeSet::new(); + + // populate problem cases from new parser + { + pub fn main_body_opts_new() -> cmarkn::Options { + cmarkn::Options::ENABLE_TABLES + | cmarkn::Options::ENABLE_FOOTNOTES + | cmarkn::Options::ENABLE_STRIKETHROUGH + | cmarkn::Options::ENABLE_TASKLISTS + | cmarkn::Options::ENABLE_SMART_PUNCTUATION + } + let mut parser_new = cmarkn::Parser::new_ext(&dox, main_body_opts_new()).into_offset_iter(); + while let Some((event, span)) = parser_new.next() { + if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event { + if !dox[span.clone()].starts_with("> ") { + spaceless_block_quotes.insert(span.start); + } + } + if let cmarkn::Event::FootnoteReference(_) = event { + found_footnote_references.insert(span.start + 1); + } + } + } + + // remove cases where they don't actually differ + { + pub fn main_body_opts_old() -> cmarko::Options { + cmarko::Options::ENABLE_TABLES + | cmarko::Options::ENABLE_FOOTNOTES + | cmarko::Options::ENABLE_STRIKETHROUGH + | cmarko::Options::ENABLE_TASKLISTS + | cmarko::Options::ENABLE_SMART_PUNCTUATION + } + let mut parser_old = cmarko::Parser::new_ext(&dox, main_body_opts_old()).into_offset_iter(); + while let Some((event, span)) = parser_old.next() { + if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event { + if !dox[span.clone()].starts_with("> ") { + spaceless_block_quotes.remove(&span.start); + } + } + if let cmarko::Event::FootnoteReference(_) = event { + if !found_footnote_references.contains(&(span.start + 1)) { + missing_footnote_references.insert(span.start + 1, span); + } + } + } + } + + for start in spaceless_block_quotes { + let (span, precise) = + source_span_for_markdown_range(tcx, &dox, &(start..start + 1), &item.attrs.doc_strings) + .map(|span| (span, true)) + .unwrap_or_else(|| (item.attr_span(tcx), false)); + + tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| { + lint.primary_message("unportable markdown"); + lint.help(format!("confusing block quote with no space after the `>` marker")); + if precise { + lint.span_suggestion( + span.shrink_to_hi(), + "if the quote is intended, add a space", + " ", + Applicability::MaybeIncorrect, + ); + lint.span_suggestion( + span.shrink_to_lo(), + "if it should not be a quote, escape it", + "\\", + Applicability::MaybeIncorrect, + ); + } + }); + } + for (_caret, span) in missing_footnote_references { + let (ref_span, precise) = + source_span_for_markdown_range(tcx, &dox, &span, &item.attrs.doc_strings) + .map(|span| (span, true)) + .unwrap_or_else(|| (item.attr_span(tcx), false)); + + tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| { + lint.primary_message("unportable markdown"); + if precise { + lint.span_suggestion( + ref_span.shrink_to_lo(), + "if it should not be a footnote, escape it", + "\\", + Applicability::MaybeIncorrect, + ); + } + if dox.as_bytes().get(span.end) == Some(&b'[') { + lint.help("confusing footnote reference and link"); + if precise { + lint.span_suggestion( + ref_span.shrink_to_hi(), + "if the footnote is intended, add a space", + " ", + Applicability::MaybeIncorrect, + ); + } else { + lint.help("there should be a space between the link and the footnote"); + } + } + }); + } +} diff --git a/tests/rustdoc-ui/unportable-markdown.rs b/tests/rustdoc-ui/unportable-markdown.rs new file mode 100644 index 0000000000000..8035e680f3cf4 --- /dev/null +++ b/tests/rustdoc-ui/unportable-markdown.rs @@ -0,0 +1,63 @@ +// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929 +// +// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes. +// +// This version of the lint is targeted at two especially-common cases where docs got broken. +// Other differences in parsing should not warn. +#![allow(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::unportable_markdown)] + +/// +/// +/// Test footnote [^foot]. +/// +/// [^foot]: This is nested within the footnote now, but didn't used to be. +/// +/// This is a multi-paragraph footnote. +pub struct GfmFootnotes; + +/// +/// +/// test [^foo][^bar] +//~^ ERROR unportable markdown +/// +/// [^foo]: test +/// [^bar]: test2 +pub struct FootnoteSmashedName; + +/// +/// +/// - _t +/// # test +/// t_ +pub struct NestingCornerCase; + +/// +/// +/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~ +pub struct Emphasis1; + +/// +/// +/// | +/// | +pub struct NotEnoughTable; + +/// +/// +/// foo +/// >bar +//~^ ERROR unportable markdown +pub struct BlockQuoteNoSpace; + +/// Negative test. +/// +/// foo +/// > bar +pub struct BlockQuoteSpace; + +/// Negative test. +/// +/// >bar +/// baz +pub struct BlockQuoteNoSpaceStart; diff --git a/tests/rustdoc-ui/unportable-markdown.stderr b/tests/rustdoc-ui/unportable-markdown.stderr new file mode 100644 index 0000000000000..b524aca25aef9 --- /dev/null +++ b/tests/rustdoc-ui/unportable-markdown.stderr @@ -0,0 +1,39 @@ +error: unportable markdown + --> $DIR/unportable-markdown.rs:21:10 + | +LL | /// test [^foo][^bar] + | ^^^^^^ + | + = help: confusing footnote reference and link +note: the lint level is defined here + --> $DIR/unportable-markdown.rs:8:9 + | +LL | #![deny(rustdoc::unportable_markdown)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if it should not be a footnote, escape it + | +LL | /// test \[^foo][^bar] + | + +help: if the footnote is intended, add a space + | +LL | /// test [^foo] [^bar] + | + + +error: unportable markdown + --> $DIR/unportable-markdown.rs:49:5 + | +LL | /// >bar + | ^ + | + = help: confusing block quote with no space after the `>` marker +help: if the quote is intended, add a space + | +LL | /// > bar + | + +help: if it should not be a quote, escape it + | +LL | /// \>bar + | + + +error: aborting due to 2 previous errors + From cc1b3ee7f1601499ec96dcdfcf6ac1ee40657e6b Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 11:25:12 -0700 Subject: [PATCH 047/189] clippy: update to pulldown-cmark 0.11 --- src/tools/clippy/clippy_lints/src/doc/mod.rs | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 3d875e7ac2d3f..3e210fd153bf5 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -6,10 +6,10 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ - Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, + Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; -use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; +use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_hir::intravisit::{self, Visitor}; @@ -659,7 +659,7 @@ fn check_doc<'a, Events: Iterator, Range { + Html(tag) | InlineHtml(tag) => { if tag.starts_with(", Range { + Start(BlockQuote(_)) => { blockquote_level += 1; containers.push(Container::Blockquote); }, - End(BlockQuote) => { + End(TagEnd::BlockQuote) => { blockquote_level -= 1; containers.pop(); }, @@ -699,15 +699,15 @@ fn check_doc<'a, Events: Iterator, Range { + End(TagEnd::CodeBlock) => { in_code = false; is_rust = false; ignore = false; }, - Start(Link(_, url, _)) => in_link = Some(url), - End(Link(..)) => in_link = None, - Start(Heading(_, _, _) | Paragraph | Item) => { - if let Start(Heading(_, _, _)) = event { + Start(Link { dest_url, .. }) => in_link = Some(dest_url), + End(TagEnd::Link) => in_link = None, + Start(Heading { .. } | Paragraph | Item) => { + if let Start(Heading { .. }) = event { in_heading = true; } if let Start(Item) = event { @@ -720,11 +720,11 @@ fn check_doc<'a, Events: Iterator, Range { - if let End(Heading(_, _, _)) = event { + End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => { + if let End(TagEnd::Heading(_)) = event { in_heading = false; } - if let End(Item) = event { + if let End(TagEnd::Item) = event { containers.pop(); } if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { @@ -746,8 +746,8 @@ fn check_doc<'a, Events: Iterator, Range in_footnote_definition = true, - End(FootnoteDefinition(..)) => in_footnote_definition = false, - Start(_tag) | End(_tag) => (), // We don't care about other tags + End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, + Start(_) | End(_) => (), // We don't care about other tags SoftBreak | HardBreak => { if !containers.is_empty() && let Some((next_event, next_range)) = events.peek() @@ -765,7 +765,7 @@ fn check_doc<'a, Events: Iterator, Range (), + TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; ticks_unbalanced |= text.contains('`') && !in_code; From c8592da16a9e16535f3dfb9359066113f8656de0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 30 Jun 2024 19:04:14 -0700 Subject: [PATCH 048/189] rustc_data_structures: fix wrong markdown syntax This didn't produce working footnote links. The unportable markdown lint warned about it. --- compiler/rustc_data_structures/src/sync.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 79ceb28abb518..058a675c40d7b 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -35,11 +35,11 @@ //! | | | | //! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | //! -//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost +//! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost //! of a `RefCell`. This is appropriate when interior mutability is not //! required. //! -//! [^2] `MTRef`, `MTLockRef` are type aliases. +//! [^2]: `MTRef`, `MTLockRef` are type aliases. pub use crate::marker::*; use std::collections::HashMap; From e9dd39cda49c260213f73af4b0ba05cecb292b39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2024 10:29:11 +0200 Subject: [PATCH 049/189] fix simd_bitmask return type for non-power-of-two inputs, and add tests --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 16 ++-- tests/ui/simd/simd-bitmask-notpow2.rs | 90 ++++++++++++++++++++ tests/ui/simd/simd-bitmask.rs | 45 +++++++--- 3 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 tests/ui/simd/simd-bitmask-notpow2.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b5b0086f7405a..e02c61cd29654 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1121,8 +1121,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_select_bitmask { let (len, _) = require_simd!(arg_tys[1], SimdArgument); - let expected_int_bits = (len.max(8) - 1).next_power_of_two(); - let expected_bytes = len / 8 + ((len % 8 > 0) as u64); + let expected_int_bits = len.max(8).next_power_of_two(); + let expected_bytes = len.div_ceil(8); let mask_ty = arg_tys[0]; let mask = match mask_ty.kind() { @@ -1379,17 +1379,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_bitmask { - // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a - // vector mask and returns the most significant bit (MSB) of each lane in the form - // of either: + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a vector mask and + // returns one bit for each lane (which must all be `0` or `!0`) in the form of either: // * an unsigned integer // * an array of `u8` // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. // // The bit order of the result depends on the byte endianness, LSB-first for little // endian and MSB-first for big endian. - let expected_int_bits = in_len.max(8); - let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + let expected_int_bits = in_len.max(8).next_power_of_two(); + let expected_bytes = in_len.div_ceil(8); // Integer vector : let (i_xn, in_elem_bitwidth) = match in_elem.kind() { @@ -1409,7 +1408,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }), }; - // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position. + // LLVM doesn't always know the inputs are `0` or `!0`, so we shift here so it optimizes to + // `pmovmskb` and similar on x86. let shift_indices = vec![ bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _); diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs new file mode 100644 index 0000000000000..ff43206a3fd6b --- /dev/null +++ b/tests/ui/simd/simd-bitmask-notpow2.rs @@ -0,0 +1,90 @@ +//@run-pass +// SEGFAULTS on LLVM 17. This should be merged into `simd-bitmask` once we require LLVM 18. +//@ min-llvm-version: 18 +// FIXME: broken codegen on big-endian (https://github.com/rust-lang/rust/issues/127205) +//@ ignore-endian-big +#![feature(repr_simd, intrinsics)] + +extern "rust-intrinsic" { + fn simd_bitmask(v: T) -> U; + fn simd_select_bitmask(m: T, a: U, b: U) -> U; +} + +fn main() { + // Non-power-of-2 multi-byte mask. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x10([i32; 10]); + impl i32x10 { + fn splat(x: i32) -> Self { + Self([x; 10]) + } + } + unsafe { + let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); + let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; + let mask_bytes = + if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] }; + + let bitmask1: u16 = simd_bitmask(mask); + let bitmask2: [u8; 2] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::( + mask_bits, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 2], _>( + mask_bytes, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } + + // Test for a mask where the next multiple of 8 is not a power of two. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x20([i32; 20]); + impl i32x20 { + fn splat(x: i32) -> Self { + Self([x; 20]) + } + } + unsafe { + let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); + let mask_bits = if cfg!(target_endian = "little") { + 0b11111110000101001011 + } else { + 0b11010010100001111111 + }; + let mask_bytes = if cfg!(target_endian = "little") { + [0b01001011, 0b11100001, 0b1111] + } else { + [0b1101, 0b00101000, 0b01111111] + }; + + let bitmask1: u32 = simd_bitmask(mask); + let bitmask2: [u8; 3] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::( + mask_bits, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 3], _>( + mask_bytes, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } +} diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs index 4a7c3bc77507c..82f73fca95124 100644 --- a/tests/ui/simd/simd-bitmask.rs +++ b/tests/ui/simd/simd-bitmask.rs @@ -1,5 +1,4 @@ //@run-pass -//@ignore-endian-big behavior of simd_select_bitmask is endian-specific #![feature(repr_simd, intrinsics)] extern "rust-intrinsic" { @@ -17,36 +16,58 @@ fn main() { let i: u8 = simd_bitmask(v); let a: [u8; 1] = simd_bitmask(v); - assert_eq!(i, 0b0101); - assert_eq!(a, [0b0101]); + if cfg!(target_endian = "little") { + assert_eq!(i, 0b0101); + assert_eq!(a, [0b0101]); + } else { + assert_eq!(i, 0b1010); + assert_eq!(a, [0b1010]); + } let v = Simd::([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]); let i: u16 = simd_bitmask(v); let a: [u8; 2] = simd_bitmask(v); - assert_eq!(i, 0b0101000000001100); - assert_eq!(a, [0b1100, 0b01010000]); + if cfg!(target_endian = "little") { + assert_eq!(i, 0b0101000000001100); + assert_eq!(a, [0b00001100, 0b01010000]); + } else { + assert_eq!(i, 0b0011000000001010); + assert_eq!(a, [0b00110000, 0b00001010]); + } } unsafe { - let a = Simd::([0, 1, 2, 3, 4, 5, 6, 7]); - let b = Simd::([8, 9, 10, 11, 12, 13, 14, 15]); - let e = [0, 9, 2, 11, 12, 13, 14, 15]; + let a = Simd::([0, 1, 2, 3]); + let b = Simd::([8, 9, 10, 11]); + let e = [0, 9, 2, 11]; - let r = simd_select_bitmask(0b0101u8, a, b); + let mask = if cfg!(target_endian = "little") { 0b0101u8 } else { 0b1010u8 }; + let r = simd_select_bitmask(mask, a, b); assert_eq!(r.0, e); - let r = simd_select_bitmask([0b0101u8], a, b); + let mask = if cfg!(target_endian = "little") { [0b0101u8] } else { [0b1010u8] }; + let r = simd_select_bitmask(mask, a, b); assert_eq!(r.0, e); let a = Simd::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); let b = Simd::([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31]; - let r = simd_select_bitmask(0b0101000000001100u16, a, b); + let mask = if cfg!(target_endian = "little") { + 0b0101000000001100u16 + } else { + 0b0011000000001010u16 + }; + let r = simd_select_bitmask(mask, a, b); assert_eq!(r.0, e); - let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b); + let mask = if cfg!(target_endian = "little") { + [0b00001100u8, 0b01010000u8] + } else { + [0b00110000u8, 0b00001010u8] + }; + let r = simd_select_bitmask(mask, a, b); assert_eq!(r.0, e); } } From 1834f5a272d567a714f78c7f48c0d3ae4a6238bb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 26 Jun 2024 19:13:38 +0000 Subject: [PATCH 050/189] Swap encapsulation of DCP state. --- .../rustc_mir_dataflow/src/value_analysis.rs | 149 ++++++++++-------- 1 file changed, 81 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index bfbfff7e25944..0364c23bfcbe4 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -39,7 +39,7 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -336,14 +336,14 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper const NAME: &'static str = T::NAME; fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { - State(StateData::Unreachable) + State::Unreachable } fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. - assert!(matches!(state.0, StateData::Unreachable)); - let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); - *state = State(StateData::Reachable(values)); + assert!(matches!(state, State::Unreachable)); + let values = StateData::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); + *state = State::Reachable(values); for arg in body.args_iter() { state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); } @@ -415,27 +415,30 @@ rustc_index::newtype_index!( /// See [`State`]. #[derive(PartialEq, Eq, Debug)] -enum StateData { - Reachable(IndexVec), - Unreachable, +struct StateData { + map: IndexVec, +} + +impl StateData { + fn from_elem_n(elem: V, n: usize) -> StateData { + StateData { map: IndexVec::from_elem_n(elem, n) } + } } impl Clone for StateData { fn clone(&self) -> Self { - match self { - Self::Reachable(x) => Self::Reachable(x.clone()), - Self::Unreachable => Self::Unreachable, - } + StateData { map: self.map.clone() } } fn clone_from(&mut self, source: &Self) { - match (&mut *self, source) { - (Self::Reachable(x), Self::Reachable(y)) => { - // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. - x.raw.clone_from(&y.raw); - } - _ => *self = source.clone(), - } + // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. + self.map.raw.clone_from(&source.map.raw) + } +} + +impl JoinSemiLattice for StateData { + fn join(&mut self, other: &Self) -> bool { + self.map.join(&other.map) } } @@ -450,33 +453,43 @@ impl Clone for StateData { /// /// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place. #[derive(PartialEq, Eq, Debug)] -pub struct State(StateData); +pub enum State { + Unreachable, + Reachable(StateData), +} impl Clone for State { fn clone(&self) -> Self { - Self(self.0.clone()) + match self { + Self::Reachable(x) => Self::Reachable(x.clone()), + Self::Unreachable => Self::Unreachable, + } } fn clone_from(&mut self, source: &Self) { - self.0.clone_from(&source.0); + match (&mut *self, source) { + (Self::Reachable(x), Self::Reachable(y)) => { + x.clone_from(&y); + } + _ => *self = source.clone(), + } } } impl State { pub fn new(init: V, map: &Map) -> State { - let values = IndexVec::from_elem_n(init, map.value_count); - State(StateData::Reachable(values)) + State::Reachable(StateData::from_elem_n(init, map.value_count)) } pub fn all(&self, f: impl Fn(&V) -> bool) -> bool { - match self.0 { - StateData::Unreachable => true, - StateData::Reachable(ref values) => values.iter().all(f), + match self { + State::Unreachable => true, + State::Reachable(ref values) => values.map.iter().all(f), } } fn is_reachable(&self) -> bool { - matches!(&self.0, StateData::Reachable(_)) + matches!(self, State::Reachable(_)) } /// Assign `value` to all places that are contained in `place` or may alias one. @@ -519,9 +532,9 @@ impl State { map: &Map, value: V, ) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; map.for_each_aliasing_place(place, tail_elem, &mut |vi| { - values[vi] = value.clone(); + values.map[vi] = value.clone(); }); } @@ -541,9 +554,9 @@ impl State { /// /// The target place must have been flooded before calling this method. pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { - values[value_index] = value; + values.map[value_index] = value; } } @@ -555,14 +568,14 @@ impl State { /// /// The target place must have been flooded before calling this method. pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; // If both places are tracked, we copy the value to the target. // If the target is tracked, but the source is not, we do nothing, as invalidation has // already been performed. if let Some(target_value) = map.places[target].value_index { if let Some(source_value) = map.places[source].value_index { - values[target_value] = values[source_value].clone(); + values.map[target_value] = values.map[source_value].clone(); } } for target_child in map.children(target) { @@ -616,11 +629,11 @@ impl State { /// Retrieve the value stored for a place index, or `None` if it is not tracked. pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { - match &self.0 { - StateData::Reachable(values) => { - map.places[place].value_index.map(|v| values[v].clone()) + match self { + State::Reachable(values) => { + map.places[place].value_index.map(|v| values.map[v].clone()) } - StateData::Unreachable => None, + State::Unreachable => None, } } @@ -631,10 +644,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -645,10 +658,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -659,10 +672,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -673,11 +686,11 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(values) => { - map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP) + match self { + State::Reachable(values) => { + map.places[place].value_index.map(|v| values.map[v].clone()).unwrap_or(V::TOP) } - StateData::Unreachable => { + State::Unreachable => { // Because this is unreachable, we can return any value we want. V::BOTTOM } @@ -687,13 +700,13 @@ impl State { impl JoinSemiLattice for State { fn join(&mut self, other: &Self) -> bool { - match (&mut self.0, &other.0) { - (_, StateData::Unreachable) => false, - (StateData::Unreachable, _) => { + match (&mut *self, other) { + (_, State::Unreachable) => false, + (State::Unreachable, _) => { *self = other.clone(); true } - (StateData::Reachable(this), StateData::Reachable(other)) => this.join(other), + (State::Reachable(this), State::Reachable(ref other)) => this.join(other), } } } @@ -1194,9 +1207,9 @@ where T::Value: Debug, { fn fmt_with(&self, ctxt: &ValueAnalysisWrapper, f: &mut Formatter<'_>) -> std::fmt::Result { - match &self.0 { - StateData::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), - StateData::Unreachable => write!(f, "unreachable"), + match self { + State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), + State::Unreachable => write!(f, "unreachable"), } } @@ -1206,8 +1219,8 @@ where ctxt: &ValueAnalysisWrapper, f: &mut Formatter<'_>, ) -> std::fmt::Result { - match (&self.0, &old.0) { - (StateData::Reachable(this), StateData::Reachable(old)) => { + match (self, old) { + (State::Reachable(this), State::Reachable(old)) => { debug_with_context(this, Some(old), ctxt.0.map(), f) } _ => Ok(()), // Consider printing something here. @@ -1218,18 +1231,18 @@ where fn debug_with_context_rec( place: PlaceIndex, place_str: &str, - new: &IndexSlice, - old: Option<&IndexSlice>, + new: &StateData, + old: Option<&StateData>, map: &Map, f: &mut Formatter<'_>, ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { match old { - None => writeln!(f, "{}: {:?}", place_str, new[value])?, + None => writeln!(f, "{}: {:?}", place_str, new.map[value])?, Some(old) => { - if new[value] != old[value] { - writeln!(f, "\u{001f}-{}: {:?}", place_str, old[value])?; - writeln!(f, "\u{001f}+{}: {:?}", place_str, new[value])?; + if new.map[value] != old.map[value] { + writeln!(f, "\u{001f}-{}: {:?}", place_str, old.map[value])?; + writeln!(f, "\u{001f}+{}: {:?}", place_str, new.map[value])?; } } } @@ -1262,8 +1275,8 @@ fn debug_with_context_rec( } fn debug_with_context( - new: &IndexSlice, - old: Option<&IndexSlice>, + new: &StateData, + old: Option<&StateData>, map: &Map, f: &mut Formatter<'_>, ) -> std::fmt::Result { From 76244d4dbc768e15e429c1f66ec021884f369f5f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 26 Jun 2024 21:57:59 +0000 Subject: [PATCH 051/189] Make jump threading state sparse. --- .../src/framework/lattice.rs | 14 +++ .../rustc_mir_dataflow/src/value_analysis.rs | 91 ++++++++++++------- .../rustc_mir_transform/src/jump_threading.rs | 19 +++- 3 files changed, 86 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 1c2b475a43c96..23738f7a4a538 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -76,6 +76,8 @@ pub trait MeetSemiLattice: Eq { /// A set that has a "bottom" element, which is less than or equal to any other element. pub trait HasBottom { const BOTTOM: Self; + + fn is_bottom(&self) -> bool; } /// A set that has a "top" element, which is greater than or equal to any other element. @@ -114,6 +116,10 @@ impl MeetSemiLattice for bool { impl HasBottom for bool { const BOTTOM: Self = false; + + fn is_bottom(&self) -> bool { + !self + } } impl HasTop for bool { @@ -267,6 +273,10 @@ impl MeetSemiLattice for FlatSet { impl HasBottom for FlatSet { const BOTTOM: Self = Self::Bottom; + + fn is_bottom(&self) -> bool { + matches!(self, Self::Bottom) + } } impl HasTop for FlatSet { @@ -291,6 +301,10 @@ impl MaybeReachable { impl HasBottom for MaybeReachable { const BOTTOM: Self = MaybeReachable::Unreachable; + + fn is_bottom(&self) -> bool { + matches!(self, Self::Unreachable) + } } impl HasTop for MaybeReachable { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 0364c23bfcbe4..7c1ff6fda53f7 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -36,7 +36,7 @@ use std::collections::VecDeque; use std::fmt::{Debug, Formatter}; use std::ops::Range; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -342,8 +342,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. assert!(matches!(state, State::Unreachable)); - let values = StateData::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); - *state = State::Reachable(values); + *state = State::new_reachable(); for arg in body.args_iter() { state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); } @@ -415,30 +414,54 @@ rustc_index::newtype_index!( /// See [`State`]. #[derive(PartialEq, Eq, Debug)] -struct StateData { - map: IndexVec, +pub struct StateData { + bottom: V, + /// This map only contains values that are not `⊥`. + map: FxHashMap, } -impl StateData { - fn from_elem_n(elem: V, n: usize) -> StateData { - StateData { map: IndexVec::from_elem_n(elem, n) } +impl StateData { + fn new() -> StateData { + StateData { bottom: V::BOTTOM, map: FxHashMap::default() } + } + + fn get(&self, idx: ValueIndex) -> &V { + self.map.get(&idx).unwrap_or(&self.bottom) + } + + fn insert(&mut self, idx: ValueIndex, elem: V) { + if elem.is_bottom() { + self.map.remove(&idx); + } else { + self.map.insert(idx, elem); + } } } impl Clone for StateData { fn clone(&self) -> Self { - StateData { map: self.map.clone() } + StateData { bottom: self.bottom.clone(), map: self.map.clone() } } fn clone_from(&mut self, source: &Self) { - // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. - self.map.raw.clone_from(&source.map.raw) + self.map.clone_from(&source.map) } } -impl JoinSemiLattice for StateData { +impl JoinSemiLattice for StateData { fn join(&mut self, other: &Self) -> bool { - self.map.join(&other.map) + let mut changed = false; + #[allow(rustc::potential_query_instability)] + for (i, v) in other.map.iter() { + match self.map.entry(*i) { + StdEntry::Vacant(e) => { + e.insert(v.clone()); + changed = true + } + StdEntry::Occupied(e) => changed |= e.into_mut().join(v), + } + } + changed } } @@ -476,15 +499,19 @@ impl Clone for State { } } -impl State { - pub fn new(init: V, map: &Map) -> State { - State::Reachable(StateData::from_elem_n(init, map.value_count)) +impl State { + pub fn new_reachable() -> State { + State::Reachable(StateData::new()) } - pub fn all(&self, f: impl Fn(&V) -> bool) -> bool { + pub fn all_bottom(&self) -> bool { match self { - State::Unreachable => true, - State::Reachable(ref values) => values.map.iter().all(f), + State::Unreachable => false, + State::Reachable(ref values) => + { + #[allow(rustc::potential_query_instability)] + values.map.values().all(V::is_bottom) + } } } @@ -533,9 +560,7 @@ impl State { value: V, ) { let State::Reachable(values) = self else { return }; - map.for_each_aliasing_place(place, tail_elem, &mut |vi| { - values.map[vi] = value.clone(); - }); + map.for_each_aliasing_place(place, tail_elem, &mut |vi| values.insert(vi, value.clone())); } /// Low-level method that assigns to a place. @@ -556,7 +581,7 @@ impl State { pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { - values.map[value_index] = value; + values.insert(value_index, value) } } @@ -575,7 +600,7 @@ impl State { // already been performed. if let Some(target_value) = map.places[target].value_index { if let Some(source_value) = map.places[source].value_index { - values.map[target_value] = values.map[source_value].clone(); + values.insert(target_value, values.get(source_value).clone()); } } for target_child in map.children(target) { @@ -631,7 +656,7 @@ impl State { pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { match self { State::Reachable(values) => { - map.places[place].value_index.map(|v| values.map[v].clone()) + map.places[place].value_index.map(|v| values.get(v).clone()) } State::Unreachable => None, } @@ -688,7 +713,7 @@ impl State { { match self { State::Reachable(values) => { - map.places[place].value_index.map(|v| values.map[v].clone()).unwrap_or(V::TOP) + map.places[place].value_index.map(|v| values.get(v).clone()).unwrap_or(V::TOP) } State::Unreachable => { // Because this is unreachable, we can return any value we want. @@ -698,7 +723,7 @@ impl State { } } -impl JoinSemiLattice for State { +impl JoinSemiLattice for State { fn join(&mut self, other: &Self) -> bool { match (&mut *self, other) { (_, State::Unreachable) => false, @@ -1228,7 +1253,7 @@ where } } -fn debug_with_context_rec( +fn debug_with_context_rec( place: PlaceIndex, place_str: &str, new: &StateData, @@ -1238,11 +1263,11 @@ fn debug_with_context_rec( ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { match old { - None => writeln!(f, "{}: {:?}", place_str, new.map[value])?, + None => writeln!(f, "{}: {:?}", place_str, new.get(value))?, Some(old) => { - if new.map[value] != old.map[value] { - writeln!(f, "\u{001f}-{}: {:?}", place_str, old.map[value])?; - writeln!(f, "\u{001f}+{}: {:?}", place_str, new.map[value])?; + if new.get(value) != old.get(value) { + writeln!(f, "\u{001f}-{}: {:?}", place_str, old.get(value))?; + writeln!(f, "\u{001f}+{}: {:?}", place_str, new.get(value))?; } } } @@ -1274,7 +1299,7 @@ fn debug_with_context_rec( Ok(()) } -fn debug_with_context( +fn debug_with_context( new: &StateData, old: Option<&StateData>, map: &Map, diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 27e506a920bce..85a61f95ca36f 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -47,6 +47,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; +use rustc_mir_dataflow::lattice::HasBottom; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; use rustc_span::DUMMY_SP; use rustc_target::abi::{TagEncoding, Variants}; @@ -158,9 +159,17 @@ impl Condition { } } -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug)] struct ConditionSet<'a>(&'a [Condition]); +impl HasBottom for ConditionSet<'_> { + const BOTTOM: Self = ConditionSet(&[]); + + fn is_bottom(&self) -> bool { + self.0.is_empty() + } +} + impl<'a> ConditionSet<'a> { fn iter(self) -> impl Iterator + 'a { self.0.iter().copied() @@ -177,7 +186,7 @@ impl<'a> ConditionSet<'a> { impl<'tcx, 'a> TOFinder<'tcx, 'a> { fn is_empty(&self, state: &State>) -> bool { - state.all(|cs| cs.0.is_empty()) + state.all_bottom() } /// Recursion entry point to find threading opportunities. @@ -198,7 +207,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { debug!(?discr); let cost = CostChecker::new(self.tcx, self.param_env, None, self.body); - let mut state = State::new(ConditionSet::default(), self.map); + let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { let value = ScalarInt::try_from_uint(value, discr_layout.size)?; @@ -255,7 +264,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. // _1 = 6 if let Some((lhs, tail)) = self.mutated_statement(stmt) { - state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::default()); + state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::BOTTOM); } } @@ -609,7 +618,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // We can recurse through this terminator. let mut state = state(); if let Some(place_to_flood) = place_to_flood { - state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::default()); + state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::BOTTOM); } self.find_opportunity(bb, state, cost.clone(), depth + 1); } From 8d1065c803a70571538296bdf25101c70d39a100 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:00:43 -0400 Subject: [PATCH 052/189] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 45c1a6d69edfd..f1e49bf7a8ea6 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 45c1a6d69edfd1fc91fb7504cb73958dbd09441e +Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index cb58c430b4e80..941db8b3df45f 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit cb58c430b4e8054c2cb81d2d4434092c482a93d8 +Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c diff --git a/src/doc/reference b/src/doc/reference index 0b805c6580401..1ae3deebc3ac1 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0b805c65804019b0ac8f2fe3117afad82a6069b8 +Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index b1d97bd6113ab..658c6c27cb975 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit b1d97bd6113aba732b2091ce093c76f2d05bb8a0 +Subproject commit 658c6c27cb975b92227936024816986c2d3716fb diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index aec82168dd312..d6e3a32a557db 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit aec82168dd3121289a194b381f56076fc789a4d2 +Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7 From 45b0f68e34c37e5e5f47a1474ad87ebdb099af4b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:02:40 +0000 Subject: [PATCH 053/189] Use the native unwind function in miri where possible --- library/panic_unwind/src/lib.rs | 34 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 4dc3612060848..77abb9125f651 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -36,18 +36,14 @@ use core::panic::PanicPayload; cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] - mod real_imp; + mod imp; } else if #[cfg(target_os = "hermit")] { #[path = "hermit.rs"] - mod real_imp; + mod imp; } else if #[cfg(target_os = "l4re")] { // L4Re is unix family but does not yet support unwinding. #[path = "dummy.rs"] - mod real_imp; - } else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] { - // LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc) - #[path = "seh.rs"] - mod real_imp; + mod imp; } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", @@ -58,7 +54,16 @@ cfg_if::cfg_if! { target_family = "wasm", ))] { #[path = "gcc.rs"] - mod real_imp; + mod imp; + } else if #[cfg(miri)] { + // Use the Miri runtime on Windows as miri doesn't support funclet based unwinding, + // only landingpad based unwinding. Also use the Miri runtime on unsupported platforms. + #[path = "miri.rs"] + mod imp; + } else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] { + // LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc) + #[path = "seh.rs"] + mod imp; } else { // Targets that don't support unwinding. // - os=none ("bare metal" targets) @@ -67,20 +72,7 @@ cfg_if::cfg_if! { // - nvptx64-nvidia-cuda // - arch=avr #[path = "dummy.rs"] - mod real_imp; - } -} - -cfg_if::cfg_if! { - if #[cfg(miri)] { - // Use the Miri runtime. - // We still need to also load the normal runtime above, as rustc expects certain lang - // items from there to be defined. - #[path = "miri.rs"] mod imp; - } else { - // Use the real runtime. - use real_imp as imp; } } From 18049b73ec1c0b899d5ede199ba991f51fd652ed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:40:00 +0000 Subject: [PATCH 054/189] Use the symbol_name query instead of trying to infer from the link_name attribute This prevents the calculated name from going out of sync with exported_symbols. It also avoids having to special case the panic_impl lang item. --- src/tools/miri/src/helpers.rs | 10 +--------- src/tools/miri/src/machine.rs | 4 ++-- src/tools/miri/src/shims/foreign_items.rs | 15 --------------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index a7a6f8cfd8729..590e8984e9908 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::{ FloatTy, IntTy, Ty, TyCtxt, UintTy, }; use rustc_session::config::CrateType; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol}; use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -1182,14 +1182,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap(); } - fn item_link_name(&self, def_id: DefId) -> Symbol { - let tcx = self.eval_context_ref().tcx; - match tcx.get_attrs(def_id, sym::link_name).filter_map(|a| a.value_str()).next() { - Some(name) => name, - None => tcx.item_name(def_id), - } - } - /// Converts `src` from floating point to integer type `dest_ty` /// after rounding with mode `round`. /// Returns `None` if `f` is NaN or out of range. diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 0d91279f9f4c4..e321237bb4a22 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -954,7 +954,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? - let link_name = ecx.item_link_name(instance.def_id()); + let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name); return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); } @@ -1050,7 +1050,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &MiriInterpCx<'tcx>, def_id: DefId, ) -> InterpResult<'tcx, StrictPointer> { - let link_name = ecx.item_link_name(def_id); + let link_name = Symbol::intern(ecx.tcx.symbol_name(Instance::mono(*ecx.tcx, def_id)).name); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { // Various parts of the engine rely on `get_alloc_info` for size and alignment // information. That uses the type information of this static. diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f9ccc6ad4d2f6..9004f7efc8b5e 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -46,24 +46,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - let tcx = this.tcx.tcx; // Some shims forward to other MIR bodies. match link_name.as_str() { - // This matches calls to the foreign item `panic_impl`. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - // We don't use `check_shim` here because we are just forwarding to the lang - // item. Argument count checking will be performed when the returned `Body` is - // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; - let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(( - this.load_mir(panic_impl_instance.def, None)?, - panic_impl_instance, - ))); - } "__rust_alloc_error_handler" => { // Forward to the right symbol that implements this function. let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else { From 9e12d919c3a247299e48d8b0fd71ca502288e443 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 1 Jul 2024 22:41:08 +0200 Subject: [PATCH 055/189] Improve well known value check-cfg diagnostic for the standard library --- .../src/context/diagnostics/check_cfg.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs index c69e680cb64fa..da36f68fca970 100644 --- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -261,10 +261,16 @@ pub(super) fn unexpected_cfg_value( lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } }; - // We don't want to suggest adding values to well known names - // since those are defined by rustc it-self. Users can still - // do it if they want, but should not encourage them. - let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name); + // We don't want to encourage people to add values to a well-known names, as these are + // defined by rustc/Rust itself. Users can still do this if they wish, but should not be + // encouraged to do so. + let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name) + // Except when working on rustc or the standard library itself, in which case we want to + // suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a + // basic heuristic, we use the "cheat" unstable feature enable method and the + // non-ui-testing enabled option. + || (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat) + && !sess.opts.unstable_opts.ui_testing); let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); @@ -275,14 +281,14 @@ pub(super) fn unexpected_cfg_value( } else { Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures) } - } else if !is_cfg_a_well_know_name { + } else if can_suggest_adding_value { Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) } else { None }; lints::unexpected_cfg_value::InvocationHelp::Cargo(help) } else { - let help = if !is_cfg_a_well_know_name { + let help = if can_suggest_adding_value { Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) } else { None From bb4c427ce4f67d8a5b866eb3f40502c47cb2b671 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 1 Jul 2024 18:18:10 -0400 Subject: [PATCH 056/189] Make `FloatTy` checks exhaustive in pretty print This should prevent the default fallback if we add more float types in the future. --- compiler/rustc_middle/src/ty/print/pretty.rs | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 19700353f5944..d2f32cafb9d42 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1710,22 +1710,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Bool if int == ScalarInt::FALSE => p!("false"), ty::Bool if int == ScalarInt::TRUE => p!("true"), // Float - ty::Float(ty::FloatTy::F16) => { - let val = Half::try_from(int).unwrap(); - p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" })) - } - ty::Float(ty::FloatTy::F32) => { - let val = Single::try_from(int).unwrap(); - p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" })) - } - ty::Float(ty::FloatTy::F64) => { - let val = Double::try_from(int).unwrap(); - p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" })) - } - ty::Float(ty::FloatTy::F128) => { - let val = Quad::try_from(int).unwrap(); - p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" })) - } + ty::Float(fty) => match fty { + ty::FloatTy::F16 => { + let val = Half::try_from(int).unwrap(); + p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" })) + } + ty::FloatTy::F32 => { + let val = Single::try_from(int).unwrap(); + p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" })) + } + ty::FloatTy::F64 => { + let val = Double::try_from(int).unwrap(); + p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" })) + } + ty::FloatTy::F128 => { + let val = Quad::try_from(int).unwrap(); + p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" })) + } + }, // Int ty::Uint(_) | ty::Int(_) => { let int = From 09e0abb0d19822455bfc40a8cf31f8fd5a675ba9 Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 1 Jul 2024 20:54:47 +0800 Subject: [PATCH 057/189] Add the definition for `extern "C"` at `cast-target-abi.rs`. --- tests/codegen/cast-target-abi.rs | 382 +++++++++++++++++++++++++++++-- 1 file changed, 358 insertions(+), 24 deletions(-) diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index c6a8b7bbf3786..e5ff64699df95 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength -//@ revisions:aarch64 loongarch64 powerpc64 sparc64 -//@ compile-flags: -O -C no-prepopulate-passes +//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64 +// FIXME: Add `-Cllvm-args=--lint-abort-on-error` after LLVM 19 +//@ compile-flags: -O -C no-prepopulate-passes -C passes=lint //@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu //@[aarch64] needs-llvm-components: arm @@ -10,6 +11,8 @@ //@[powerpc64] needs-llvm-components: powerpc //@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu //@[sparc64] needs-llvm-components: sparc +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 // Tests that arguments with `PassMode::Cast` are handled correctly. @@ -60,30 +63,269 @@ pub struct DoubleFloat { g: f32, } -extern "C" { - fn receives_twou16s(x: TwoU16s); - fn returns_twou16s() -> TwoU16s; +// On x86_64, this struct will be passed as `{ i64, i32 }`. +// The load and store instructions will access 16 bytes, so we should allocate 16 bytes. +#[repr(C)] +pub struct Three32s { + a: u32, + b: u32, + c: u32, +} + +// CHECK-LABEL: @receives_twou16s +// aarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_twou16s(x: TwoU16s) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] - fn receives_fiveu16s(x: FiveU16s); - fn returns_fiveu16s() -> FiveU16s; + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] - fn receives_doubledouble(x: DoubleDouble); - fn returns_doubledouble() -> DoubleDouble; + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) - #[cfg(not(target_arch = "sparc64"))] - fn receives_doublefloat(x: DoubleFloat); - #[cfg(not(target_arch = "sparc64"))] - fn returns_doublefloat() -> DoubleFloat; + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) +} + +// CHECK-LABEL: @returns_twou16s +// powerpc64-SAME: sret([4 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_twou16s() -> TwoU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + TwoU16s { a: 0, b: 1 } +} + +// CHECK-LABEL: @receives_fiveu16s +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_fiveu16s(x: FiveU16s) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) +} + +// CHECK-LABEL: @returns_fiveu16s +// powerpc64-SAME: sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_fiveu16s() -> FiveU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 } +} + +// CHECK-LABEL: @receives_doubledouble +// aarch64-SAME: ([[ABI_TYPE:\[2 x double\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_doubledouble(x: DoubleDouble) { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) +} + +// CHECK-LABEL: @returns_doubledouble +// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_doubledouble() -> DoubleDouble { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + DoubleDouble { f: 0., g: 1. } +} + +// CHECK-LABEL: @receives_three32s +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// sparc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_three32s(x: Three32s) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + + // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) +} + +// CHECK-LABEL: @returns_three32s +// powerpc64-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_three32s() -> Three32s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // sparc64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + Three32s { a: 0, b: 0, c: 0 } +} + +// These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @receives_doublefloat +// loongarch64-LABEL: @receives_doublefloat +// powerpc64-LABEL: @receives_doublefloat +// x86_64-LABEL: @receives_doublefloat + +// aarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// loongarch64-SAME: ([[ABI_TYPE:{ double, float }]] {{.*}}[[ABI_VALUE:%.+]]) +// powerpc64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]]) +// x86_64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn receives_doublefloat(x: DoubleFloat) { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) +} + +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @returns_doublefloat +// loongarch64-LABEL: @returns_doublefloat +// powerpc64-LABEL: @returns_doublefloat +// x86_64-LABEL: @returns_doublefloat + +// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]]) +#[no_mangle] +#[inline(never)] +pub extern "C" fn returns_doublefloat() -> DoubleFloat { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]] + // x86_64: ret [[ABI_TYPE]] [[ABI_VALUE]] + DoubleFloat { f: 0., g: 0. } } // CHECK-LABEL: @call_twou16s #[no_mangle] -pub unsafe fn call_twou16s() { +pub fn call_twou16s() { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] @@ -93,6 +335,7 @@ pub unsafe fn call_twou16s() { // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) let x = TwoU16s { a: 1, b: 2 }; @@ -101,7 +344,7 @@ pub unsafe fn call_twou16s() { // CHECK-LABEL: @return_twou16s #[no_mangle] -pub unsafe fn return_twou16s() -> TwoU16s { +pub fn return_twou16s() -> TwoU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2 @@ -112,34 +355,49 @@ pub unsafe fn return_twou16s() -> TwoU16s { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] // sparc64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) returns_twou16s() } // CHECK-LABEL: @call_fiveu16s #[no_mangle] -pub unsafe fn call_fiveu16s() { - // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] +pub fn call_fiveu16s() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2 // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false) - // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 }; receives_fiveu16s(x); @@ -148,7 +406,7 @@ pub unsafe fn call_fiveu16s() { // CHECK-LABEL: @return_fiveu16s // CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]]) #[no_mangle] -pub unsafe fn return_fiveu16s() -> FiveU16s { +pub fn return_fiveu16s() -> FiveU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) @@ -158,24 +416,28 @@ pub unsafe fn return_fiveu16s() -> FiveU16s { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) returns_fiveu16s() } // CHECK-LABEL: @call_doubledouble #[no_mangle] -pub unsafe fn call_doubledouble() { +pub fn call_doubledouble() { // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] @@ -186,6 +448,7 @@ pub unsafe fn call_doubledouble() { // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) let x = DoubleDouble { f: 1., g: 2. }; @@ -194,7 +457,7 @@ pub unsafe fn call_doubledouble() { // CHECK-LABEL: @return_doubledouble #[no_mangle] -pub unsafe fn return_doubledouble() -> DoubleDouble { +pub fn return_doubledouble() -> DoubleDouble { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 @@ -205,22 +468,27 @@ pub unsafe fn return_doubledouble() -> DoubleDouble { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // sparc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) returns_doubledouble() } @@ -229,27 +497,33 @@ pub unsafe fn return_doubledouble() -> DoubleDouble { // aarch64-LABEL: @call_doublefloat // loongarch64-LABEL: @call_doublefloat // powerpc64-LABEL: @call_doublefloat +// x86_64-LABEL: @call_doublefloat #[no_mangle] -pub unsafe fn call_doublefloat() { +pub fn call_doublefloat() { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // powerpc64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) // powerpc64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // x86_64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) let x = DoubleFloat { f: 1., g: 2. }; receives_doublefloat(x); } @@ -259,8 +533,9 @@ pub unsafe fn call_doublefloat() { // aarch64-LABEL: @return_doublefloat // loongarch64-LABEL: @return_doublefloat // powerpc64-LABEL: @return_doublefloat +// x86_64-LABEL: @return_doublefloat #[no_mangle] -pub unsafe fn return_doublefloat() -> DoubleFloat { +pub fn return_doublefloat() -> DoubleFloat { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8 @@ -270,17 +545,76 @@ pub unsafe fn return_doublefloat() -> DoubleFloat { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] + // x86_64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) returns_doublefloat() } + +// CHECK-LABEL: @call_three32s +#[no_mangle] +pub fn call_three32s() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) + + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = Three32s { a: 1, b: 2, c: 3 }; + receives_three32s(x); +} + +// Regression test for #75839 +// CHECK-LABEL: @return_three32s( +// CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]]) +#[no_mangle] +pub fn return_three32s() -> Three32s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]]) + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() + // x86_64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // x86_64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // x86_64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + returns_three32s() +} From c453dcd62abba536d0580ad9b880b86d46e911ce Mon Sep 17 00:00:00 2001 From: DianQK Date: Sun, 30 Jun 2024 21:33:46 +0800 Subject: [PATCH 058/189] Use the aligned size for alloca at args when the pass mode is cast. The `load` and `store` instructions in LLVM access the aligned size. --- compiler/rustc_codegen_llvm/src/abi.rs | 3 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 8 ++++- tests/codegen/cast-target-abi.rs | 35 +++++-------------- tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 4 +-- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index a6a3f0f964611..d034f9b525690 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -226,7 +226,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // when passed by value, making it smaller. // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes // when passed by value, making it larger. - let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes()); + let copy_bytes = + cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes()); // Allocate some scratch space... let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 57138d3b9dbdb..d4da13068d267 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1540,7 +1540,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // when passed by value, making it smaller. // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes // when passed by value, making it larger. - let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes()); + let copy_bytes = cmp::min(cast.unaligned_size(bx).bytes(), arg.layout.size.bytes()); // Allocate some scratch space... let llscratch = bx.alloca(scratch_size, scratch_align); bx.lifetime_start(llscratch, scratch_size); diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 5713542c17d63..8058130f44151 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -339,7 +339,9 @@ impl CastTarget { } } - pub fn size(&self, _cx: &C) -> Size { + /// When you only access the range containing valid data, you can use this unaligned size; + /// otherwise, use the safer `size` method. + pub fn unaligned_size(&self, _cx: &C) -> Size { // Prefix arguments are passed in specific designated registers let prefix_size = self .prefix @@ -353,6 +355,10 @@ impl CastTarget { prefix_size + rest_size } + pub fn size(&self, cx: &C) -> Size { + self.unaligned_size(cx).align_to(self.align(cx)) + } + pub fn align(&self, cx: &C) -> Align { self.prefix .iter() diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index e5ff64699df95..13b74d68f76e4 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -128,11 +128,7 @@ pub extern "C" fn returns_twou16s() -> TwoU16s { #[no_mangle] #[inline(never)] pub extern "C" fn receives_fiveu16s(x: FiveU16s) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]] @@ -218,11 +214,7 @@ pub extern "C" fn returns_doubledouble() -> DoubleDouble { #[no_mangle] #[inline(never)] pub extern "C" fn receives_three32s(x: Three32s) { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] @@ -271,7 +263,7 @@ pub extern "C" fn returns_three32s() -> Three32s { #[inline(never)] pub extern "C" fn receives_doublefloat(x: DoubleFloat) { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] @@ -382,11 +374,7 @@ pub fn return_twou16s() -> TwoU16s { // CHECK-LABEL: @call_fiveu16s #[no_mangle] pub fn call_fiveu16s() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2 @@ -416,7 +404,7 @@ pub fn return_fiveu16s() -> FiveU16s { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s() @@ -501,7 +489,7 @@ pub fn return_doubledouble() -> DoubleDouble { #[no_mangle] pub fn call_doublefloat() { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] @@ -544,7 +532,7 @@ pub fn return_doublefloat() -> DoubleFloat { // The other targets copy the cast ABI type to an alloca. // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]] @@ -568,12 +556,7 @@ pub fn return_doublefloat() -> DoubleFloat { // CHECK-LABEL: @call_three32s #[no_mangle] pub fn call_three32s() { - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] - + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]] // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) @@ -600,7 +583,7 @@ pub fn return_three32s() -> Three32s { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s() diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index 614d5d94f6208..a4b7c0caa6d46 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -1,5 +1,5 @@ //@ revisions: linux apple -//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes +//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes -C passes=lint //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 @@ -36,7 +36,7 @@ extern "C" { pub fn test() { let s = S { f1: 1, f2: 2, f3: 3 }; unsafe { - // CHECK: [[ALLOCA:%.+]] = alloca [12 x i8], align 8 + // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8 // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8 // CHECK: call void @foo({ i64, i32 } [[LOAD]]) foo(s); From 2ef82805d52a2f53368a56e8d3c9473f3cd89efc Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 1 Jul 2024 13:15:40 +0800 Subject: [PATCH 059/189] Use the aligned size for alloca at ret when the pass mode is cast. --- compiler/rustc_codegen_ssa/src/mir/mod.rs | 18 +++++++++++++---- compiler/rustc_codegen_ssa/src/mir/place.rs | 10 +++++++++- tests/codegen/cast-target-abi.rs | 22 ++++++++++----------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index e8da98428829e..61f57c9030a1a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -230,10 +230,20 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); - if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { - debug!("alloc: {:?} (return place) -> place", local); - let llretptr = start_bx.get_param(0); - return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); + if local == mir::RETURN_PLACE { + match fx.fn_abi.ret.mode { + PassMode::Indirect { .. } => { + debug!("alloc: {:?} (return place) -> place", local); + let llretptr = start_bx.get_param(0); + return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); + } + PassMode::Cast { ref cast, .. } => { + debug!("alloc: {:?} (return place) -> place", local); + let size = cast.size(&start_bx); + return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout)); + } + _ => {} + }; } if memory_locals.contains(local) { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 449fd9ae0db9c..97d5bb8312891 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -108,9 +108,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn alloca>( bx: &mut Bx, layout: TyAndLayout<'tcx>, + ) -> Self { + Self::alloca_size(bx, layout.size, layout) + } + + pub fn alloca_size>( + bx: &mut Bx, + size: Size, + layout: TyAndLayout<'tcx>, ) -> Self { assert!(layout.is_sized(), "tried to statically allocate unsized place"); - PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout) + PlaceValue::alloca(bx, size, layout.align.abi).with_type(layout) } /// Returns a place for an indirect reference to an unsized place. diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index 13b74d68f76e4..34e52d38bbea9 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -102,9 +102,9 @@ pub extern "C" fn returns_twou16s() -> TwoU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]] // x86_64: [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]] // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] @@ -145,10 +145,10 @@ pub extern "C" fn returns_fiveu16s() -> FiveU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [10 x i8], align [[ABI_ALIGN:2]] + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]] // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] @@ -231,10 +231,10 @@ pub extern "C" fn returns_three32s() -> Three32s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. // The other targets copy the cast ABI type to an alloca. - // aarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] - // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] - // x86_64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:4]] + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] + // x86_64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]] // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] From 16fc41cedc5f81a4ecba7bfaa9f408d41ca87f62 Mon Sep 17 00:00:00 2001 From: mat Date: Mon, 1 Jul 2024 22:36:40 +0000 Subject: [PATCH 060/189] Optimize SipHash by reordering compress instructions --- compiler/rustc_data_structures/src/sip128.rs | 11 ++++++----- library/core/src/hash/sip.rs | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index fed23df10dcf4..812ed410a94b6 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -70,18 +70,19 @@ macro_rules! compress { ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }}; ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ $v0 = $v0.wrapping_add($v1); + $v2 = $v2.wrapping_add($v3); $v1 = $v1.rotate_left(13); $v1 ^= $v0; - $v0 = $v0.rotate_left(32); - $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2; - $v0 = $v0.wrapping_add($v3); - $v3 = $v3.rotate_left(21); - $v3 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v1); + $v0 = $v0.wrapping_add($v3); $v1 = $v1.rotate_left(17); $v1 ^= $v2; + $v3 = $v3.rotate_left(21); + $v3 ^= $v0; $v2 = $v2.rotate_left(32); }}; } diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 78a232faaf88c..0d1ac64aa56cf 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -76,18 +76,19 @@ macro_rules! compress { ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }}; ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ $v0 = $v0.wrapping_add($v1); + $v2 = $v2.wrapping_add($v3); $v1 = $v1.rotate_left(13); $v1 ^= $v0; - $v0 = $v0.rotate_left(32); - $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2; - $v0 = $v0.wrapping_add($v3); - $v3 = $v3.rotate_left(21); - $v3 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v1); + $v0 = $v0.wrapping_add($v3); $v1 = $v1.rotate_left(17); $v1 ^= $v2; + $v3 = $v3.rotate_left(21); + $v3 ^= $v0; $v2 = $v2.rotate_left(32); }}; } From 06982239a6210cfc7b0b370634c9a9160c9b9dc4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 23 Jun 2024 16:58:15 -0700 Subject: [PATCH 061/189] Parenthesize break values containing leading label --- compiler/rustc_ast/src/util/classify.rs | 79 ++++++++++++++++++- .../rustc_ast_pretty/src/pprust/state/expr.rs | 8 +- .../ui/unpretty/expanded-interpolation.stdout | 4 +- 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 4b2544ac47ed8..541b95ea97160 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -1,7 +1,8 @@ //! Routines the parser and pretty-printer use to classify AST nodes. use crate::ast::ExprKind::*; -use crate::{ast, token::Delimiter}; +use crate::ast::{self, MatchKind}; +use crate::token::Delimiter; /// This classification determines whether various syntactic positions break out /// of parsing the current expression (true) or continue parsing more of the @@ -81,6 +82,82 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { } } +/// Returns whether the leftmost token of the given expression is the label of a +/// labeled loop or block, such as in `'inner: loop { break 'inner 1 } + 1`. +/// +/// Such expressions are not allowed as the value of an unlabeled break. +/// +/// ```ignore (illustrative) +/// 'outer: { +/// break 'inner: loop { break 'inner 1 } + 1; // invalid syntax +/// +/// break 'outer 'inner: loop { break 'inner 1 } + 1; // okay +/// +/// break ('inner: loop { break 'inner 1 } + 1); // okay +/// +/// break ('inner: loop { break 'inner 1 }) + 1; // okay +/// } +/// ``` +pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { + loop { + match &expr.kind { + Block(_, label) | ForLoop { label, .. } | Loop(_, label, _) | While(_, _, label) => { + return label.is_some(); + } + + Assign(e, _, _) + | AssignOp(_, e, _) + | Await(e, _) + | Binary(_, e, _) + | Call(e, _) + | Cast(e, _) + | Field(e, _) + | Index(e, _, _) + | Match(e, _, MatchKind::Postfix) + | Range(Some(e), _, _) + | Try(e) => { + expr = e; + } + MethodCall(method_call) => { + expr = &method_call.receiver; + } + + AddrOf(..) + | Array(..) + | Become(..) + | Break(..) + | Closure(..) + | ConstBlock(..) + | Continue(..) + | FormatArgs(..) + | Gen(..) + | If(..) + | IncludedBytes(..) + | InlineAsm(..) + | Let(..) + | Lit(..) + | MacCall(..) + | Match(_, _, MatchKind::Prefix) + | OffsetOf(..) + | Paren(..) + | Path(..) + | Range(None, _, _) + | Repeat(..) + | Ret(..) + | Struct(..) + | TryBlock(..) + | Tup(..) + | Type(..) + | Unary(..) + | Underscore + | Yeet(..) + | Yield(..) + | Err(..) + | Dummy => return false, + } + } +} + pub enum TrailingBrace<'a> { /// Trailing brace in a macro call, like the one in `x as *const brace! {}`. /// We will suggest changing the macro call to a different delimiter. diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 1e117c46b6e29..86b6b0e219928 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -5,6 +5,7 @@ use ast::{ForLoopKind, MatchKind}; use itertools::{Itertools, Position}; use rustc_ast::ptr::P; use rustc_ast::token; +use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode}; @@ -610,9 +611,12 @@ impl<'a> State<'a> { } if let Some(expr) = opt_expr { self.space(); - self.print_expr_maybe_paren( + self.print_expr_cond_paren( expr, - parser::PREC_JUMP, + // Parenthesize if required by precedence, or in the + // case of `break 'inner: loop { break 'inner 1 } + 1` + expr.precedence().order() < parser::PREC_JUMP + || (opt_label.is_none() && classify::leading_labeled_expr(expr)), fixup.subsequent_subexpression(), ); } diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout index ed075c9114ce6..556e57dbd9210 100644 --- a/tests/ui/unpretty/expanded-interpolation.stdout +++ b/tests/ui/unpretty/expanded-interpolation.stdout @@ -25,12 +25,12 @@ fn break_labeled_loop() { 'outer: loop { break 'outer 'inner: loop { break 'inner 1; } + 1; }; let paren_around_break_value = - 'outer: loop { break 'inner: loop { break 'inner 1; } + 1; }; + 'outer: loop { break ('inner: loop { break 'inner 1; } + 1); }; macro_rules! breaking { ($value:expr) => { break $value }; } let paren_around_break_value = - loop { break 'inner: loop { break 'inner 1; } + 1; }; + loop { break ('inner: loop { break 'inner 1; } + 1); }; } fn if_let() { From 1680b791d57013ca2cf5839a279e3d4d826c336c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:33:46 +1000 Subject: [PATCH 062/189] Simplify `CfgEval`. It can contain an owned value instead of a reference. --- compiler/rustc_builtin_macros/src/cfg_eval.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 03aff6f96330e..884cebf1939e4 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -38,16 +38,14 @@ pub(crate) fn cfg_eval( lint_node_id: NodeId, ) -> Annotatable { let features = Some(features); - CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } } + CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id }) .configure_annotatable(annotatable) // Since the item itself has already been configured by the `InvocationCollector`, // we know that fold result vector will contain exactly one element. .unwrap() } -struct CfgEval<'a, 'b> { - cfg: &'a mut StripUnconfigured<'b>, -} +struct CfgEval<'a>(StripUnconfigured<'a>); fn flat_map_annotatable( vis: &mut impl MutVisitor, @@ -125,9 +123,9 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { res.is_break() } -impl CfgEval<'_, '_> { +impl CfgEval<'_> { fn configure(&mut self, node: T) -> Option { - self.cfg.configure(node) + self.0.configure(node) } fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option { @@ -196,7 +194,7 @@ impl CfgEval<'_, '_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); + let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, @@ -212,16 +210,16 @@ impl CfgEval<'_, '_> { } } -impl MutVisitor for CfgEval<'_, '_> { +impl MutVisitor for CfgEval<'_> { #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr, false); + self.0.configure_expr(expr, false); mut_visit::noop_visit_expr(expr, self); } #[instrument(level = "trace", skip(self))] fn visit_method_receiver_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr, true); + self.0.configure_expr(expr, true); mut_visit::noop_visit_expr(expr, self); } From d6c0b8117e4ccccd83c4a6e70eee8b12c51d1a18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:34:05 +1000 Subject: [PATCH 063/189] Fix a typo in a comment. --- 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 b5480b6b7d210..4b1531c5ff3e4 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -340,7 +340,7 @@ impl<'a> Parser<'a> { // If we support tokens at all if let Some(target_tokens) = ret.tokens_mut() { if target_tokens.is_none() { - // Store se our newly captured tokens into the AST node + // Store our newly captured tokens into the AST node. *target_tokens = Some(tokens.clone()); } } From f852568fa601171f20f924a50478c33fd2661fba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:42:46 +1000 Subject: [PATCH 064/189] Change `AttrTokenStream::to_tokenstream` to `to_token_trees`. I.e. change the return type from `TokenStream` to `Vec`. Most of the callsites require a `TokenStream`, but the recursive call used to create `target_tokens` requires a `Vec`. It's easy to convert a `Vec` to a `TokenStream` (just call `TokenStream::new`) but it's harder to convert a `TokenStream` to a `Vec` (either iterate/clone/collect, or use `Lrc::into_inner` if appropriate). So this commit changes the return value to simplify that `target_tokens` call site. --- compiler/rustc_ast/src/attr/mod.rs | 14 ++++++++------ compiler/rustc_ast/src/tokenstream.rs | 23 +++++++---------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 593c78df3cdb8..65f1b5dbaf5b7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -204,12 +204,14 @@ impl Attribute { pub fn tokens(&self) -> TokenStream { match &self.kind { - AttrKind::Normal(normal) => normal - .tokens - .as_ref() - .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) - .to_attr_token_stream() - .to_tokenstream(), + AttrKind::Normal(normal) => TokenStream::new( + normal + .tokens + .as_ref() + .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) + .to_attr_token_stream() + .to_token_trees(), + ), &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( token::DocComment(comment_kind, self.style, data), self.span, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index b4ddbe20689e2..5b2d673316a52 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -180,14 +180,13 @@ impl AttrTokenStream { AttrTokenStream(Lrc::new(tokens)) } - /// Converts this `AttrTokenStream` to a plain `TokenStream`. + /// Converts this `AttrTokenStream` to a plain `Vec`. /// During conversion, `AttrTokenTree::Attributes` get 'flattened' /// back to a `TokenStream` of the form `outer_attr attr_target`. /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. - pub fn to_tokenstream(&self) -> TokenStream { - let trees: Vec<_> = self - .0 + pub fn to_token_trees(&self) -> Vec { + self.0 .iter() .flat_map(|tree| match &tree { AttrTokenTree::Token(inner, spacing) => { @@ -198,7 +197,7 @@ impl AttrTokenStream { *span, *spacing, *delim, - stream.to_tokenstream() + TokenStream::new(stream.to_token_trees()) ),] .into_iter() } @@ -208,14 +207,7 @@ impl AttrTokenStream { .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); - let mut target_tokens: Vec<_> = data - .tokens - .to_attr_token_stream() - .to_tokenstream() - .0 - .iter() - .cloned() - .collect(); + let mut target_tokens = data.tokens.to_attr_token_stream().to_token_trees(); if !inner_attrs.is_empty() { let mut found = false; // Check the last two trees (to account for a trailing semi) @@ -260,8 +252,7 @@ impl AttrTokenStream { flat.into_iter() } }) - .collect(); - TokenStream::new(trees) + .collect() } } @@ -461,7 +452,7 @@ impl TokenStream { AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) }; - attr_stream.to_tokenstream() + TokenStream::new(attr_stream.to_token_trees()) } pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { From 0cfd2473be4a5555018cfbca089a7ed1bfd16c53 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:49:12 +1000 Subject: [PATCH 065/189] Rename `TokenStream::new` argument. `tts` is a better name than `streams` for a `Vec`. --- compiler/rustc_ast/src/tokenstream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 5b2d673316a52..cabf18fd1530a 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -400,8 +400,8 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { - TokenStream(Lrc::new(streams)) + pub fn new(tts: Vec) -> TokenStream { + TokenStream(Lrc::new(tts)) } pub fn is_empty(&self) -> bool { From 7416c20cfd781de5608494d67975be94e8689c24 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 11:15:38 +1000 Subject: [PATCH 066/189] Just `push` in `AttrTokenStream::to_token_trees`. Currently it uses a mixture of functional style (`flat_map`) and imperative style (`push`), which is a bit hard to read. This commit converts it to fully imperative, which is more concise and avoids the need for `smallvec`. --- compiler/rustc_ast/src/tokenstream.rs | 28 ++++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index cabf18fd1530a..655c18e45597a 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -23,7 +23,6 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::{cmp, fmt, iter}; @@ -186,20 +185,19 @@ impl AttrTokenStream { /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. pub fn to_token_trees(&self) -> Vec { - self.0 - .iter() - .flat_map(|tree| match &tree { + let mut res = Vec::with_capacity(self.0.len()); + for tree in self.0.iter() { + match tree { AttrTokenTree::Token(inner, spacing) => { - smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter() + res.push(TokenTree::Token(inner.clone(), *spacing)); } AttrTokenTree::Delimited(span, spacing, delim, stream) => { - smallvec![TokenTree::Delimited( + res.push(TokenTree::Delimited( *span, *spacing, *delim, - TokenStream::new(stream.to_token_trees()) - ),] - .into_iter() + TokenStream::new(stream.to_token_trees()), + )) } AttrTokenTree::Attributes(data) => { let idx = data @@ -243,16 +241,14 @@ impl AttrTokenStream { "Failed to find trailing delimited group in: {target_tokens:?}" ); } - let mut flat: SmallVec<[_; 1]> = - SmallVec::with_capacity(target_tokens.len() + outer_attrs.len()); for attr in outer_attrs { - flat.extend(attr.tokens().0.iter().cloned()); + res.extend(attr.tokens().0.iter().cloned()); } - flat.extend(target_tokens); - flat.into_iter() + res.extend(target_tokens); } - }) - .collect() + } + } + res } } From 36c30a968b60a2926a0f600feb78eaba618d8d9a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 14:32:47 +1000 Subject: [PATCH 067/189] Fix comment. Both the indenting, and the missing `)`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 4b1531c5ff3e4..a5aaa9f052208 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -233,9 +233,9 @@ impl<'a> Parser<'a> { // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`) // so there's nothing for us to do. // 2. Our target already has tokens set (e.g. we've parsed something - // like `#[my_attr] $item`. The actual parsing code takes care of prepending - // any attributes to the nonterminal, so we don't need to modify the - // already captured tokens. + // like `#[my_attr] $item`). The actual parsing code takes care of + // prepending any attributes to the nonterminal, so we don't need to + // modify the already captured tokens. // Note that this check is independent of `force_collect`- if we already // have tokens, or can't even store them, then there's never a need to // force collection of new tokens. From 2342770f49dcc7e98069efb2db3620d4803c7698 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:50:06 +1000 Subject: [PATCH 068/189] Flip an if/else in `AttrTokenStream::to_attr_token_stream`. To put the simple case first. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index a5aaa9f052208..244a4f26fba85 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -112,7 +112,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { })) .take(self.num_calls); - if !self.replace_ranges.is_empty() { + if self.replace_ranges.is_empty() { + make_token_stream(tokens, self.break_last_token) + } else { let mut tokens: Vec<_> = tokens.collect(); let mut replace_ranges = self.replace_ranges.to_vec(); replace_ranges.sort_by_key(|(range, _)| range.start); @@ -165,8 +167,6 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { ); } make_token_stream(tokens.into_iter(), self.break_last_token) - } else { - make_token_stream(tokens, self.break_last_token) } } } From 8b5a7eb7f4840dcc27e1dcf4a0e102a417ad988f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:12:22 +1000 Subject: [PATCH 069/189] Move things around in `collect_tokens_trailing_token`. So that the `capturing` state is adjusted immediately before and after the call to `f`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 244a4f26fba85..7c22cac350b02 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -218,16 +218,16 @@ impl<'a> Parser<'a> { let start_token = (self.token.clone(), self.token_spacing); let cursor_snapshot = self.token_cursor.clone(); let start_pos = self.num_bump_calls; - let has_outer_attrs = !attrs.attrs.is_empty(); - let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let replace_ranges_start = self.capture_state.replace_ranges.len(); - let ret = f(self, attrs.attrs); - - self.capture_state.capturing = prev_capturing; - - let (mut ret, trailing) = ret?; + let (mut ret, trailing) = { + let prev_capturing = + std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); + let ret_and_trailing = f(self, attrs.attrs); + self.capture_state.capturing = prev_capturing; + ret_and_trailing? + }; // When we're not in `capture-cfg` mode, then bail out early if: // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`) From f5b28968db07c96d1e2fe239d380fe5a418e85c5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:21:47 +1000 Subject: [PATCH 070/189] Move more things around in `collect_tokens_trailing_token`. To make things a little clearer, and to avoid some `mut` variables. --- .../rustc_parse/src/parser/attr_wrapper.rs | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 7c22cac350b02..10feccd21e286 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -276,37 +276,32 @@ impl<'a> Parser<'a> { let replace_ranges_end = self.capture_state.replace_ranges.len(); - let mut end_pos = self.num_bump_calls; - - let mut captured_trailing = false; - // Capture a trailing token if requested by the callback 'f' - match trailing { - TrailingToken::None => {} + let captured_trailing = match trailing { + TrailingToken::None => false, TrailingToken::Gt => { assert_eq!(self.token.kind, token::Gt); + false } TrailingToken::Semi => { assert_eq!(self.token.kind, token::Semi); - end_pos += 1; - captured_trailing = true; + true } - TrailingToken::MaybeComma => { - if self.token.kind == token::Comma { - end_pos += 1; - captured_trailing = true; - } - } - } + TrailingToken::MaybeComma => self.token.kind == token::Comma, + }; - // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), - // then extend the range of captured tokens to include it, since the parser - // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted - // into an `AttrTokenStream`, we will create the proper token. - if self.break_last_token { - assert!(!captured_trailing, "Cannot set break_last_token and have trailing token"); - end_pos += 1; - } + assert!( + !(self.break_last_token && captured_trailing), + "Cannot set break_last_token and have trailing token" + ); + + let end_pos = self.num_bump_calls + + captured_trailing as usize + // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then + // extend the range of captured tokens to include it, since the parser was not actually + // bumped past it. When the `LazyAttrTokenStream` gets converted into an + // `AttrTokenStream`, we will create the proper token. + + self.break_last_token as usize; let num_calls = end_pos - start_pos; From ada9fda7c38b1be39b4e8273ee6af150985df064 Mon Sep 17 00:00:00 2001 From: hattizai Date: Tue, 2 Jul 2024 11:25:31 +0800 Subject: [PATCH 071/189] chore: remove duplicate words --- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_const_eval/src/interpret/discriminant.rs | 2 +- compiler/rustc_hir_typeck/src/method/suggest.rs | 4 ++-- compiler/rustc_middle/src/ty/closure.rs | 2 +- compiler/rustc_mir_build/src/build/expr/as_place.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_serialize/src/opaque.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 2 +- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 2 +- library/core/src/clone.rs | 2 +- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/num/dec2flt/lemire.rs | 2 +- library/std/src/io/error/repr_bitpacked.rs | 2 +- library/std/src/sys/pal/unix/args.rs | 2 +- library/std/src/sys/pal/windows/alloc.rs | 2 +- src/tools/clippy/clippy_lints/src/empty_with_brackets.rs | 4 ++-- src/tools/clippy/clippy_lints/src/non_copy_const.rs | 2 +- .../2229_closure_analysis/migrations/precise_no_migrations.rs | 4 ++-- .../116464-invalid-assoc-type-suggestion-in-trait-impl.rs | 2 +- 23 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b1c22faf1ae9d..a26359942a614 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -403,7 +403,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // Why only in unoptimized builds? // - In unoptimized builds LLVM uses FastISel which does not support switches, so it - // must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives + // must fall back to the slower SelectionDAG isel. Therefore, using `br` gives // significant compile time speedups for unoptimized builds. // - In optimized builds the above doesn't hold, and using `br` sometimes results in // worse generated code because LLVM can no longer tell that the value being switched diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index b3a139d553ade..181c71153866c 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -245,7 +245,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The tag of a `Single` enum is like the tag of the niched // variant: there's no tag as the discriminant is encoded // entirely implicitly. If `write_discriminant` ever hits this - // case, we do a "validation read" to ensure the the right + // case, we do a "validation read" to ensure the right // discriminant is encoded implicitly, so any attempt to write // the wrong discriminant for a `Single` enum will reliably // result in UB. diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e310730bf9e91..72efe86b84170 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -499,7 +499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // If the shadowed binding has an an itializer expression, + // If the shadowed binding has an itializer expression, // use the initializer expression'ty to try to find the method again. // For example like: `let mut x = Vec::new();`, // `Vec::new()` is the itializer expression. @@ -968,7 +968,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Make sure that, if any traits other than the found ones were involved, - // we don't don't report an unimplemented trait. + // we don't report an unimplemented trait. // We don't want to say that `iter::Cloned` is not an iterator, just // because of some non-Clone item being iterated over. for (predicate, _parent_pred, _cause) in unsatisfied_predicates { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index bade0d564156f..bdd9a6bab2bee 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -237,7 +237,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of /// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. /// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. -/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// 2. Since we only look at the projections here function will return `bar.x` as a valid /// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections /// list are being applied to the same root variable. pub fn is_ancestor_or_same_capture( diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 4b62afa61bbd5..91a3b53cc79c7 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -130,7 +130,7 @@ fn convert_to_hir_projections_and_truncate_for_capture( /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of /// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. /// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. -/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// 2. Since we only look at the projections here function will return `bar.x` as a valid /// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections /// list are being applied to the same root variable. fn is_ancestor_or_same_capture( diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 8c6c9e10cdfdc..5745dc0969cce 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -138,7 +138,7 @@ impl<'tcx> ConstToPat<'tcx> { // lints, but no errors), double-check that all types in the const implement // `PartialEq`. Even if we have a valtree, we may have found something // in there with non-structural-equality, meaning we match using `PartialEq` - // and we hence have to check that that impl exists. + // and we hence have to check if that impl exists. // This is all messy but not worth cleaning up: at some point we'll emit // a hard error when we don't have a valtree or when we find something in // the valtree that is not structural; then this can all be made a lot simpler. diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 3dbdeb615cfe2..2b7d9be6d350b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -8,7 +8,7 @@ //! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values. //! //! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available -//! values, the locals in which they are stored, and a the assignment location. +//! values, the locals in which they are stored, and the assignment location. //! //! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each //! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index f7056702cb4ed..5d253d7384df4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -519,7 +519,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &add_subtyping_projections::Subtyper, // calling this after reveal_all ensures that we don't deal with opaque types &elaborate_drops::ElaborateDrops, // This will remove extraneous landing pads which are no longer - // necessary as well as well as forcing any call in a non-unwinding + // necessary as well as forcing any call in a non-unwinding // function calling a possibly-unwinding function to abort the process. &abort_unwinding_calls::AbortUnwindingCalls, // AddMovesForPackedDrops needs to run after drop diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 3f4d2b65ff240..736647fb64b12 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -816,7 +816,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { mut func, mut args, call_source: desugar, fn_span, .. } => { // This promoted involves a function call, so it may fail to evaluate. - // Let's make sure it is added to `required_consts` so that that failure cannot get lost. + // Let's make sure it is added to `required_consts` so that failure cannot get lost. self.add_to_required = true; self.visit_operand(&mut func, loc); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bbd586386dd27..6ea0ed339a66e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -102,7 +102,7 @@ fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { Publicness::new(true, true) } -/// Determine if a work from the worklist is coming from the a `#[allow]` +/// Determine if a work from the worklist is coming from a `#[allow]` /// or a `#[expect]` of `dead_code` #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] enum ComesFromAllowExpect { diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 1dcb69920d73e..d27dfd888245b 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -155,7 +155,7 @@ impl FileEncoder { if std::intrinsics::unlikely(self.buffered > flush_threshold) { self.flush(); } - // SAFETY: We checked above that that N < self.buffer_empty().len(), + // SAFETY: We checked above that N < self.buffer_empty().len(), // and if isn't, flush ensures that our empty buffer is now BUF_SIZE. // We produce a post-mono error if N > BUF_SIZE. let buf = unsafe { self.buffer_empty().first_chunk_mut::().unwrap_unchecked() }; 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 ccf86dbb1d0b6..a0a8e5963f109 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4114,7 +4114,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expr = binding_expr; } if let hir::Node::Param(param) = parent { - // ...and it is a an fn argument. + // ...and it is an fn argument. let prev_ty = self.resolve_vars_if_possible( typeck_results .node_type_opt(param.hir_id) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index adf1076a7c90e..3e316b7845439 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1296,7 +1296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expr = binding_expr; } if let hir::Node::Param(_param) = parent { - // ...and it is a an fn argument. + // ...and it is an fn argument. break; } } diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index d7ce65f6c53a9..939b2be6dfaf1 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -230,7 +230,7 @@ pub struct AssertParamIsCopy { pub unsafe trait CloneToUninit { /// Performs copy-assignment from `self` to `dst`. /// - /// This is analogous to to `std::ptr::write(dst, self.clone())`, + /// This is analogous to `std::ptr::write(dst, self.clone())`, /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). /// /// Before this function is called, `dst` may point to uninitialized memory. diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 05a5f2689056b..1bde4488cc9de 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -159,7 +159,7 @@ pub(crate) struct GenericShunt<'a, I, R> { residual: &'a mut Option, } -/// Process the given iterator as if it yielded a the item's `Try::Output` +/// Process the given iterator as if it yielded the item's `Try::Output` /// type instead. Any `Try::Residual`s encountered will stop the inner iterator /// and be propagated back to the overall result. pub(crate) fn try_process(iter: I, mut f: F) -> ChangeOutputType diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs index 3bc052df7a6c1..01642e1b1112a 100644 --- a/library/core/src/num/dec2flt/lemire.rs +++ b/library/core/src/num/dec2flt/lemire.rs @@ -157,7 +157,7 @@ fn compute_product_approx(q: i64, w: u64, precision: usize) -> (u64, u64) { // Need to do a second multiplication to get better precision // for the lower product. This will always be exact // where q is < 55, since 5^55 < 2^128. If this wraps, - // then we need to need to round up the hi product. + // then we need to round up the hi product. let (_, second_hi) = full_multiplication(w, hi5); first_lo = first_lo.wrapping_add(second_hi); if second_hi > first_lo { diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index c9d3934ad70ce..a5cefe2292be4 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -28,7 +28,7 @@ //! //! # Layout //! Tagged values are 64 bits, with the 2 least significant bits used for the -//! tag. This means there are there are 4 "variants": +//! tag. This means there are 4 "variants": //! //! - **Tag 0b00**: The first variant is equivalent to //! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly. diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index db2ec73148e38..e2ec838b740cb 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -183,7 +183,7 @@ mod imp { // Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms. // // Even though these have underscores in their names, they've been available -// since since the first versions of both macOS and iOS, and are declared in +// since the first versions of both macOS and iOS, and are declared in // the header `crt_externs.h`. // // NOTE: This header was added to the iOS 13.0 SDK, which has been the source diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 681d1a5efe932..24c237b5eb03d 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -190,7 +190,7 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { // it, it is safe to write a header directly before it. unsafe { ptr::write((aligned as *mut Header).sub(1), Header(ptr)) }; - // SAFETY: The returned pointer does not point to the to the start of an allocated block, + // SAFETY: The returned pointer does not point to the start of an allocated block, // but there is a header readable directly before it containing the location of the start // of the block. aligned diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs index 745599b0e57a2..743ec5b9ea7fb 100644 --- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// and it may be desirable to do so consistently for style. /// /// However, removing the brackets also introduces a public constant named after the struct, - /// so this is not just a syntactic simplification but an an API change, and adding them back + /// so this is not just a syntactic simplification but an API change, and adding them back /// is a *breaking* API change. /// /// ### Example @@ -44,7 +44,7 @@ declare_clippy_lint! { /// and it may be desirable to do so consistently for style. /// /// However, removing the brackets also introduces a public constant named after the variant, - /// so this is not just a syntactic simplification but an an API change, and adding them back + /// so this is not just a syntactic simplification but an API change, and adding them back /// is a *breaking* API change. /// /// ### Example diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 5cb8e7bfab2a9..964d199bfcb69 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -258,7 +258,7 @@ impl<'tcx> NonCopyConst<'tcx> { // e.g. implementing `has_frozen_variant` described above, and not running this function // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with the a frozen variant) (e.g. borrowing + // similar to 2., but with a frozen variant) (e.g. borrowing // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). matches!(err, ErrorHandled::TooGeneric(..)) diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs index f46ec4b927aca..4da8703857740 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs +++ b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs @@ -48,7 +48,7 @@ impl Drop for ContainsAndImplsDrop { } // If a path isn't directly captured but requires Drop, then this tests that migrations aren't -// needed if the a parent to that path is captured. +// needed if the parent to that path is captured. fn test_precise_analysis_parent_captured_1() { let t = ConstainsDropField(Foo(10), Foo(20)); @@ -60,7 +60,7 @@ fn test_precise_analysis_parent_captured_1() { } // If a path isn't directly captured but requires Drop, then this tests that migrations aren't -// needed if the a parent to that path is captured. +// needed if the parent to that path is captured. fn test_precise_analysis_parent_captured_2() { let t = ContainsAndImplsDrop(Foo(10)); diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs index 445ea2de610fd..52b488101a8b0 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs @@ -11,7 +11,7 @@ impl Trait for i32 { type Assoc = String; } -// Should not not trigger suggestion here... +// Should not trigger suggestion here... impl Trait for () {} //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied From b998cff5582b819910cc8e0f092c15151b930d02 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 2 Jul 2024 06:04:23 +0000 Subject: [PATCH 072/189] Use `cfg!(windows)` --- src/bootstrap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 6d00ff9982d96..f5941e31e251f 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1678,7 +1678,7 @@ impl Build { return; } if let Err(e) = fs::remove_file(dst) { - if e.kind() != io::ErrorKind::NotFound { + if cfg!(windows) && e.kind() != io::ErrorKind::NotFound { // workaround for https://github.com/rust-lang/rust/issues/127126 // if removing the file fails, attempt to rename it instead. let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)); From 3e44883606ad4df77018c157971ba7a47e540088 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2024 08:21:44 +0200 Subject: [PATCH 073/189] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index fd59ad3b8f130..912aa11ded053 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9ed2ab3790ff41bf741dd690befd6a1c1e2b23ca +7d97c59438e933e86f557ed999da3b8dfc6855a7 From 3d750e270279d2d8689aee3ee5cdbf60faec42bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 16:31:24 +1000 Subject: [PATCH 074/189] Shrink parser positions from `usize` to `u32`. The number of source code bytes can't exceed a `u32`'s range, so a token position also can't. This reduces the size of `Parser` and `LazyAttrTokenStreamImpl` by eight bytes each. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 12 +++++------ compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 4 ++-- .../rustc_parse/src/parser/attr_wrapper.rs | 21 ++++++++----------- compiler/rustc_parse/src/parser/mod.rs | 6 +++--- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index bf475c1dc96ff..2df8b8f00f862 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -120,21 +120,21 @@ struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { struct BestFailure { token: Token, - position_in_tokenstream: usize, + position_in_tokenstream: u32, msg: &'static str, remaining_matcher: MatcherLoc, } impl BestFailure { - fn is_better_position(&self, position: usize) -> bool { + fn is_better_position(&self, position: u32) -> bool { position > self.position_in_tokenstream } } impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { - type Failure = (Token, usize, &'static str); + type Failure = (Token, u32, &'static str); - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure { + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { (tok, position, msg) } @@ -211,9 +211,9 @@ impl<'matcher> FailureForwarder<'matcher> { } impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> { - type Failure = (Token, usize, &'static str); + type Failure = (Token, u32, &'static str); - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure { + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { (tok, position, msg) } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 2fbd09fd9ae20..99a9d4f8912cd 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -452,7 +452,7 @@ impl TtParser { &mut self, matcher: &'matcher [MatcherLoc], token: &Token, - approx_position: usize, + approx_position: u32, track: &mut T, ) -> Option> { // Matcher positions that would be valid if the macro invocation was over now. Only diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e43ba7c3a5a8f..88ec3d8366429 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -153,7 +153,7 @@ pub(super) trait Tracker<'matcher> { /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected /// end of macro invocation. Otherwise, it indicates that no rules expected the given token. /// The usize is the approximate position of the token in the input token stream. - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure; + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure; /// This is called before trying to match next MatcherLoc on the current token. fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {} @@ -182,7 +182,7 @@ pub(super) struct NoopTracker; impl<'matcher> Tracker<'matcher> for NoopTracker { type Failure = (); - fn build_failure(_tok: Token, _position: usize, _msg: &'static str) -> Self::Failure {} + fn build_failure(_tok: Token, _position: u32, _msg: &'static str) -> Self::Failure {} fn description() -> &'static str { "none" diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 10feccd21e286..d0d01cec816fb 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -29,15 +29,15 @@ pub struct AttrWrapper { // The start of the outer attributes in the token cursor. // This allows us to create a `ReplaceRange` for the entire attribute // target, including outer attributes. - start_pos: usize, + start_pos: u32, } impl AttrWrapper { - pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper { + pub(super) fn new(attrs: AttrVec, start_pos: u32) -> AttrWrapper { AttrWrapper { attrs, start_pos } } pub fn empty() -> AttrWrapper { - AttrWrapper { attrs: AttrVec::new(), start_pos: usize::MAX } + AttrWrapper { attrs: AttrVec::new(), start_pos: u32::MAX } } pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec { @@ -91,7 +91,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, - num_calls: usize, + num_calls: u32, break_last_token: bool, replace_ranges: Box<[ReplaceRange]>, } @@ -110,7 +110,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { let token = cursor_snapshot.next(); (FlatToken::Token(token.0), token.1) })) - .take(self.num_calls); + .take(self.num_calls as usize); if self.replace_ranges.is_empty() { make_token_stream(tokens, self.break_last_token) @@ -296,12 +296,12 @@ impl<'a> Parser<'a> { ); let end_pos = self.num_bump_calls - + captured_trailing as usize + + captured_trailing as u32 // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then // extend the range of captured tokens to include it, since the parser was not actually // bumped past it. When the `LazyAttrTokenStream` gets converted into an // `AttrTokenStream`, we will create the proper token. - + self.break_last_token as usize; + + self.break_last_token as u32; let num_calls = end_pos - start_pos; @@ -313,14 +313,11 @@ impl<'a> Parser<'a> { // Grab any replace ranges that occur *inside* the current AST node. // We will perform the actual replacement when we convert the `LazyAttrTokenStream` // to an `AttrTokenStream`. - let start_calls: u32 = start_pos.try_into().unwrap(); self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] .iter() .cloned() .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, tokens)| { - ((range.start - start_calls)..(range.end - start_calls), tokens) - }) + .map(|(range, tokens)| ((range.start - start_pos)..(range.end - start_pos), tokens)) .collect() }; @@ -459,6 +456,6 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(AttrWrapper, 16); - static_assert_size!(LazyAttrTokenStreamImpl, 104); + static_assert_size!(LazyAttrTokenStreamImpl, 96); // tidy-alphabetical-end } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index cfd0a72c056d5..5f16a3e1f3784 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -153,7 +153,7 @@ pub struct Parser<'a> { expected_tokens: Vec, token_cursor: TokenCursor, // The number of calls to `bump`, i.e. the position in the token stream. - num_bump_calls: usize, + num_bump_calls: u32, // During parsing we may sometimes need to 'unglue' a glued token into two // component tokens (e.g. '>>' into '>' and '>), so the parser can consume // them one at a time. This process bypasses the normal capturing mechanism @@ -192,7 +192,7 @@ pub struct Parser<'a> { // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(Parser<'_>, 264); +rustc_data_structures::static_assert_size!(Parser<'_>, 256); /// Stores span information about a closure. #[derive(Clone, Debug)] @@ -1572,7 +1572,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn approx_token_stream_pos(&self) -> usize { + pub fn approx_token_stream_pos(&self) -> u32 { self.num_bump_calls } } From 6f6015679fb0153bd35d1b56df2456bb6146a9af Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 17:38:43 +1000 Subject: [PATCH 075/189] Rename `make_token_stream`. And update the comment. Clearly the return type of this function was changed at some point in the past, but its name and comment weren't updated to match. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index d0d01cec816fb..3afd178cc2b4e 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -113,7 +113,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { .take(self.num_calls as usize); if self.replace_ranges.is_empty() { - make_token_stream(tokens, self.break_last_token) + make_attr_token_stream(tokens, self.break_last_token) } else { let mut tokens: Vec<_> = tokens.collect(); let mut replace_ranges = self.replace_ranges.to_vec(); @@ -166,7 +166,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { new_tokens.into_iter().chain(filler), ); } - make_token_stream(tokens.into_iter(), self.break_last_token) + make_attr_token_stream(tokens.into_iter(), self.break_last_token) } } } @@ -374,10 +374,10 @@ impl<'a> Parser<'a> { } } -/// Converts a flattened iterator of tokens (including open and close delimiter tokens) -/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair -/// of open and close delims. -fn make_token_stream( +/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an +/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and +/// close delims. +fn make_attr_token_stream( mut iter: impl Iterator, break_last_token: bool, ) -> AttrTokenStream { From 565ddfb48ca2a3b24236c2b393ec14eb86d64a7a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 6 Jun 2024 19:57:36 +0300 Subject: [PATCH 076/189] linker: Link dylib crates by path --- compiler/rustc_codegen_ssa/src/back/link.rs | 42 ++---- compiler/rustc_codegen_ssa/src/back/linker.rs | 137 +++++++++++------- tests/run-make/dylib-soname/foo.rs | 1 + tests/run-make/dylib-soname/rmake.rs | 19 +++ 4 files changed, 114 insertions(+), 85 deletions(-) create mode 100644 tests/run-make/dylib-soname/foo.rs create mode 100644 tests/run-make/dylib-soname/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index da4fa41e2aafc..1f627353d54e1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2817,6 +2817,15 @@ fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf { } } +fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf { + if let Some(dir) = path.parent() { + let file_name = path.file_name().expect("library path has no file name component"); + rehome_sysroot_lib_dir(sess, dir).join(file_name) + } else { + fix_windows_verbatim_for_gcc(path) + } +} + // Adds the static "rlib" versions of all crates to the command line. // There's a bit of magic which happens here specifically related to LTO, // namely that we remove upstream object files. @@ -2847,15 +2856,8 @@ fn add_static_crate( let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; - let mut link_upstream = |path: &Path| { - let rlib_path = if let Some(dir) = path.parent() { - let file_name = path.file_name().expect("rlib path has no file name path component"); - rehome_sysroot_lib_dir(sess, dir).join(file_name) - } else { - fix_windows_verbatim_for_gcc(path) - }; - cmd.link_staticlib_by_path(&rlib_path, false); - }; + let mut link_upstream = + |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false); if !are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum) @@ -2919,27 +2921,7 @@ fn add_static_crate( // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // Just need to tell the linker about where the library lives and - // what its name is - let parent = cratepath.parent(); - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() { - return; - } - if let Some(dir) = parent { - cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); - } - // "

    /name.dll -> name.dll" on windows-msvc - // "/name.dll -> name" on windows-gnu - // "/libname. -> name" elsewhere - let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; - let stem = stem.unwrap().to_str().unwrap(); - // Convert library file-stem into a cc -l argument. - let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_dylib_by_name(&stem[prefix..], false, true); + cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true); } fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 0f75ece9729cd..2bd5dfdce83ee 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -268,7 +268,12 @@ pub trait Linker { false } fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } + fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("framework linked with unsupported linker") } @@ -403,28 +408,53 @@ impl<'a> GccLinker<'a> { } } else { self.link_or_cc_arg("-shared"); - if self.sess.target.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.staticlib_prefix, - file, - self.sess.target.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.link_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); - } + if let Some(name) = out_filename.file_name() { + if self.sess.target.is_like_windows { + // The output filename already contains `dll_suffix` so + // the resulting import library will have a name in the + // form of libfoo.dll.a + let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix); + implib_name.push(name); + implib_name.push(&*self.sess.target.staticlib_suffix); + let mut out_implib = OsString::from("--out-implib="); + out_implib.push(out_filename.with_file_name(implib_name)); + self.link_arg(out_implib); + } else { + // When dylibs are linked by a full path this value will get into `DT_NEEDED` + // instead of the full path, so the library can be later found in some other + // location than that specific path. + let mut soname = OsString::from("-soname="); + soname.push(name); + self.link_arg(soname); } } } } + + fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) { + if !as_needed { + if self.sess.target.is_like_osx { + // FIXME(81490): ld64 doesn't support these flags but macOS 11 + // has -needed-l{} / -needed_library {} + // but we have no way to detect that here. + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--no-as-needed"); + } else { + self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); + } + } + + f(self); + + if !as_needed { + if self.sess.target.is_like_osx { + // See above FIXME comment + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--as-needed"); + } + } + } } impl<'a> Linker for GccLinker<'a> { @@ -506,27 +536,18 @@ impl<'a> Linker for GccLinker<'a> { // to the linker. return; } - if !as_needed { - if self.sess.target.is_like_osx { - // FIXME(81490): ld64 doesn't support these flags but macOS 11 - // has -needed-l{} / -needed_library {} - // but we have no way to detect that here. - self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.link_arg("--no-as-needed"); - } else { - self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); - } - } self.hint_dynamic(); - self.link_or_cc_arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - if !as_needed { - if self.sess.target.is_like_osx { - // See above FIXME comment - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.link_arg("--as-needed"); - } - } + self.with_as_needed(as_needed, |this| { + let colon = if verbatim && this.is_gnu { ":" } else { "" }; + this.link_or_cc_arg(format!("-l{colon}{name}")); + }); + } + + fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) { + self.hint_dynamic(); + self.with_as_needed(as_needed, |this| { + this.link_or_cc_arg(path); + }) } fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { @@ -861,6 +882,15 @@ impl<'a> Linker for MsvcLinker<'a> { self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export + // any symbols, so we skip linking if the implib file is not present. + let implib_path = path.with_extension("dll.lib"); + if implib_path.exists() { + self.link_or_cc_arg(implib_path); + } + } + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; @@ -1083,6 +1113,10 @@ impl<'a> Linker for EmLinker<'a> { self.link_or_cc_args(&["-l", name]); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { self.link_or_cc_args(&["-l", name]); } @@ -1240,6 +1274,10 @@ impl<'a> Linker for WasmLd<'a> { self.link_or_cc_args(&["-l", name]); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { self.link_or_cc_args(&["-l", name]); @@ -1368,10 +1406,6 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - bug!("dylibs are not supported on L4Re"); - } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { @@ -1536,6 +1570,11 @@ impl<'a> Linker for AixLinker<'a> { self.link_or_cc_arg(format!("-l{name}")); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.hint_dynamic(); + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { @@ -1721,10 +1760,6 @@ impl<'a> Linker for PtxLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1791,10 +1826,6 @@ impl<'a> Linker for LlbcLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1866,10 +1897,6 @@ impl<'a> Linker for BpfLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } diff --git a/tests/run-make/dylib-soname/foo.rs b/tests/run-make/dylib-soname/foo.rs new file mode 100644 index 0000000000000..6833f39199943 --- /dev/null +++ b/tests/run-make/dylib-soname/foo.rs @@ -0,0 +1 @@ +pub fn something() {} diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs new file mode 100644 index 0000000000000..a0215a6906e47 --- /dev/null +++ b/tests/run-make/dylib-soname/rmake.rs @@ -0,0 +1,19 @@ +// Checks that produced dylibs have a relative SONAME set, so they don't put "unmovable" full paths +// into DT_NEEDED when used by a full path. + +//@ only-linux +//@ ignore-cross-compile + +use run_make_support::regex::Regex; +use run_make_support::{cmd, run_in_tmpdir, rustc}; + +fn main() { + run_in_tmpdir(|| { + rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run(); + cmd("readelf") + .arg("-d") + .arg("libfoo.so") + .run() + .assert_stdout_contains("Library soname: [libfoo.so]"); + }); +} From e03c3b6f19df854fbc52dc57bf39dbe9ae4972e9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:09:25 +0000 Subject: [PATCH 077/189] Allow _Unwind_RaiseException with MinGW --- .../miri/src/shims/windows/foreign_items.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index c9db798caad7f..71f6a2bc03333 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -758,6 +758,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } + "_Unwind_RaiseException" => { + // This is not formally part of POSIX, but it is very wide-spread on POSIX systems. + // It was originally specified as part of the Itanium C++ ABI: + // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw. + // MinGW implements _Unwind_RaiseException on top of SEH exceptions. + if this.tcx.sess.target.env != "gnu" { + throw_unsup_format!( + "`_Unwind_RaiseException` is not supported on non-MinGW Windows", + ); + } + // This function looks and behaves excatly like miri_start_unwind. + let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?; + this.handle_miri_start_unwind(payload)?; + return Ok(EmulateItemResult::NeedsUnwind); + } + _ => return Ok(EmulateItemResult::NotSupported), } From edeebe675b39cbdca93ec5b4c79f9a0765678112 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 20:29:01 +1000 Subject: [PATCH 078/189] Import `std::{iter,mem}`. --- .../rustc_parse/src/parser/attr_wrapper.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 3afd178cc2b4e..13a647adfe3b5 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -9,6 +9,7 @@ use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; use std::ops::Range; +use std::{iter, mem}; /// A wrapper type to ensure that the parser handles outer attributes correctly. /// When we parse outer attributes, we need to ensure that we capture tokens @@ -53,7 +54,7 @@ impl AttrWrapper { // FIXME: require passing an NT to prevent misuse of this method pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) { let mut self_attrs = self.attrs; - std::mem::swap(attrs, &mut self_attrs); + mem::swap(attrs, &mut self_attrs); attrs.extend(self_attrs); } @@ -104,13 +105,12 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. 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(std::iter::repeat_with(|| { - let token = cursor_snapshot.next(); - (FlatToken::Token(token.0), token.1) - })) - .take(self.num_calls as usize); + let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) + .chain(iter::repeat_with(|| { + let token = cursor_snapshot.next(); + (FlatToken::Token(token.0), token.1) + })) + .take(self.num_calls as usize); if self.replace_ranges.is_empty() { make_attr_token_stream(tokens, self.break_last_token) @@ -158,7 +158,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // This keeps the total length of `tokens` constant throughout the // replacement process, allowing us to use all of the `ReplaceRanges` entries // without adjusting indices. - let filler = std::iter::repeat((FlatToken::Empty, Spacing::Alone)) + let filler = iter::repeat((FlatToken::Empty, Spacing::Alone)) .take(range.len() - new_tokens.len()); tokens.splice( @@ -222,8 +222,7 @@ impl<'a> Parser<'a> { let replace_ranges_start = self.capture_state.replace_ranges.len(); let (mut ret, trailing) = { - let prev_capturing = - std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); + let prev_capturing = mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let ret_and_trailing = f(self, attrs.attrs); self.capture_state.capturing = prev_capturing; ret_and_trailing? From 8c353cbc4688b50a0c950d9afc4bba5b1718278d Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Mon, 24 Jun 2024 12:54:43 -0700 Subject: [PATCH 079/189] Disable rmake test inaccessible-temp-dir on riscv64 --- tests/run-make/inaccessible-temp-dir/rmake.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index 6b3e9e0b29e38..b98e151e90696 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -13,13 +13,18 @@ // use a directory with non-existing parent like `/does-not-exist/output`. // See https://github.com/rust-lang/rust/issues/66530 +//@ ignore-riscv64 +// FIXME: The riscv build container runs as root, and can always write +// into `inaccessible/tmp`. Ideally, the riscv64-gnu docker container +// would use a non-root user, but this leads to issues with +// `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. //@ ignore-arm // Reason: linker error on `armhf-gnu` //@ ignore-windows // Reason: `set_readonly` has no effect on directories // and does not prevent modification. -use run_make_support::{fs_wrapper, rustc, target, test_while_readonly}; +use run_make_support::{fs_wrapper, rustc, test_while_readonly}; fn main() { // Create an inaccessible directory. @@ -28,7 +33,6 @@ fn main() { // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, // so that it can't create `tmp`. rustc() - .target(target()) .input("program.rs") .arg("-Ztemps-dir=inaccessible/tmp") .run_fail() From 6c803ffefb8eba9c65afc9a122d94383f71ebfa2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2024 15:28:16 +0200 Subject: [PATCH 080/189] remove unnecessary ignore-endian-big from stack-overflow-trait-infer test --- tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr | 4 ++-- tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr | 4 ++-- tests/ui/sized/stack-overflow-trait-infer-98842.rs | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr index 6bbd81ae3e163..c01b2ccd1637c 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr @@ -3,14 +3,14 @@ error[E0391]: cycle detected when computing layout of `Foo` = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`... = note: ...which again requires computing layout of `Foo`, completing the cycle note: cycle used when const-evaluating + checking `_` - --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 + --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0080]: evaluation of constant value failed - --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 + --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr index 6bbd81ae3e163..c01b2ccd1637c 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr @@ -3,14 +3,14 @@ error[E0391]: cycle detected when computing layout of `Foo` = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`... = note: ...which again requires computing layout of `Foo`, completing the cycle note: cycle used when const-evaluating + checking `_` - --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 + --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error[E0080]: evaluation of constant value failed - --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 + --> $DIR/stack-overflow-trait-infer-98842.rs:14:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs index be4807b2e4aa7..8a958870b0e17 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs @@ -3,8 +3,7 @@ //@ check-fail //@ edition:2021 //@ stderr-per-bitwidth -//@ ignore-endian-big -//~^^^^^^ ERROR cycle detected when computing layout of `Foo` +//~^^^^^ ERROR cycle detected when computing layout of `Foo` // If the inner `Foo` is named through an associated type, // the "infinite size" error does not occur. From 1df876f4c0ab583ef8821739c38340c8062f2ed5 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 2 Jul 2024 16:28:01 +0100 Subject: [PATCH 081/189] Add test --- .../nested_bad_const_param_ty.rs | 18 +++++++ .../nested_bad_const_param_ty.stderr | 51 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs create mode 100644 tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs new file mode 100644 index 0000000000000..9f05c53eef0f6 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs @@ -0,0 +1,18 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy)] +//~^ the trait `ConstParamTy` cannot be implemented for this ty +struct Foo([*const u8; 1]); + +#[derive(ConstParamTy)] +//~^ the trait `ConstParamTy` cannot be implemented for this ty +struct Foo2([*mut u8; 1]); + +#[derive(ConstParamTy)] +//~^ the trait `ConstParamTy` cannot be implemented for this ty +struct Foo3([fn(); 1]); + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr new file mode 100644 index 0000000000000..9e772e8d55df9 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr @@ -0,0 +1,51 @@ +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:6:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +LL | +LL | struct Foo([*const u8; 1]); + | -------------- this field does not implement `ConstParamTy` + | +note: the `ConstParamTy` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:8:12 + | +LL | struct Foo([*const u8; 1]); + | ^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:10:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +LL | +LL | struct Foo2([*mut u8; 1]); + | ------------ this field does not implement `ConstParamTy` + | +note: the `ConstParamTy` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:12:13 + | +LL | struct Foo2([*mut u8; 1]); + | ^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:14:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +LL | +LL | struct Foo3([fn(); 1]); + | --------- this field does not implement `ConstParamTy` + | +note: the `ConstParamTy` impl for `[fn(); 1]` requires that `fn(): ConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:16:13 + | +LL | struct Foo3([fn(); 1]); + | ^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0204`. From 371845b630a86f86233c4a031971f9737a2092ff Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 10:14:24 -0400 Subject: [PATCH 082/189] rewrite dylib-chain to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dylib-chain/Makefile | 13 ----------- tests/run-make/dylib-chain/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/dylib-chain/Makefile create mode 100644 tests/run-make/dylib-chain/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 276d2d694cda0..cd01b8596bba1 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile -run-make/dylib-chain/Makefile run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile run-make/emit-to-stdout/Makefile diff --git a/tests/run-make/dylib-chain/Makefile b/tests/run-make/dylib-chain/Makefile deleted file mode 100644 index f1fea99c5ee91..0000000000000 --- a/tests/run-make/dylib-chain/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) m1.rs -C prefer-dynamic - $(RUSTC) m2.rs -C prefer-dynamic - $(RUSTC) m3.rs -C prefer-dynamic - $(RUSTC) m4.rs - $(call RUN,m4) - $(call REMOVE_DYLIBS,m1) - $(call REMOVE_DYLIBS,m2) - $(call REMOVE_DYLIBS,m3) - $(call FAIL,m4) diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs new file mode 100644 index 0000000000000..1d27191806f8b --- /dev/null +++ b/tests/run-make/dylib-chain/rmake.rs @@ -0,0 +1,22 @@ +// In this test, m4 depends on m3, which depends on m2, which depends on m1. +// Even though dependencies are chained like this and there is no direct mention +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Naturally, +// removing those dependencies should cause execution to fail. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc}; + +fn main() { + rustc().input("m1.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m2.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m3.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m4.rs").run(); + run("m4"); + fs_wrapper::remove_file(dynamic_lib_name("m1")); + fs_wrapper::remove_file(dynamic_lib_name("m2")); + fs_wrapper::remove_file(dynamic_lib_name("m3")); + run_fail("m4"); +} From 86bd3498b2c5a6a40f3db62c48a22f81d7713950 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 10:20:49 -0400 Subject: [PATCH 083/189] rewrite rlib-chain to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dylib-chain/rmake.rs | 5 ++-- tests/run-make/rlib-chain/Makefile | 11 --------- tests/run-make/rlib-chain/rmake.rs | 23 +++++++++++++++++++ 4 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/rlib-chain/Makefile create mode 100644 tests/run-make/rlib-chain/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index cd01b8596bba1..1e213eabab580 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -135,7 +135,6 @@ run-make/remap-path-prefix-dwarf/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile run-make/return-non-c-like-enum-from-c/Makefile -run-make/rlib-chain/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs index 1d27191806f8b..a96cc3508750b 100644 --- a/tests/run-make/dylib-chain/rmake.rs +++ b/tests/run-make/dylib-chain/rmake.rs @@ -1,7 +1,8 @@ // In this test, m4 depends on m3, which depends on m2, which depends on m1. // Even though dependencies are chained like this and there is no direct mention -// of m1 or m2 in m4.rs, compilation and execution should still succeed. Naturally, -// removing those dependencies should cause execution to fail. +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike the +// rlib-chain test, dynamic libraries contain upstream dependencies, and breaking +// the chain by removing the dylibs causes execution to fail. // See https://github.com/rust-lang/rust/issues/10434 //@ ignore-cross-compile diff --git a/tests/run-make/rlib-chain/Makefile b/tests/run-make/rlib-chain/Makefile deleted file mode 100644 index 7a1f887fa5271..0000000000000 --- a/tests/run-make/rlib-chain/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) m1.rs - $(RUSTC) m2.rs - $(RUSTC) m3.rs - $(RUSTC) m4.rs - $(call RUN,m4) - rm $(TMPDIR)/*lib - $(call RUN,m4) diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs new file mode 100644 index 0000000000000..0947262bf6200 --- /dev/null +++ b/tests/run-make/rlib-chain/rmake.rs @@ -0,0 +1,23 @@ +// In this test, m4 depends on m3, which depends on m2, which depends on m1. +// Even though dependencies are chained like this and there is no direct mention +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike +// the dylib-chain test, rlibs do not contain upstream dependencies, and removing +// the libraries still allows m4 to successfully execute. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{fs_wrapper, run, rust_lib_name, rustc}; + +fn main() { + rustc().input("m1.rs").run(); + rustc().input("m2.rs").run(); + rustc().input("m3.rs").run(); + rustc().input("m4.rs").run(); + run("m4"); + fs_wrapper::remove_file(rust_lib_name("m1")); + fs_wrapper::remove_file(rust_lib_name("m2")); + fs_wrapper::remove_file(rust_lib_name("m3")); + run("m4"); +} From 3a656462ef59a5d5288e0eb9651060d640c975ed Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:08:49 -0400 Subject: [PATCH 084/189] rewrite and rename issue-47384 to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../lib.rs | 0 .../linker.ld | 0 .../main.rs | 0 .../include-all-symbols-linking/rmake.rs | 29 +++++++++++++++++++ tests/run-make/issue-47384/Makefile | 12 -------- 6 files changed, 29 insertions(+), 13 deletions(-) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/lib.rs (100%) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/linker.ld (100%) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/main.rs (100%) create mode 100644 tests/run-make/include-all-symbols-linking/rmake.rs delete mode 100644 tests/run-make/issue-47384/Makefile diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 1e213eabab580..6ef68509f1095 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -65,7 +65,6 @@ run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-37839/Makefile run-make/issue-40535/Makefile -run-make/issue-47384/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile diff --git a/tests/run-make/issue-47384/lib.rs b/tests/run-make/include-all-symbols-linking/lib.rs similarity index 100% rename from tests/run-make/issue-47384/lib.rs rename to tests/run-make/include-all-symbols-linking/lib.rs diff --git a/tests/run-make/issue-47384/linker.ld b/tests/run-make/include-all-symbols-linking/linker.ld similarity index 100% rename from tests/run-make/issue-47384/linker.ld rename to tests/run-make/include-all-symbols-linking/linker.ld diff --git a/tests/run-make/issue-47384/main.rs b/tests/run-make/include-all-symbols-linking/main.rs similarity index 100% rename from tests/run-make/issue-47384/main.rs rename to tests/run-make/include-all-symbols-linking/main.rs diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs new file mode 100644 index 0000000000000..a443fc0a5c41b --- /dev/null +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -0,0 +1,29 @@ +// Linkers treat archives differently from object files: all object files participate in linking, +// while archives will only participate in linking if they can satisfy at least one undefined +// reference (version scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to +// be ignored by the linker, and since they never participate in the linking, using `KEEP` in the +// linker scripts can't keep them either. This causes #47384. After the fix in #95604, this test +// checks that these symbols and sections successfully appear in the output dynamic library. +// See https://github.com/rust-lang/rust/pull/95604 +// See https://github.com/rust-lang/rust/issues/47384 + +//FIXME(Oneirical): ignore flags: only linux and cross compile + +use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc}; + +fn main() { + rustc().crate_type("lib").input("lib.rs").run(); + rustc().crate_type("cdylib").link_args("-Tlinker.ld").input("main.rs").run(); + // Ensure `#[used]` and `KEEP`-ed section is there + llvm_objdump() + .arg("--full-contents") + .arg("--section=.static") + .input(dynamic_lib_name("main")) + .run(); + // Ensure `#[no_mangle]` symbol is there + llvm_readobj() + .arg("--symbols") + .input(dynamic_lib_name("main")) + .run() + .assert_stdout_contains("bar"); +} diff --git a/tests/run-make/issue-47384/Makefile b/tests/run-make/issue-47384/Makefile deleted file mode 100644 index afc77cb275aaa..0000000000000 --- a/tests/run-make/issue-47384/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# only-linux -# ignore-cross-compile - -all: main.rs - $(RUSTC) --crate-type lib lib.rs - $(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs - # Ensure `#[used]` and `KEEP`-ed section is there - objdump -s -j".static" $(TMPDIR)/libmain.so - # Ensure `#[no_mangle]` symbol is there - nm $(TMPDIR)/libmain.so | $(CGREP) bar From b75dd71ef0472a5ef2c7c1ec9f0a12b125905d02 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:28:50 -0400 Subject: [PATCH 085/189] rewrite msvc-opt-minsize to ui test --- tests/run-make/msvc-opt-minsize/Makefile | 6 ---- tests/run-make/msvc-opt-minsize/foo.rs | 19 ------------ .../{windows-subsystem => windows}/console.rs | 0 tests/ui/windows/msvc-opt-minsize.rs | 31 +++++++++++++++++++ .../windows-subsystem-invalid.rs | 0 .../windows-subsystem-invalid.stderr | 0 .../{windows-subsystem => windows}/windows.rs | 0 7 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 tests/run-make/msvc-opt-minsize/Makefile delete mode 100644 tests/run-make/msvc-opt-minsize/foo.rs rename tests/ui/{windows-subsystem => windows}/console.rs (100%) create mode 100644 tests/ui/windows/msvc-opt-minsize.rs rename tests/ui/{windows-subsystem => windows}/windows-subsystem-invalid.rs (100%) rename tests/ui/{windows-subsystem => windows}/windows-subsystem-invalid.stderr (100%) rename tests/ui/{windows-subsystem => windows}/windows.rs (100%) diff --git a/tests/run-make/msvc-opt-minsize/Makefile b/tests/run-make/msvc-opt-minsize/Makefile deleted file mode 100644 index 32e6e28018f7a..0000000000000 --- a/tests/run-make/msvc-opt-minsize/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs -Copt-level=z 2>&1 - $(call RUN,foo) diff --git a/tests/run-make/msvc-opt-minsize/foo.rs b/tests/run-make/msvc-opt-minsize/foo.rs deleted file mode 100644 index 3f5496c08ee25..0000000000000 --- a/tests/run-make/msvc-opt-minsize/foo.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(test)] -extern crate test; - -fn foo(x: i32, y: i32) -> i64 { - (x + y) as i64 -} - -#[inline(never)] -fn bar() { - let _f = Box::new(0); - // This call used to trigger an LLVM bug in opt-level z where the base - // pointer gets corrupted, see issue #45034 - let y: fn(i32, i32) -> i64 = test::black_box(foo); - test::black_box(y(1, 2)); -} - -fn main() { - bar(); -} diff --git a/tests/ui/windows-subsystem/console.rs b/tests/ui/windows/console.rs similarity index 100% rename from tests/ui/windows-subsystem/console.rs rename to tests/ui/windows/console.rs diff --git a/tests/ui/windows/msvc-opt-minsize.rs b/tests/ui/windows/msvc-opt-minsize.rs new file mode 100644 index 0000000000000..c1be168a05dde --- /dev/null +++ b/tests/ui/windows/msvc-opt-minsize.rs @@ -0,0 +1,31 @@ +// A previously outdated version of LLVM caused compilation failures on Windows +// specifically with optimization level `z`. After the update to a more recent LLVM +// version, this test checks that compilation and execution both succeed. +// See https://github.com/rust-lang/rust/issues/45034 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed +//@ only-windows +// Reason: the observed bug only occurs on Windows +//@ run-pass +//@ compile-flags: -C opt-level=z + +#![feature(test)] +extern crate test; + +fn foo(x: i32, y: i32) -> i64 { + (x + y) as i64 +} + +#[inline(never)] +fn bar() { + let _f = Box::new(0); + // This call used to trigger an LLVM bug in opt-level z where the base + // pointer gets corrupted, see issue #45034 + let y: fn(i32, i32) -> i64 = test::black_box(foo); + test::black_box(y(1, 2)); +} + +fn main() { + bar(); +} diff --git a/tests/ui/windows-subsystem/windows-subsystem-invalid.rs b/tests/ui/windows/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows-subsystem/windows-subsystem-invalid.rs rename to tests/ui/windows/windows-subsystem-invalid.rs diff --git a/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr b/tests/ui/windows/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows-subsystem/windows-subsystem-invalid.stderr rename to tests/ui/windows/windows-subsystem-invalid.stderr diff --git a/tests/ui/windows-subsystem/windows.rs b/tests/ui/windows/windows.rs similarity index 100% rename from tests/ui/windows-subsystem/windows.rs rename to tests/ui/windows/windows.rs From 45313a6ca038995bc3a0cc952fac94102d00f60c Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:44:47 -0400 Subject: [PATCH 086/189] rewrite test-harness to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 2 -- src/tools/tidy/src/ui_tests.rs | 2 +- .../include-all-symbols-linking/rmake.rs | 4 ++- tests/run-make/test-harness/Makefile | 9 ------- tests/run-make/test-harness/rmake.rs | 25 +++++++++++++++++++ tests/ui/{windows => }/msvc-opt-minsize.rs | 0 .../{windows => windows-subsystem}/console.rs | 0 .../windows-subsystem-invalid.rs | 0 .../windows-subsystem-invalid.stderr | 0 .../{windows => windows-subsystem}/windows.rs | 0 10 files changed, 29 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/test-harness/Makefile create mode 100644 tests/run-make/test-harness/rmake.rs rename tests/ui/{windows => }/msvc-opt-minsize.rs (100%) rename tests/ui/{windows => windows-subsystem}/console.rs (100%) rename tests/ui/{windows => windows-subsystem}/windows-subsystem-invalid.rs (100%) rename tests/ui/{windows => windows-subsystem}/windows-subsystem-invalid.stderr (100%) rename tests/ui/{windows => windows-subsystem}/windows.rs (100%) diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6ef68509f1095..2da4e476e9016 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -96,7 +96,6 @@ run-make/metadata-dep-info/Makefile run-make/min-global-align/Makefile run-make/missing-crate-dependency/Makefile run-make/mixing-libs/Makefile -run-make/msvc-opt-minsize/Makefile run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile @@ -163,7 +162,6 @@ run-make/target-cpu-native/Makefile run-make/target-specs/Makefile run-make/target-without-atomic-cas/Makefile run-make/test-benches/Makefile -run-make/test-harness/Makefile run-make/thumb-none-cortex-m/Makefile run-make/thumb-none-qemu/Makefile run-make/track-path-dep-info/Makefile diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 95857502108da..5e6992038e395 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; // should all be 1000 or lower. Limits significantly smaller than 1000 are also // desirable, because large numbers of files are unwieldy in general. See issue // #73494. -const ENTRY_LIMIT: u32 = 900; +const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: u32 = 1672; diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs index a443fc0a5c41b..77fd71ab20d21 100644 --- a/tests/run-make/include-all-symbols-linking/rmake.rs +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -7,7 +7,9 @@ // See https://github.com/rust-lang/rust/pull/95604 // See https://github.com/rust-lang/rust/issues/47384 -//FIXME(Oneirical): ignore flags: only linux and cross compile +//@ only-linux +// Reason: differences in object file formats on OSX and Windows +// causes errors in the llvm_objdump step use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc}; diff --git a/tests/run-make/test-harness/Makefile b/tests/run-make/test-harness/Makefile deleted file mode 100644 index ee8c9294f91ab..0000000000000 --- a/tests/run-make/test-harness/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - # check that #[cfg_attr(..., ignore)] does the right thing. - $(RUSTC) --test test-ignore-cfg.rs --cfg ignorecfg - $(call RUN,test-ignore-cfg) | $(CGREP) 'shouldnotignore ... ok' 'shouldignore ... ignored' - $(call RUN,test-ignore-cfg --quiet) | $(CGREP) -e "^i\.$$" - $(call RUN,test-ignore-cfg --quiet) | $(CGREP) -v 'should' diff --git a/tests/run-make/test-harness/rmake.rs b/tests/run-make/test-harness/rmake.rs new file mode 100644 index 0000000000000..30b3d00f4d114 --- /dev/null +++ b/tests/run-make/test-harness/rmake.rs @@ -0,0 +1,25 @@ +// The way test suites run can be modified using configuration flags, +// ignoring certain tests while running others. This test contains two +// functions, one which must run and the other which must not. The standard +// output is checked to verify that the ignore configuration is doing its job, +// and that output is successfully minimized with the --quiet flag. +// See https://github.com/rust-lang/rust/commit/f7ebe23ae185991b0fee05b32fbb3e29b89a41bf + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{run, run_with_args, rustc}; + +fn main() { + rustc().arg("--test").input("test-ignore-cfg.rs").cfg("ignorecfg").run(); + // check that #[cfg_attr(..., ignore)] does the right thing. + run("test-ignore-cfg") + .assert_stdout_contains("shouldnotignore ... ok") + .assert_stdout_contains("shouldignore ... ignored"); + assert_eq!( + // One of the lines is exactly "i." + run_with_args("test-ignore-cfg", &["--quiet"]).stdout_utf8().lines().find(|&x| x == "i."), + Some("i.") + ); + run_with_args("test-ignore-cfg", &["--quiet"]).assert_stdout_not_contains("should"); +} diff --git a/tests/ui/windows/msvc-opt-minsize.rs b/tests/ui/msvc-opt-minsize.rs similarity index 100% rename from tests/ui/windows/msvc-opt-minsize.rs rename to tests/ui/msvc-opt-minsize.rs diff --git a/tests/ui/windows/console.rs b/tests/ui/windows-subsystem/console.rs similarity index 100% rename from tests/ui/windows/console.rs rename to tests/ui/windows-subsystem/console.rs diff --git a/tests/ui/windows/windows-subsystem-invalid.rs b/tests/ui/windows-subsystem/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows/windows-subsystem-invalid.rs rename to tests/ui/windows-subsystem/windows-subsystem-invalid.rs diff --git a/tests/ui/windows/windows-subsystem-invalid.stderr b/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows/windows-subsystem-invalid.stderr rename to tests/ui/windows-subsystem/windows-subsystem-invalid.stderr diff --git a/tests/ui/windows/windows.rs b/tests/ui/windows-subsystem/windows.rs similarity index 100% rename from tests/ui/windows/windows.rs rename to tests/ui/windows-subsystem/windows.rs From 8ce8c62f1e908ffb7edec993cb5e6cbafe4d620c Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 2 Jul 2024 17:07:21 +0100 Subject: [PATCH 087/189] add test --- .../generic_const_exprs/adt_wf_hang.rs | 14 ++++++++++++++ .../generic_const_exprs/adt_wf_hang.stderr | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs new file mode 100644 index 0000000000000..5d538d2679dd8 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs @@ -0,0 +1,14 @@ +#![feature(generic_const_exprs)] +#![feature(adt_const_params)] +#![allow(incomplete_features)] +#![allow(dead_code)] + +#[derive(PartialEq, Eq)] +struct U; + +struct S() +where + S<{ U }>:; +//~^ ERROR: overflow evaluating the requirement `S<{ U }> well-formed` + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr new file mode 100644 index 0000000000000..b244acb37dde0 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr @@ -0,0 +1,18 @@ +error[E0275]: overflow evaluating the requirement `S<{ U }> well-formed` + --> $DIR/adt_wf_hang.rs:11:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/adt_wf_hang.rs:11:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From 4b0b97f66ddf36525b844a9c0c775db9f980248f Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Tue, 2 Jul 2024 10:09:40 -0700 Subject: [PATCH 088/189] Give remote-test-client a longer timeout --- src/tools/remote-test-client/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index dd2c09c430b61..42de3caf5474d 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -71,7 +71,7 @@ fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option Date: Tue, 2 Jul 2024 21:03:13 +0200 Subject: [PATCH 089/189] use let-else to avoid rightwards drift --- src/tools/miri/src/shims/unix/fd.rs | 45 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 87e20954a70a1..7f6a097810350 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -276,29 +276,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - match this.machine.fds.dup(old_fd) { - Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)), - None => this.fd_not_found(), - } + let Some(dup_fd) = this.machine.fds.dup(old_fd) else { + return this.fd_not_found(); + }; + Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)) } fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - match this.machine.fds.dup(old_fd) { - Some(dup_fd) => { - if new_fd != old_fd { - // Close new_fd if it is previously opened. - // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive. - if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) { - // Ignore close error (not interpreter's) according to dup2() doc. - file_descriptor.close(this.machine.communicate())?.ok(); - } - } - Ok(new_fd) + let Some(dup_fd) = this.machine.fds.dup(old_fd) else { + return this.fd_not_found(); + }; + if new_fd != old_fd { + // Close new_fd if it is previously opened. + // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive. + if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) { + // Ignore close error (not interpreter's) according to dup2() doc. + file_descriptor.close(this.machine.communicate())?.ok(); } - None => this.fd_not_found(), } + Ok(new_fd) } fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { @@ -362,14 +360,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd = this.read_scalar(fd_op)?.to_i32()?; - Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) { - let result = file_descriptor.close(this.machine.communicate())?; - // return `0` if close is successful - let result = result.map(|()| 0i32); - this.try_unwrap_io_result(result)? - } else { - this.fd_not_found()? - })) + let Some(file_descriptor) = this.machine.fds.remove(fd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + let result = file_descriptor.close(this.machine.communicate())?; + // return `0` if close is successful + let result = result.map(|()| 0i32); + Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets From 41b98da42d0500e38b9dd85c82110ba177ac4de1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2024 21:05:22 +0200 Subject: [PATCH 090/189] Miri function identity hack: account for possible inlining --- .../rustc_codegen_cranelift/src/constant.rs | 8 +- compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 4 +- .../rustc_const_eval/src/interpret/memory.rs | 14 ++-- .../src/interpret/validity.rs | 2 +- .../rustc_middle/src/mir/interpret/mod.rs | 73 +++++++++++++------ compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- compiler/rustc_monomorphize/src/collector.rs | 8 +- compiler/rustc_passes/src/reachable.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 2 +- src/tools/miri/src/shims/backtrace.rs | 2 +- .../miri/tests/pass/function_pointers.rs | 3 +- .../miri/tests/pass/issues/issue-91636.rs | 1 + 14 files changed, 80 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 87c5da3b7c3ed..9f7b95261d528 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -155,7 +155,7 @@ pub(crate) fn codegen_const_value<'tcx>( fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } } - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); @@ -351,7 +351,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant TodoItem::Alloc(alloc_id) => { let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { + GlobalAlloc::Function { .. } + | GlobalAlloc::Static(_) + | GlobalAlloc::VTable(..) => { unreachable!() } }; @@ -415,7 +417,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let reloc_target_alloc = tcx.global_alloc(alloc_id); let data_id = match reloc_target_alloc { - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { assert_eq!(addend, 0); let func_id = crate::abi::import_function(tcx, module, instance.polymorphize(tcx)); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 230fe4f5871e8..fa8a1ec037c5c 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -220,7 +220,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } value } - GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), GlobalAlloc::VTable(ty, trait_ref) => { let alloc = self .tcx diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index d42c6ed827aec..fe64649cf70fb 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -289,8 +289,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { (value, AddressSpace::DATA) } } - GlobalAlloc::Function(fn_instance) => ( - self.get_fn_addr(fn_instance.polymorphize(self.tcx)), + GlobalAlloc::Function { instance, .. } => ( + self.get_fn_addr(instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9d0c490822561..36fe8dfdd29b7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { // Deallocating global memory -- always an error return Err(match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::Function(..)) => { + Some(GlobalAlloc::Function { .. }) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, alloc_id = alloc_id, @@ -555,7 +555,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Memory of a constant or promoted or anonymous memory referenced by a static. (mem, None) } - Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)), Some(GlobalAlloc::Static(def_id)) => { @@ -828,7 +828,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let alloc = alloc.inner(); (alloc.size(), alloc.align, AllocKind::LiveData) } - Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), + Some(GlobalAlloc::Function { .. }) => { + bug!("We already checked function pointers above") + } Some(GlobalAlloc::VTable(..)) => { // No data to be accessed here. But vtables are pointer-aligned. return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); @@ -865,7 +867,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(FnVal::Other(*extra)) } else { match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), + Some(GlobalAlloc::Function { instance, .. }) => Some(FnVal::Instance(instance)), _ => None, } } @@ -1056,8 +1058,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { alloc.inner(), )?; } - Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {func})")?; + Some(GlobalAlloc::Function { instance, .. }) => { + write!(fmt, " (fn: {instance})")?; } Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index add48e1b186cb..7fea061766666 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -745,7 +745,7 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => { + GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable, we better don't allow mutable pointers here. Mutability::Not } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 16093cfca6add..4e95e600b5ab9 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -18,6 +18,7 @@ use smallvec::{smallvec, SmallVec}; use tracing::{debug, trace}; use rustc_ast::LitKind; +use rustc_attr::InlineAttr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_errors::ErrorGuaranteed; @@ -134,10 +135,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( AllocDiscriminant::Alloc.encode(encoder); alloc.encode(encoder); } - GlobalAlloc::Function(fn_instance) => { - trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); + GlobalAlloc::Function { instance, unique } => { + trace!("encoding {:?} with {:#?}", alloc_id, instance); AllocDiscriminant::Fn.encode(encoder); - fn_instance.encode(encoder); + instance.encode(encoder); + unique.encode(encoder); } GlobalAlloc::VTable(ty, poly_trait_ref) => { trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); @@ -285,7 +287,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("creating fn alloc ID"); let instance = ty::Instance::decode(decoder); trace!("decoded fn alloc instance: {:?}", instance); - let alloc_id = decoder.interner().reserve_and_set_fn_alloc(instance); + let unique = bool::decode(decoder); + // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which + // is not possible in this context. That's why the allocation stores + // whether it is unique or not. + let alloc_id = + decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique); alloc_id } AllocDiscriminant::VTable => { @@ -323,7 +330,12 @@ impl<'s> AllocDecodingSession<'s> { #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)] pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. - Function(Instance<'tcx>), + Function { + instance: Instance<'tcx>, + /// Stores whether this instance is unique, i.e. all pointers to this function use the same + /// alloc ID. + unique: bool, + }, /// This alloc ID points to a symbolic (not-reified) vtable. VTable(Ty<'tcx>, Option>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). @@ -349,7 +361,7 @@ impl<'tcx> GlobalAlloc<'tcx> { #[inline] pub fn unwrap_fn(&self) -> Instance<'tcx> { match *self { - GlobalAlloc::Function(instance) => instance, + GlobalAlloc::Function { instance, .. } => instance, _ => bug!("expected function, got {:?}", self), } } @@ -368,7 +380,7 @@ impl<'tcx> GlobalAlloc<'tcx> { #[inline] pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { - GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, + GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { AddressSpace::DATA } @@ -426,7 +438,7 @@ impl<'tcx> TyCtxt<'tcx> { fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} + GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -445,30 +457,45 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } + /// Generates an `AllocId` for a function. The caller must already have decided whether this + /// function obtains a unique AllocId or gets de-duplicated via the cache. + fn reserve_and_set_fn_alloc_internal(self, instance: Instance<'tcx>, unique: bool) -> AllocId { + let alloc = GlobalAlloc::Function { instance, unique }; + if unique { + // Deduplicate. + self.reserve_and_set_dedup(alloc) + } else { + // Get a fresh ID. + let mut alloc_map = self.alloc_map.lock(); + let id = alloc_map.reserve(); + alloc_map.alloc_map.insert(id, alloc); + id + } + } + /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be - // duplicated across crates. - // We thus generate a new `AllocId` for every mention of a function. This means that - // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true. - // However, formatting code relies on function identity (see #58320), so we only do - // this for generic functions. Lifetime parameters are ignored. + // duplicated across crates. We thus generate a new `AllocId` for every mention of a + // function. This means that `main as fn() == main as fn()` is false, while `let x = main as + // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify + // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will + // actually emit duplicate functions. It does that when they have non-lifetime generics, or + // when they can be inlined. All other functions are given a unique address. + // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied + // upon for anything. But if we don't do this, backtraces look terrible. let is_generic = instance .args .into_iter() .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_))); - if is_generic { - // Get a fresh ID. - let mut alloc_map = self.alloc_map.lock(); - let id = alloc_map.reserve(); - alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance)); - id - } else { - // Deduplicate. - self.reserve_and_set_dedup(GlobalAlloc::Function(instance)) - } + let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline { + InlineAttr::Never => false, + _ => true, + }; + let unique = !is_generic && !can_be_inlined; + self.reserve_and_set_fn_alloc_internal(instance, unique) } /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4657f4dcf8132..4453ce44b0371 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1449,7 +1449,7 @@ pub fn write_allocations<'tcx>( // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, - Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, + Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?, Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(w, " (vtable: impl {trait_ref} for {ty})")? } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 19700353f5944..3f08ab33e1052 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1667,7 +1667,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Some(GlobalAlloc::Static(def_id)) => { p!(write("", def_id)) } - Some(GlobalAlloc::Function(_)) => p!(""), + Some(GlobalAlloc::Function { .. }) => p!(""), Some(GlobalAlloc::VTable(..)) => p!(""), None => p!(""), } @@ -1679,7 +1679,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - if let Some(GlobalAlloc::Function(instance)) = + if let Some(GlobalAlloc::Function { instance, .. }) = self.tcx().try_get_global_alloc(prov.alloc_id()) { self.typed_value( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 235743fccc89e..ec16b716c109c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1223,10 +1223,10 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt }); } } - GlobalAlloc::Function(fn_instance) => { - if should_codegen_locally(tcx, fn_instance) { - trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); - output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); + GlobalAlloc::Function { instance, .. } => { + if should_codegen_locally(tcx, instance) { + trace!("collecting {:?} with {:#?}", alloc_id, instance); + output.push(create_fn_mono_item(tcx, instance, DUMMY_SP)); } } GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 6dd8eaf7e6734..dee8ba7e87dfd 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -310,7 +310,7 @@ impl<'tcx> ReachableContext<'tcx> { GlobalAlloc::Static(def_id) => { self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id)) } - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { // Manually visit to actually see the instance's `DefId`. Type visitors won't see it self.propagate_item(Res::Def( self.tcx.def_kind(instance.def_id()), diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index f15b82d0c031f..9d5a14b5145fb 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -709,7 +709,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { - mir::interpret::GlobalAlloc::Function(instance) => { + mir::interpret::GlobalAlloc::Function { instance, .. } => { GlobalAlloc::Function(instance.stable(tables)) } mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 06be9c1e63e06..24a4b5f26a950 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -119,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; // This has to be an actual global fn ptr, not a dlsym function. - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + let fn_instance = if let Some(GlobalAlloc::Function { instance, .. }) = this.tcx.try_get_global_alloc(alloc_id) { instance diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs index 36679b7180a64..2aa3ebf2dd0b4 100644 --- a/src/tools/miri/tests/pass/function_pointers.rs +++ b/src/tools/miri/tests/pass/function_pointers.rs @@ -23,6 +23,7 @@ fn h(i: i32, j: i32) -> i32 { j * i * 7 } +#[inline(never)] fn i() -> i32 { 73 } @@ -77,7 +78,7 @@ fn main() { assert_eq!(indirect_mut3(h), 210); assert_eq!(indirect_once3(h), 210); // Check that `i` always has the same address. This is not guaranteed - // but Miri currently uses a fixed address for monomorphic functions. + // but Miri currently uses a fixed address for non-inlineable monomorphic functions. assert!(return_fn_ptr(i) == i); assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32); // Miri gives different addresses to different reifications of a generic function. diff --git a/src/tools/miri/tests/pass/issues/issue-91636.rs b/src/tools/miri/tests/pass/issues/issue-91636.rs index 21000bb68d2bc..00370165812f5 100644 --- a/src/tools/miri/tests/pass/issues/issue-91636.rs +++ b/src/tools/miri/tests/pass/issues/issue-91636.rs @@ -10,6 +10,7 @@ impl Function { } } +#[inline(never)] fn dummy(_: &str) {} fn main() { From d3a742bde999add41c002513fccd0949859128f4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 12:53:03 -0400 Subject: [PATCH 091/189] Miscellaneous renaming --- .../src/interpret/terminator.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/instance.rs | 120 +++++++++--------- .../src/traits/vtable.rs | 6 +- compiler/rustc_ty_utils/src/instance.rs | 4 +- 5 files changed, 71 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 74521d0f49345..f59293e7266ac 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -883,13 +883,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - let concrete_method = Instance::resolve_for_vtable( + let concrete_method = Instance::expect_resolve_for_vtable( tcx, self.param_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), - ) - .unwrap(); + ); assert_eq!(fn_inst, concrete_method); } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d40a783358959..33c27d41d8642 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2197,8 +2197,8 @@ rustc_queries! { /// * `Err(ErrorGuaranteed)` when the `Instance` resolution process /// couldn't complete due to errors elsewhere - this is distinct /// from `Ok(None)` to avoid misleading diagnostics when an error - /// has already been/will be emitted, for the original cause - query resolve_instance( + /// has already been/will be emitted, for the original cause. + query resolve_instance_raw( key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)> ) -> Result>, ErrorGuaranteed> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1ba8820e0e11d..99ac503cd6800 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -505,7 +505,7 @@ impl<'tcx> Instance<'tcx> { // below is more likely to ignore the bounds in scope (e.g. if the only // generic parameters mentioned by `args` were lifetime ones). let args = tcx.erase_regions(args); - tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, args)))) + tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args)))) } pub fn expect_resolve( @@ -571,77 +571,81 @@ impl<'tcx> Instance<'tcx> { }) } - pub fn resolve_for_vtable( + pub fn expect_resolve_for_vtable( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, - ) -> Option> { + ) -> Instance<'tcx> { debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args); let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty() && fn_sig.input(0).skip_binder().is_param(0) && tcx.generics_of(def_id).has_self; + if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceKind::VTableShim(def_id), args }) - } else { - let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); - Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { - match resolved.def { - InstanceKind::Item(def) => { - // We need to generate a shim when we cannot guarantee that - // the caller of a trait object method will be aware of - // `#[track_caller]` - this ensures that the caller - // and callee ABI will always match. - // - // The shim is generated when all of these conditions are met: - // - // 1) The underlying method expects a caller location parameter - // in the ABI - if resolved.def.requires_caller_location(tcx) - // 2) The caller location parameter comes from having `#[track_caller]` - // on the implementation, and *not* on the trait method. - && !tcx.should_inherit_track_caller(def) - // If the method implementation comes from the trait definition itself - // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), - // then we don't need to generate a shim. This check is needed because - // `should_inherit_track_caller` returns `false` if our method - // implementation comes from the trait block, and not an impl block - && !matches!( - tcx.opt_associated_item(def), - Some(ty::AssocItem { - container: ty::AssocItemContainer::TraitContainer, - .. - }) - ) - { - if tcx.is_closure_like(def) { - debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", - def, def_id, args); - - // Create a shim for the `FnOnce/FnMut/Fn` method we are calling - // - unlike functions, invoking a closure always goes through a - // trait. - resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; - } else { - debug!( - " => vtable fn pointer created for function with #[track_caller]: {:?}", def - ); - resolved.def = InstanceKind::ReifyShim(def, reason); - } - } - } - InstanceKind::Virtual(def_id, _) => { - debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceKind::ReifyShim(def_id, reason) + return Instance { def: InstanceKind::VTableShim(def_id), args }; + } + + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args); + + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); + match resolved.def { + InstanceKind::Item(def) => { + // We need to generate a shim when we cannot guarantee that + // the caller of a trait object method will be aware of + // `#[track_caller]` - this ensures that the caller + // and callee ABI will always match. + // + // The shim is generated when all of these conditions are met: + // + // 1) The underlying method expects a caller location parameter + // in the ABI + if resolved.def.requires_caller_location(tcx) + // 2) The caller location parameter comes from having `#[track_caller]` + // on the implementation, and *not* on the trait method. + && !tcx.should_inherit_track_caller(def) + // If the method implementation comes from the trait definition itself + // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), + // then we don't need to generate a shim. This check is needed because + // `should_inherit_track_caller` returns `false` if our method + // implementation comes from the trait block, and not an impl block + && !matches!( + tcx.opt_associated_item(def), + Some(ty::AssocItem { + container: ty::AssocItemContainer::TraitContainer, + .. + }) + ) + { + if tcx.is_closure_like(def) { + debug!( + " => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", + def, def_id, args + ); + + // Create a shim for the `FnOnce/FnMut/Fn` method we are calling + // - unlike functions, invoking a closure always goes through a + // trait. + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; + } else { + debug!( + " => vtable fn pointer created for function with #[track_caller]: {:?}", + def + ); + resolved.def = InstanceKind::ReifyShim(def, reason); } - _ => {} } - - resolved - }) + } + InstanceKind::Virtual(def_id, _) => { + debug!(" => vtable fn pointer created for virtual call"); + resolved.def = InstanceKind::ReifyShim(def_id, reason) + } + _ => {} } + + resolved } pub fn resolve_closure( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index e54ced85deeb7..e710b17a10d6e 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -285,13 +285,13 @@ fn vtable_entries<'tcx>( return VtblEntry::Vacant; } - let instance = ty::Instance::resolve_for_vtable( + let instance = ty::Instance::expect_resolve_for_vtable( tcx, ty::ParamEnv::reveal_all(), def_id, args, - ) - .expect("resolution failed during building vtable representation"); + ); + VtblEntry::Method(instance) }); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index c50a490a9dc0c..7b6d86d22a578 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -16,7 +16,7 @@ use traits::{translate_args, Reveal}; use crate::errors::UnexpectedFnPtrAssociatedItem; -fn resolve_instance<'tcx>( +fn resolve_instance_raw<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>, ) -> Result>, ErrorGuaranteed> { @@ -364,5 +364,5 @@ fn resolve_associated_item<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { resolve_instance, ..*providers }; + *providers = Providers { resolve_instance_raw, ..*providers }; } From 9dc129ae829f8f322421dc9fb2c64d58e11eb08a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 13:06:23 -0400 Subject: [PATCH 092/189] Give Instance::expect_resolve a span --- .../rustc_codegen_cranelift/src/abi/mod.rs | 11 +++++++--- .../rustc_codegen_cranelift/src/main_shim.rs | 2 ++ compiler/rustc_codegen_gcc/src/context.rs | 1 + compiler/rustc_codegen_llvm/src/context.rs | 1 + compiler/rustc_codegen_ssa/src/base.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + .../src/const_eval/machine.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 12 ++++++----- compiler/rustc_monomorphize/src/collector.rs | 20 +++++++++++++++---- 9 files changed, 38 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 0d7eee7afb41e..81dfde81e938c 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -371,9 +371,14 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Handle special calls like intrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { - let instance = - ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args) - .polymorphize(fx.tcx); + let instance = ty::Instance::expect_resolve( + fx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + fn_args, + Some(source_info.span), + ) + .polymorphize(fx.tcx); if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 33d3f9b8a90a3..d1dc147dba8f8 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -119,6 +119,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), + None, ) .polymorphize(tcx); @@ -144,6 +145,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), + None, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 6231b09552cea..88ffcd7f4b502 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -479,6 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), + None, ); let symbol_name = tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1a8e8efdae507..a012c40ec0a6f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -580,6 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), + None, )), _ => { let name = name.unwrap_or("rust_eh_personality"); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c18816533a2fb..1be4cb186a7e9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -467,6 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty::ParamEnv::reveal_all(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), + None, ); let start_fn = cx.get_fn_addr(start_instance); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b1c22faf1ae9d..8b302b59e1312 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -842,6 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), def_id, args, + Some(fn_span), ) .polymorphize(bx.tcx()), ), diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 99276bac03501..cb3288402c11b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -253,6 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ty::ParamEnv::reveal_all(), const_def_id, instance.args, + Some(self.find_closest_untracked_caller_location()), ); return Ok(Some(new_instance)); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 99ac503cd6800..6d7c04fca4b94 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -13,7 +13,7 @@ use rustc_macros::{ }; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -513,10 +513,12 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, + span: Option, ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, - instance => bug!( + instance => span_bug!( + span.unwrap_or(tcx.def_span(def_id)), "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_args(def_id, args) ), @@ -588,7 +590,7 @@ impl<'tcx> Instance<'tcx> { return Instance { def: InstanceKind::VTableShim(def_id), args }; } - let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args); + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, None); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); match resolved.def { @@ -665,13 +667,13 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 235743fccc89e..8915876226572 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -916,7 +916,13 @@ fn visit_fn_use<'tcx>( ) { if let ty::FnDef(def_id, args) = *ty.kind() { let instance = if is_direct_call { - ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + ty::Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + Some(source), + ) } else { match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) { Some(instance) => instance, @@ -1318,8 +1324,13 @@ fn visit_mentioned_item<'tcx>( match *item { MentionedItem::Fn(ty) => { if let ty::FnDef(def_id, args) = *ty.kind() { - let instance = - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args); + let instance = Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + Some(span), + ); // `visit_instance_use` was written for "used" item collection but works just as well // for "mentioned" item collection. // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway @@ -1544,6 +1555,7 @@ impl<'v> RootCollector<'_, 'v> { ty::ParamEnv::reveal_all(), start_def_id, self.tcx.mk_args(&[main_ret_ty.into()]), + None, ); self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); @@ -1614,7 +1626,7 @@ fn create_mono_items_for_default_impls<'tcx>( // As mentioned above, the method is legal to eagerly instantiate if it // only has lifetime generic parameters. This is validated by let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); - let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args); + let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, None); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { From 0f7f3f4045a3b34678584a4148ff452f8a072904 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 May 2024 14:09:40 -0400 Subject: [PATCH 093/189] Re-implement a type-size based limit --- compiler/rustc_middle/messages.ftl | 6 ++ compiler/rustc_middle/src/error.rs | 14 ++++ compiler/rustc_middle/src/middle/limits.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 82 +++++++++++++++++-- compiler/rustc_middle/src/ty/print/mod.rs | 32 +++++++- compiler/rustc_monomorphize/messages.ftl | 5 -- compiler/rustc_monomorphize/src/collector.rs | 69 +--------------- compiler/rustc_monomorphize/src/errors.rs | 13 --- ...issue-72408-nested-closures-exponential.rs | 4 +- ...e-72408-nested-closures-exponential.stderr | 10 +++ tests/ui/codegen/overflow-during-mono.rs | 1 - tests/ui/codegen/overflow-during-mono.stderr | 11 +-- tests/ui/issues/issue-22638.rs | 5 +- tests/ui/issues/issue-22638.stderr | 17 ++-- .../issue-37311.rs | 4 +- .../issue-37311.stderr | 10 +-- .../issue-58952-filter-type-length.rs | 7 +- .../issue-58952-filter-type-length.stderr | 8 ++ .../ui/iterators/iter-map-fold-type-length.rs | 2 +- tests/ui/recursion/issue-83150.rs | 5 +- tests/ui/recursion/issue-83150.stderr | 16 ++-- .../traits/issue-91949-hangs-on-recursion.rs | 6 +- .../issue-91949-hangs-on-recursion.stderr | 20 ++--- tests/ui/type_length_limit.rs | 4 +- tests/ui/type_length_limit.stderr | 13 ++- 25 files changed, 206 insertions(+), 160 deletions(-) create mode 100644 tests/ui/closures/issue-72408-nested-closures-exponential.stderr create mode 100644 tests/ui/iterators/issue-58952-filter-type-length.stderr diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index f4d619329eb9c..2b9d9a07a98ef 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -41,6 +41,9 @@ middle_cannot_be_normalized = middle_conflict_types = this expression supplies two conflicting concrete types for the same opaque type +middle_consider_type_length_limit = + consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate + middle_const_eval_non_int = constant evaluation of enum discriminant resulted in non-integer @@ -94,8 +97,11 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute +middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` + middle_unknown_layout = the type `{$ty}` has an unknown layout middle_values_too_big = values of the type `{$ty}` are too big for the current architecture +middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 6e622b0405f0a..711db4e0a6bdb 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::path::PathBuf; use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -149,3 +150,16 @@ pub struct ErroneousConstant { /// Used by `rustc_const_eval` pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; + +#[derive(Diagnostic)] +#[diag(middle_type_length_limit)] +#[help(middle_consider_type_length_limit)] +pub struct TypeLengthLimit { + #[primary_span] + pub span: Span, + pub shrunk: String, + #[note(middle_written_to_path)] + pub was_written: Option<()>, + pub path: PathBuf, + pub type_length: usize, +} diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 4d69801274956..d0b4f36a426fd 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -30,7 +30,7 @@ pub fn provide(providers: &mut Providers) { tcx.hir().krate_attrs(), tcx.sess, sym::type_length_limit, - 1048576, + 2usize.pow(24), ), } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6d7c04fca4b94..65039d8b52c22 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,23 +1,25 @@ +use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; -use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt}; +use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer}; +use crate::ty::{ + self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::FiniteBitSet; -use rustc_macros::{ - Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable, TypeVisitable, -}; +use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, DUMMY_SP}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; use std::fmt; +use std::path::PathBuf; /// An `InstanceKind` along with the args that are needed to substitute the instance. /// @@ -385,7 +387,28 @@ impl<'tcx> InstanceKind<'tcx> { } } -fn fmt_instance( +fn type_length<'tcx>(item: impl TypeVisitable>) -> usize { + struct Visitor { + type_length: usize, + } + impl<'tcx> TypeVisitor> for Visitor { + fn visit_ty(&mut self, t: Ty<'tcx>) { + self.type_length += 1; + t.super_visit_with(self); + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + self.type_length += 1; + ct.super_visit_with(self); + } + } + let mut visitor = Visitor { type_length: 0 }; + item.visit_with(&mut visitor); + + visitor.type_length +} + +pub fn fmt_instance( f: &mut fmt::Formatter<'_>, instance: Instance<'_>, type_length: Option, @@ -485,7 +508,8 @@ impl<'tcx> Instance<'tcx> { /// /// Presuming that coherence and type-check have succeeded, if this method is invoked /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return - /// `Ok(Some(instance))`. + /// `Ok(Some(instance))`, **except** for when the instance's inputs hit the type size limit, + /// in which case it may bail out and return `Ok(None)`. /// /// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process /// couldn't complete due to errors elsewhere - this is distinct @@ -498,6 +522,16 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, args: GenericArgsRef<'tcx>, ) -> Result>, ErrorGuaranteed> { + // Rust code can easily create exponentially-long types using only a + // polynomial recursion depth. Even with the default recursion + // depth, you can easily get cases that take >2^60 steps to run, + // which means that rustc basically hangs. + // + // Bail out in these cases to avoid that bad user experience. + if !tcx.type_length_limit().value_within_limit(type_length(args)) { + return Ok(None); + } + // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. @@ -517,6 +551,36 @@ impl<'tcx> Instance<'tcx> { ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, + Ok(None) => { + let type_length = type_length(args); + if !tcx.type_length_limit().value_within_limit(type_length) { + let (shrunk, written_to_path) = + shrunk_instance_name(tcx, Instance::new(def_id, args)); + let mut path = PathBuf::new(); + let was_written = if let Some(path2) = written_to_path { + path = path2; + Some(()) + } else { + None + }; + tcx.dcx().emit_fatal(error::TypeLengthLimit { + // We don't use `def_span(def_id)` so that diagnostics point + // to the crate root during mono instead of to foreign items. + // This is arguably better. + span: span.unwrap_or(DUMMY_SP), + shrunk, + was_written, + path, + type_length, + }); + } else { + span_bug!( + span.unwrap_or(tcx.def_span(def_id)), + "failed to resolve instance for {}", + tcx.def_path_str_with_args(def_id, args) + ) + } + } instance => span_bug!( span.unwrap_or(tcx.def_span(def_id)), "failed to resolve instance for {}: {instance:#?}", diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 3c27df9529aa1..c165790548d75 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,5 +1,7 @@ +use std::path::PathBuf; + use crate::ty::GenericArg; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, ShortInstance, Ty, TyCtxt}; use hir::def::Namespace; use rustc_data_structures::fx::FxHashSet; @@ -356,3 +358,31 @@ where with_no_trimmed_paths!(Self::print(t, fmt)) } } + +/// Format instance name that is already known to be too long for rustc. +/// Show only the first 2 types if it is longer than 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +pub fn shrunk_instance_name<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +) -> (String, Option) { + let s = instance.to_string(); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if s.chars().nth(33).is_some() { + let shrunk = format!("{}", ShortInstance(instance, 4)); + if shrunk == s { + return (s, None); + } + + let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); + + (shrunk, written_to_path) + } else { + (s, None) + } +} diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 94b553a07a755..7210701d4828c 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,6 +1,3 @@ -monomorphize_consider_type_length_limit = - consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate - monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} @@ -25,8 +22,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined -monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` - monomorphize_unknown_cgu_collection_mode = unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8915876226572..f98d4700528d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -222,12 +222,12 @@ use rustc_middle::mir::{self, Location, MentionedItem}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths}; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{ self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; -use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::{bug, span_bug}; use rustc_session::config::EntryFnType; use rustc_session::Limit; @@ -238,9 +238,7 @@ use rustc_target::abi::Size; use std::path::PathBuf; use tracing::{debug, instrument, trace}; -use crate::errors::{ - self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit, -}; +use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit}; use move_check::MoveCheckState; #[derive(PartialEq)] @@ -443,7 +441,6 @@ fn collect_items_rec<'tcx>( recursion_depths, recursion_limit, )); - check_type_length_limit(tcx, instance); rustc_data_structures::stack::ensure_sufficient_stack(|| { collect_items_of_instance( @@ -554,34 +551,6 @@ fn collect_items_rec<'tcx>( } } -/// Format instance name that is already known to be too long for rustc. -/// Show only the first 2 types if it is longer than 32 characters to avoid blasting -/// the user's terminal with thousands of lines of type-name. -/// -/// If the type name is longer than before+after, it will be written to a file. -fn shrunk_instance_name<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, -) -> (String, Option) { - let s = instance.to_string(); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if s.chars().nth(33).is_some() { - let shrunk = format!("{}", ty::ShortInstance(instance, 4)); - if shrunk == s { - return (s, None); - } - - let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); - let written_to_path = std::fs::write(&path, s).ok().map(|_| path); - - (shrunk, written_to_path) - } else { - (s, None) - } -} - fn check_recursion_limit<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -630,38 +599,6 @@ fn check_recursion_limit<'tcx>( (def_id, recursion_depth) } -fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance - .args - .iter() - .flat_map(|arg| arg.walk()) - .filter(|arg| match arg.unpack() { - GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, - GenericArgKind::Lifetime(_) => false, - }) - .count(); - debug!(" => type length={}", type_length); - - // Rust code can easily create exponentially-long types using only a - // polynomial recursion depth. Even with the default recursion - // depth, you can easily get cases that take >2^60 steps to run, - // which means that rustc basically hangs. - // - // Bail out in these cases to avoid that bad user experience. - if !tcx.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance); - let span = tcx.def_span(instance.def_id()); - let mut path = PathBuf::new(); - let was_written = if let Some(path2) = written_to_path { - path = path2; - Some(()) - } else { - None - }; - tcx.dcx().emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length }); - } -} - struct MirUsedCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index c0d1efd96c5b7..9548c46e6fa04 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -19,19 +19,6 @@ pub struct RecursionLimit { pub path: PathBuf, } -#[derive(Diagnostic)] -#[diag(monomorphize_type_length_limit)] -#[help(monomorphize_consider_type_length_limit)] -pub struct TypeLengthLimit { - #[primary_span] - pub span: Span, - pub shrunk: String, - #[note(monomorphize_written_to_path)] - pub was_written: Option<()>, - pub path: PathBuf, - pub type_length: usize, -} - #[derive(Diagnostic)] #[diag(monomorphize_no_optimized_mir)] pub struct NoOptimizedMir { diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs index 682508f928082..033e422433861 100644 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,5 +1,4 @@ -//@ build-pass -//@ ignore-compare-mode-next-solver (hangs) +//@ build-fail // Closures include captured types twice in a type tree. // @@ -46,6 +45,7 @@ fn main() { let f = dup(f); let f = dup(f); + //~^ ERROR reached the type-length limit let f = dup(f); let f = dup(f); let f = dup(f); diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr new file mode 100644 index 0000000000000..2120b45696392 --- /dev/null +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr @@ -0,0 +1,10 @@ +error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>` + --> $DIR/issue-72408-nested-closures-exponential.rs:47:13 + | +LL | let f = dup(f); + | ^^^^^^ + | + = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate + +error: aborting due to 1 previous error + diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 919f1a8120e0b..278298f27ff0e 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,5 +1,4 @@ //@ build-fail -//~^ ERROR overflow evaluating the requirement #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index f7a3e2df3dbaa..9e463378004dc 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,11 +1,8 @@ -error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:12:41: 12:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` + --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` - = note: 31 redundant requirements hidden - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` + = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt' error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs index 3e04eb41b98de..3e401e99fb48d 100644 --- a/tests/ui/issues/issue-22638.rs +++ b/tests/ui/issues/issue-22638.rs @@ -1,7 +1,4 @@ //@ build-fail -//@ normalize-stderr-test: "<\{closure@.+`" -> "$$CLOSURE`" -//@ normalize-stderr-test: ".nll/" -> "/" -//@ ignore-compare-mode-next-solver (hangs) #![allow(unused)] @@ -43,6 +40,7 @@ impl C { pub fn matches(&self, f: &F) { let &C(ref base) = self; base.matches(&|| { + //~^ ERROR reached the type-length limit C(base.clone()).matches(f) }) } @@ -55,7 +53,6 @@ impl D { pub fn matches(&self, f: &F) { let &D(ref a) = self; a.matches(f) - //~^ ERROR reached the recursion limit while instantiating `A::matches::<{closure } } diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr index 45290f6afe9de..1344409c77040 100644 --- a/tests/ui/issues/issue-22638.stderr +++ b/tests/ui/issues/issue-22638.stderr @@ -1,14 +1,13 @@ -error: reached the recursion limit while instantiating `A::matches::$CLOSURE` - --> $DIR/issue-22638.rs:57:9 +error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` + --> $DIR/issue-22638.rs:42:9 | -LL | a.matches(f) - | ^^^^^^^^^^^^ +LL | / base.matches(&|| { +LL | | +LL | | C(base.clone()).matches(f) +LL | | }) + | |__________^ | -note: `A::matches` defined here - --> $DIR/issue-22638.rs:16:5 - | -LL | pub fn matches(&self, f: &F) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs index 1646f16e1ecea..131c7535537f6 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,6 +1,5 @@ //@ build-fail //@ normalize-stderr-test: ".nll/" -> "/" -//@ ignore-compare-mode-next-solver (hangs) trait Mirror { type Image; @@ -15,7 +14,8 @@ trait Foo { impl Foo for T { #[allow(unconditional_recursion)] fn recurse(&self) { - (self, self).recurse(); //~ ERROR reached the recursion limit + (self, self).recurse(); + //~^ ERROR reached the type-length limit } } diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index ccee9ed4daadb..2978ced527949 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,14 +1,10 @@ -error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:18:9 +error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` + --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | -note: `::recurse` defined here - --> $DIR/issue-37311.rs:17:5 - | -LL | fn recurse(&self) { - | ^^^^^^^^^^^^^^^^^ + = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index 9904eddb598ce..b2c208ae28f19 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,5 +1,4 @@ -//@ run-pass -//@ ignore-compare-mode-next-solver (hangs) +//@ build-fail //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. @@ -30,5 +29,9 @@ fn main() { .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) .collect::>(); } diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr new file mode 100644 index 0000000000000..975fcd4afffee --- /dev/null +++ b/tests/ui/iterators/issue-58952-filter-type-length.stderr @@ -0,0 +1,8 @@ +error: reached the type-length limit while instantiating ` as Iterator>::try_fold::, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>` + --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL + | + = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt' + +error: aborting due to 1 previous error + diff --git a/tests/ui/iterators/iter-map-fold-type-length.rs b/tests/ui/iterators/iter-map-fold-type-length.rs index 6444fb9dada98..5f9567d68e819 100644 --- a/tests/ui/iterators/iter-map-fold-type-length.rs +++ b/tests/ui/iterators/iter-map-fold-type-length.rs @@ -3,7 +3,7 @@ //! //! The normal limit is a million, and this test used to exceed 1.5 million, but //! now we can survive an even tighter limit. Still seems excessive though... -#![type_length_limit = "256000"] +#![type_length_limit = "1327047"] // Custom wrapper so Iterator methods aren't specialized. struct Iter(I); diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs index b74b2adfeab47..b3ddf88c4493f 100644 --- a/tests/ui/recursion/issue-83150.rs +++ b/tests/ui/recursion/issue-83150.rs @@ -1,7 +1,6 @@ //@ build-fail //@ compile-flags: -Copt-level=0 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -//~^^^ ERROR overflow evaluating the requirement //@ ignore-compare-mode-next-solver (hangs) fn main() { @@ -9,6 +8,8 @@ fn main() { func(&mut iter) } -fn func>(iter: &mut T) { //~ WARN function cannot return without recursing +fn func>(iter: &mut T) { + //~^ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) + //~^ ERROR reached the type-length limit } diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr index 783f9cf763254..127de98ddc5b9 100644 --- a/tests/ui/recursion/issue-83150.stderr +++ b/tests/ui/recursion/issue-83150.stderr @@ -1,21 +1,23 @@ warning: function cannot return without recursing - --> $DIR/issue-83150.rs:12:1 + --> $DIR/issue-83150.rs:11:1 | LL | fn func>(iter: &mut T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | LL | func(&mut iter.map(|x| x + 1)) | ------------------------------ recursive call site | = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator` +error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>` + --> $DIR/issue-83150.rs:13:15 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) - = note: required for `&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator` - = note: 65 redundant requirements hidden - = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator` +LL | func(&mut iter.map(|x| x + 1)) + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt' error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index ddbbcdd052965..d9c422e6f7096 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,9 +1,5 @@ //@ build-fail //@ compile-flags: -Zinline-mir=no -//@ error-pattern: overflow evaluating the requirement ` as Iterator>::Item == ()` -//@ error-pattern: function cannot return without recursing -//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -//@ ignore-compare-mode-next-solver (hangs) // Regression test for #91949. // This hanged *forever* on 1.56, fixed by #90423. @@ -22,10 +18,12 @@ impl> Iterator for IteratorOfWrapped { } fn recurse(elements: T) -> Vec +//~^ WARN function cannot return without recursing where T: Iterator, { recurse(IteratorOfWrapped(elements).map(|t| t.0)) + //~^ ERROR reached the type-length limit } fn main() { diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index c4324f0f0a872..c46c78609d2c3 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,7 +1,8 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:24:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:20:1 | LL | / fn recurse(elements: T) -> Vec +LL | | LL | | where LL | | T: Iterator, | |___________________________^ cannot return without recursing @@ -12,19 +13,14 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement ` as Iterator>::Item == ()` +error: reached the type-length limit while instantiating `, ...>> as Iterator>::map::<..., ...>` + --> $DIR/issue-91949-hangs-on-recursion.rs:25:13 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) -note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` - --> $DIR/issue-91949-hangs-on-recursion.rs:17:32 +LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | impl> Iterator for IteratorOfWrapped { - | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: 256 redundant requirements hidden - = note: required for `IteratorOfWrapped<(), Map>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>` to implement `Iterator` + = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt' error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs index c60f1be06c671..d6937481a1551 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/type_length_limit.rs @@ -1,7 +1,6 @@ //@ build-fail -//@ error-pattern: reached the type-length limit while instantiating //@ compile-flags: -Copt-level=0 -//@ normalize-stderr-test: ".nll/" -> "/" +//~^^ ERROR reached the type-length limit // Test that the type length limit can be changed. // The exact type depends on optimizations, so disable them. @@ -31,4 +30,5 @@ pub struct G(std::marker::PhantomData::<(T, K)>); fn main() { drop::>(None); + //~^ ERROR reached the type-length limit } diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/type_length_limit.stderr index 32290a2f5bfc7..83353547d34db 100644 --- a/tests/ui/type_length_limit.stderr +++ b/tests/ui/type_length_limit.stderr @@ -1,8 +1,15 @@ error: reached the type-length limit while instantiating `std::mem::drop::>` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + --> $DIR/type_length_limit.rs:32:5 | - = help: consider adding a `#![type_length_limit="10"]` attribute to your crate +LL | drop::>(None); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#![type_length_limit="4010"]` attribute to your crate = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' -error: aborting due to 1 previous error +error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut` + | + = help: consider adding a `#![type_length_limit="10"]` attribute to your crate + +error: aborting due to 2 previous errors From 3273ccea4b2c1995a7ddd059657ded593eb859c9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 1 Jul 2024 16:32:32 -0400 Subject: [PATCH 094/189] Fix spans --- .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../rustc_codegen_cranelift/src/main_shim.rs | 5 ++-- compiler/rustc_codegen_gcc/src/context.rs | 4 ++-- compiler/rustc_codegen_llvm/src/context.rs | 4 ++-- compiler/rustc_codegen_ssa/src/base.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../src/const_eval/machine.rs | 2 +- .../src/interpret/terminator.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 21 ++++++++++------ compiler/rustc_monomorphize/src/collector.rs | 24 ++++++------------- .../src/traits/vtable.rs | 3 ++- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 81dfde81e938c..9dc94ab33ea9e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( ty::ParamEnv::reveal_all(), def_id, fn_args, - Some(source_info.span), + source_info.span, ) .polymorphize(fx.tcx); diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index d1dc147dba8f8..fe0a15514190c 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::AssocKind; use rustc_middle::ty::GenericArg; use rustc_session::config::{sigpipe, EntryFnType}; use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; use crate::prelude::*; @@ -119,7 +120,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), - None, + DUMMY_SP, ) .polymorphize(tcx); @@ -145,7 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 88ffcd7f4b502..1d689c9ac0ef1 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::{source_map::respan, Span}; +use rustc_span::{source_map::respan, Span, DUMMY_SP}; use rustc_target::abi::{ call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, }; @@ -479,7 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), - None, + DUMMY_SP, ); let symbol_name = tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index a012c40ec0a6f..77beb9a6bb386 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -28,7 +28,7 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; @@ -580,7 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), - None, + DUMMY_SP, )), _ => { let name = name.unwrap_or("rust_eh_personality"); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1be4cb186a7e9..137f14fe706cc 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -37,7 +37,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_span::Symbol; +use rustc_span::{Symbol, DUMMY_SP}; use rustc_target::abi::FIRST_VARIANT; use std::cmp; @@ -467,7 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty::ParamEnv::reveal_all(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ); let start_fn = cx.get_fn_addr(start_instance); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 8b302b59e1312..f5c7821fd7015 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -842,7 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), def_id, args, - Some(fn_span), + fn_span, ) .polymorphize(bx.tcx()), ), diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index cb3288402c11b..17e1d8566c26c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -253,7 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ty::ParamEnv::reveal_all(), const_def_id, instance.args, - Some(self.find_closest_untracked_caller_location()), + self.cur_span(), ); return Ok(Some(new_instance)); diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index f59293e7266ac..68acddf63d86e 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -888,6 +888,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.param_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), + self.cur_span(), ); assert_eq!(fn_inst, concrete_method); } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 65039d8b52c22..3f854ba74916f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -547,8 +547,14 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, - span: Option, + span: Span, ) -> Instance<'tcx> { + // We compute the span lazily, to avoid unnecessary query calls. + // If `span` is a DUMMY_SP, and the def id is local, then use the + // def span of the def id. + let span_or_local_def_span = + || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span }; + match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, Ok(None) => { @@ -567,7 +573,7 @@ impl<'tcx> Instance<'tcx> { // We don't use `def_span(def_id)` so that diagnostics point // to the crate root during mono instead of to foreign items. // This is arguably better. - span: span.unwrap_or(DUMMY_SP), + span: span_or_local_def_span(), shrunk, was_written, path, @@ -575,14 +581,14 @@ impl<'tcx> Instance<'tcx> { }); } else { span_bug!( - span.unwrap_or(tcx.def_span(def_id)), + span_or_local_def_span(), "failed to resolve instance for {}", tcx.def_path_str_with_args(def_id, args) ) } } instance => span_bug!( - span.unwrap_or(tcx.def_span(def_id)), + span_or_local_def_span(), "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_args(def_id, args) ), @@ -642,6 +648,7 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, + span: Span, ) -> Instance<'tcx> { debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args); let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); @@ -654,7 +661,7 @@ impl<'tcx> Instance<'tcx> { return Instance { def: InstanceKind::VTableShim(def_id), args }; } - let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, None); + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); match resolved.def { @@ -731,13 +738,13 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f98d4700528d5..342c01ff69731 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -853,13 +853,7 @@ fn visit_fn_use<'tcx>( ) { if let ty::FnDef(def_id, args) = *ty.kind() { let instance = if is_direct_call { - ty::Instance::expect_resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - args, - Some(source), - ) + ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source) } else { match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) { Some(instance) => instance, @@ -1261,13 +1255,8 @@ fn visit_mentioned_item<'tcx>( match *item { MentionedItem::Fn(ty) => { if let ty::FnDef(def_id, args) = *ty.kind() { - let instance = Instance::expect_resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - args, - Some(span), - ); + let instance = + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span); // `visit_instance_use` was written for "used" item collection but works just as well // for "mentioned" item collection. // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway @@ -1492,7 +1481,7 @@ impl<'v> RootCollector<'_, 'v> { ty::ParamEnv::reveal_all(), start_def_id, self.tcx.mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ); self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); @@ -1561,9 +1550,10 @@ fn create_mono_items_for_default_impls<'tcx>( } // As mentioned above, the method is legal to eagerly instantiate if it - // only has lifetime generic parameters. This is validated by + // only has lifetime generic parameters. This is validated by calling + // `own_requires_monomorphization` on both the impl and method. let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); - let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, None); + let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index e710b17a10d6e..8f56f9c0f3eea 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry}; use rustc_middle::ty::{GenericArgs, TypeVisitableExt}; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::fmt::Debug; @@ -290,6 +290,7 @@ fn vtable_entries<'tcx>( ty::ParamEnv::reveal_all(), def_id, args, + DUMMY_SP, ); VtblEntry::Method(instance) From a21ba348964e6d72a3369daa4bc22af507eb7778 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 23:01:24 -0400 Subject: [PATCH 095/189] add TyCtxt::as_lang_item, use in new solver --- compiler/rustc_hir/src/lang_items.rs | 13 ++- .../rustc_middle/src/middle/lang_items.rs | 4 + compiler/rustc_middle/src/ty/context.rs | 95 +++++++++++-------- .../src/solve/assembly/mod.rs | 87 +++++++++-------- compiler/rustc_type_ir/src/interner.rs | 2 + 5 files changed, 126 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3c44acb16577a..30c0e40206aaf 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -11,6 +11,7 @@ use crate::def_id::DefId; use crate::{MethodKind, Target}; use rustc_ast as ast; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -23,6 +24,7 @@ pub struct LanguageItems { /// Mappings from lang items to their possibly found [`DefId`]s. /// The index corresponds to the order in [`LangItem`]. items: [Option; std::mem::variant_count::()], + reverse_items: FxIndexMap, /// Lang items that were not found during collection. pub missing: Vec, } @@ -30,7 +32,11 @@ pub struct LanguageItems { impl LanguageItems { /// Construct an empty collection of lang items and no missing ones. pub fn new() -> Self { - Self { items: [None; std::mem::variant_count::()], missing: Vec::new() } + Self { + items: [None; std::mem::variant_count::()], + reverse_items: FxIndexMap::default(), + missing: Vec::new(), + } } pub fn get(&self, item: LangItem) -> Option { @@ -39,6 +45,11 @@ impl LanguageItems { pub fn set(&mut self, item: LangItem, def_id: DefId) { self.items[item as usize] = Some(def_id); + self.reverse_items.insert(def_id, item); + } + + pub fn from_def_id(&self, def_id: DefId) -> Option { + self.reverse_items.get(&def_id).copied() } pub fn iter(&self) -> impl Iterator + '_ { diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index e76d7af6e4aba..a0c9af436e207 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -27,6 +27,10 @@ impl<'tcx> TyCtxt<'tcx> { self.lang_items().get(lang_item) == Some(def_id) } + pub fn as_lang_item(self, def_id: DefId) -> Option { + self.lang_items().from_def_id(def_id) + } + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9225ae6300fc6..155a76713cab6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -366,6 +366,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item)) } + fn as_lang_item(self, def_id: DefId) -> Option { + lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?) + } + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() @@ -584,46 +588,63 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } } -fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { - match lang_item { - TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct, - TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper, - TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars, - TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, - TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator, - TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, - TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture, - TraitSolverLangItem::Clone => LangItem::Clone, - TraitSolverLangItem::Copy => LangItem::Copy, - TraitSolverLangItem::Coroutine => LangItem::Coroutine, - TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, - TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield, - TraitSolverLangItem::Destruct => LangItem::Destruct, - TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, - TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, - TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, - TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection, - TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput, - TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, - TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, - TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, - TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, - TraitSolverLangItem::Future => LangItem::Future, - TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, - TraitSolverLangItem::Iterator => LangItem::Iterator, - TraitSolverLangItem::Metadata => LangItem::Metadata, - TraitSolverLangItem::Option => LangItem::Option, - TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, - TraitSolverLangItem::PointerLike => LangItem::PointerLike, - TraitSolverLangItem::Poll => LangItem::Poll, - TraitSolverLangItem::Sized => LangItem::Sized, - TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait, - TraitSolverLangItem::Tuple => LangItem::Tuple, - TraitSolverLangItem::Unpin => LangItem::Unpin, - TraitSolverLangItem::Unsize => LangItem::Unsize, +macro_rules! bidirectional_lang_item_map { + ($($name:ident),+ $(,)?) => { + fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { + match lang_item { + $(TraitSolverLangItem::$name => LangItem::$name,)+ + } + } + + fn lang_item_to_trait_lang_item(lang_item: LangItem) -> Option { + Some(match lang_item { + $(LangItem::$name => TraitSolverLangItem::$name,)+ + _ => return None, + }) + } } } +bidirectional_lang_item_map! { +// tidy-alphabetical-start + AsyncDestruct, + AsyncFnKindHelper, + AsyncFnKindUpvars, + AsyncFnOnceOutput, + AsyncIterator, + CallOnceFuture, + CallRefFuture, + Clone, + Copy, + Coroutine, + CoroutineReturn, + CoroutineYield, + Destruct, + DiscriminantKind, + DynMetadata, + EffectsMaybe, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsNoRuntime, + EffectsRuntime, + FnPtrTrait, + FusedIterator, + Future, + FutureOutput, + Iterator, + Metadata, + Option, + PointeeTrait, + PointerLike, + Poll, + Sized, + TransmuteTrait, + Tuple, + Unpin, + Unsize, +// tidy-alphabetical-end +} + impl<'tcx> rustc_type_ir::inherent::DefId> for DefId { fn as_local(self) -> Option { self.as_local() diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 6ee684605ac60..20a0da16c7521 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -387,48 +387,61 @@ where G::consider_auto_trait_candidate(self, goal) } else if cx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { - G::consider_builtin_sized_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) - || cx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) - { - G::consider_builtin_copy_clone_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { - G::consider_builtin_pointer_like_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { - G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { - G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { - G::consider_builtin_tuple_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { - G::consider_builtin_pointee_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { - G::consider_builtin_future_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { - G::consider_builtin_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { - G::consider_builtin_fused_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { - G::consider_builtin_async_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { - G::consider_builtin_coroutine_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { - G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { - G::consider_builtin_async_destruct_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { - G::consider_builtin_destruct_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { - G::consider_builtin_transmute_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) { - G::consider_builtin_effects_intersection_candidate(self, goal) } else { - Err(NoSolution) + match cx.as_lang_item(trait_def_id) { + Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal), + Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { + G::consider_builtin_copy_clone_candidate(self, goal) + } + Some(TraitSolverLangItem::PointerLike) => { + G::consider_builtin_pointer_like_candidate(self, goal) + } + Some(TraitSolverLangItem::FnPtrTrait) => { + G::consider_builtin_fn_ptr_trait_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncFnKindHelper) => { + G::consider_builtin_async_fn_kind_helper_candidate(self, goal) + } + Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal), + Some(TraitSolverLangItem::PointeeTrait) => { + G::consider_builtin_pointee_candidate(self, goal) + } + Some(TraitSolverLangItem::Future) => { + G::consider_builtin_future_candidate(self, goal) + } + Some(TraitSolverLangItem::Iterator) => { + G::consider_builtin_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::FusedIterator) => { + G::consider_builtin_fused_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncIterator) => { + G::consider_builtin_async_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::Coroutine) => { + G::consider_builtin_coroutine_candidate(self, goal) + } + Some(TraitSolverLangItem::DiscriminantKind) => { + G::consider_builtin_discriminant_kind_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncDestruct) => { + G::consider_builtin_async_destruct_candidate(self, goal) + } + Some(TraitSolverLangItem::Destruct) => { + G::consider_builtin_destruct_candidate(self, goal) + } + Some(TraitSolverLangItem::TransmuteTrait) => { + G::consider_builtin_transmute_candidate(self, goal) + } + Some(TraitSolverLangItem::EffectsIntersection) => { + G::consider_builtin_effects_intersection_candidate(self, goal) + } + _ => Err(NoSolution), + } }; candidates.extend(result); diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6665158c7cd34..84c7e6e8f2003 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -220,6 +220,8 @@ pub trait Interner: fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool; + fn as_lang_item(self, def_id: Self::DefId) -> Option; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; // FIXME: move `fast_reject` into `rustc_type_ir`. From 5a837515f28eed106dd031b0243d6476eba58dd9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 23:05:35 -0400 Subject: [PATCH 096/189] Make fn traits into first-class TraitSolverLangItems to avoid needing fn_trait_kind_from_def_id --- compiler/rustc_middle/src/ty/context.rs | 16 +++++----- .../src/solve/assembly/mod.rs | 30 ++++++++++++++++--- compiler/rustc_type_ir/src/interner.rs | 4 --- compiler/rustc_type_ir/src/lang_items.rs | 6 ++++ 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 155a76713cab6..7c3d2df72faa2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -537,14 +537,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(trait_def_id).implement_via_object } - fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { - self.fn_trait_kind_from_def_id(trait_def_id) - } - - fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { - self.async_fn_trait_kind_from_def_id(trait_def_id) - } - fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator { self.supertrait_def_ids(trait_def_id) } @@ -608,8 +600,11 @@ macro_rules! bidirectional_lang_item_map { bidirectional_lang_item_map! { // tidy-alphabetical-start AsyncDestruct, + AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnMut, + AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, CallOnceFuture, @@ -622,11 +617,14 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, - EffectsMaybe, EffectsIntersection, EffectsIntersectionOutput, + EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + Fn, + FnMut, + FnOnce, FnPtrTrait, FusedIterator, Future, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 20a0da16c7521..38a4f7dfe25cb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -387,16 +387,38 @@ where G::consider_auto_trait_candidate(self, goal) } else if cx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { - G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { - G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else { match cx.as_lang_item(trait_def_id) { Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal), Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { G::consider_builtin_copy_clone_candidate(self, goal) } + Some(TraitSolverLangItem::Fn) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn) + } + Some(TraitSolverLangItem::FnMut) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut) + } + Some(TraitSolverLangItem::FnOnce) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce) + } + Some(TraitSolverLangItem::AsyncFn) => { + G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn) + } + Some(TraitSolverLangItem::AsyncFnMut) => { + G::consider_builtin_async_fn_trait_candidates( + self, + goal, + ty::ClosureKind::FnMut, + ) + } + Some(TraitSolverLangItem::AsyncFnOnce) => { + G::consider_builtin_async_fn_trait_candidates( + self, + goal, + ty::ClosureKind::FnOnce, + ) + } Some(TraitSolverLangItem::PointerLike) => { G::consider_builtin_pointer_like_candidate(self, goal) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 84c7e6e8f2003..f76a2f55c482e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -254,10 +254,6 @@ pub trait Interner: fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; - fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; - - fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; - fn supertrait_def_ids(self, trait_def_id: Self::DefId) -> impl IntoIterator; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index cf00c37caa287..265a411882735 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -3,8 +3,11 @@ pub enum TraitSolverLangItem { // tidy-alphabetical-start AsyncDestruct, + AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnMut, + AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, CallOnceFuture, @@ -22,6 +25,9 @@ pub enum TraitSolverLangItem { EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + Fn, + FnMut, + FnOnce, FnPtrTrait, FusedIterator, Future, From ecdaff240da6938473d14f784f8ba9a8c5f3611b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 11:53:52 -0400 Subject: [PATCH 097/189] Actually report normalization-based type errors correctly for alias-relate obligations in new solver --- .../error_reporting/type_err_ctxt_ext.rs | 149 ++++++++++++------ .../as_expression.next.stderr | 5 +- .../issue-100222.nn.stderr | 5 +- .../issue-100222.ny.stderr | 5 +- .../issue-100222.yn.stderr | 5 +- .../issue-100222.yy.stderr | 5 +- tests/ui/traits/next-solver/async.fail.stderr | 6 +- tests/ui/traits/next-solver/async.rs | 2 +- .../next-solver/more-object-bound.stderr | 15 +- 9 files changed, 140 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index adf1076a7c90e..ff263eaac34fb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1586,60 +1586,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } self.probe(|_| { - let ocx = ObligationCtxt::new(self); - // try to find the mismatched types to report the error with. // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. let bound_predicate = predicate.kind(); - let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) = - bound_predicate.skip_binder() - { - let data = self.instantiate_binder_with_fresh_vars( - obligation.cause.span, - infer::BoundRegionConversionTime::HigherRankedType, - bound_predicate.rebind(data), - ); - let unnormalized_term = data.projection_term.to_term(self.tcx); - // FIXME(-Znext-solver): For diagnostic purposes, it would be nice - // to deeply normalize this type. - let normalized_term = - ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); - - debug!(?obligation.cause, ?obligation.param_env); - - debug!(?normalized_term, data.ty = ?data.term); + let (values, err) = match bound_predicate.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { + let ocx = ObligationCtxt::new(self); + + let data = self.instantiate_binder_with_fresh_vars( + obligation.cause.span, + infer::BoundRegionConversionTime::HigherRankedType, + bound_predicate.rebind(data), + ); + let unnormalized_term = data.projection_term.to_term(self.tcx); + // FIXME(-Znext-solver): For diagnostic purposes, it would be nice + // to deeply normalize this type. + let normalized_term = + ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); + + let is_normalized_term_expected = !matches!( + obligation.cause.code().peel_derives(), + ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) + | ObligationCauseCode::Coercion { .. } + ); - let is_normalized_term_expected = !matches!( - obligation.cause.code().peel_derives(), - |ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr( - .. - ) | ObligationCauseCode::Coercion { .. } - ); + let (expected, actual) = if is_normalized_term_expected { + (normalized_term, data.term) + } else { + (data.term, normalized_term) + }; - let (expected, actual) = if is_normalized_term_expected { - (normalized_term, data.term) - } else { - (data.term, normalized_term) - }; + // constrain inference variables a bit more to nested obligations from normalize so + // we can have more helpful errors. + // + // we intentionally drop errors from normalization here, + // since the normalization is just done to improve the error message. + let _ = ocx.select_where_possible(); - // constrain inference variables a bit more to nested obligations from normalize so - // we can have more helpful errors. - // - // we intentionally drop errors from normalization here, - // since the normalization is just done to improve the error message. - let _ = ocx.select_where_possible(); + if let Err(new_err) = + ocx.eq(&obligation.cause, obligation.param_env, expected, actual) + { + ( + Some(( + data.projection_term, + is_normalized_term_expected, + self.resolve_vars_if_possible(normalized_term), + data.term, + )), + new_err, + ) + } else { + (None, error.err) + } + } + ty::PredicateKind::AliasRelate(lhs, rhs, _) => { + let derive_better_type_error = + |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| { + let ocx = ObligationCtxt::new(self); + let normalized_term = match expected_term.unpack() { + ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(), + ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(), + }; + ocx.register_obligation(Obligation::new( + self.tcx, + ObligationCause::dummy(), + obligation.param_env, + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { + alias: alias_term, + term: normalized_term, + }), + )); + let _ = ocx.select_where_possible(); + if let Err(terr) = ocx.eq( + &ObligationCause::dummy(), + obligation.param_env, + expected_term, + normalized_term, + ) { + Some((terr, self.resolve_vars_if_possible(normalized_term))) + } else { + None + } + }; - if let Err(new_err) = - ocx.eq(&obligation.cause, obligation.param_env, expected, actual) - { - (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err) - } else { - (None, error.err) + if let Some(lhs) = lhs.to_alias_term() + && let Some((better_type_err, expected_term)) = + derive_better_type_error(lhs, rhs) + { + ( + Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)), + better_type_err, + ) + } else if let Some(rhs) = rhs.to_alias_term() + && let Some((better_type_err, expected_term)) = + derive_better_type_error(rhs, lhs) + { + ( + Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)), + better_type_err, + ) + } else { + (None, error.err) + } } - } else { - (None, error.err) + _ => (None, error.err), }; let msg = values @@ -1737,15 +1790,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn maybe_detailed_projection_msg( &self, - pred: ty::ProjectionPredicate<'tcx>, + projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, ) -> Option { - let trait_def_id = pred.projection_term.trait_def_id(self.tcx); - let self_ty = pred.projection_term.self_ty(); + let trait_def_id = projection_term.trait_def_id(self.tcx); + let self_ty = projection_term.self_ty(); with_forced_trimmed_paths! { - if self.tcx.is_lang_item(pred.projection_term.def_id,LangItem::FnOnceOutput) { + if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) { let fn_kind = self_ty.prefix_string(self.tcx); let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index d189d2dbdedc8..a686b913c55ef 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -29,7 +29,10 @@ error[E0271]: type mismatch resolving `::SqlType == Tex --> $DIR/as_expression.rs:57:5 | LL | SelectInt.check("bar"); - | ^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^ expected `Integer`, found `Text` + | + = note: expected struct `Integer` + found struct `Text` error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr index 4a949e90d8554..03536dca1e848 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr @@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde --> $DIR/issue-100222.rs:34:12 | LL | fn foo(&mut self, x: ::Output) -> ::Output - | ^^^^^^^^^ types differ + | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` + | + = note: expected unit type `()` + found mutable reference `&mut <() as Index>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr index 1bfce48d26a2d..6a70a50360619 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr @@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde --> $DIR/issue-100222.rs:25:12 | LL | fn foo(&mut self, x: ::Output) -> ::Output - | ^^^^^^^^^ types differ + | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` + | + = note: expected unit type `()` + found mutable reference `&mut <() as Index>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr index 4a949e90d8554..03536dca1e848 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr @@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde --> $DIR/issue-100222.rs:34:12 | LL | fn foo(&mut self, x: ::Output) -> ::Output - | ^^^^^^^^^ types differ + | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` + | + = note: expected unit type `()` + found mutable reference `&mut <() as Index>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr index 1bfce48d26a2d..6a70a50360619 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr @@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde --> $DIR/issue-100222.rs:25:12 | LL | fn foo(&mut self, x: ::Output) -> ::Output - | ^^^^^^^^^ types differ + | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` + | + = note: expected unit type `()` + found mutable reference `&mut <() as Index>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index 83d520341bcc3..e47da338736f4 100644 --- a/tests/ui/traits/next-solver/async.fail.stderr +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -1,11 +1,13 @@ -error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:22} as Future>::Output == i32` +error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ types differ + | ----------- ^^^^^^^^ expected `()`, found `i32` | | | required by a bound introduced by this call | + = note: expected unit type `()` + found type `i32` note: required by a bound in `needs_async` --> $DIR/async.rs:8:31 | diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs index 129e4cfaa028b..fded774354759 100644 --- a/tests/ui/traits/next-solver/async.rs +++ b/tests/ui/traits/next-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR type mismatch + //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` } #[cfg(pass)] diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr index 8cc2a51ee2b6c..043cbdff9ab9d 100644 --- a/tests/ui/traits/next-solver/more-object-bound.stderr +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -1,9 +1,22 @@ error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` --> $DIR/more-object-bound.rs:12:5 | +LL | fn transmute(x: A) -> B { + | - - + | | | + | | expected type parameter + | | found type parameter + | found type parameter + | expected type parameter LL | foo::>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `A`, found type parameter `B` | + = note: expected type parameter `A` + found type parameter `B` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = note: required because it appears within the type `dyn Trait` note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8 From b1059ccda210e11c19b3c639a13ddd64de781daf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Jul 2024 15:55:17 -0400 Subject: [PATCH 098/189] Instance::resolve -> Instance::try_resolve, and other nits --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 2 +- .../src/check_consts/check.rs | 2 +- .../src/interpret/eval_context.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- compiler/rustc_lint/src/internal.rs | 4 ++-- compiler/rustc_lint/src/noop_method_call.rs | 4 +++- .../rustc_middle/src/mir/interpret/queries.rs | 4 ++-- compiler/rustc_middle/src/ty/instance.rs | 22 ++++++++++++++----- compiler/rustc_middle/src/util/call_kind.rs | 2 +- compiler/rustc_mir_build/src/lints.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 3 ++- compiler/rustc_mir_transform/src/inline.rs | 2 +- .../rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_passes/src/abi_test.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 2 +- .../clippy_lints/src/assigning_clones.rs | 4 ++-- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- src/tools/miri/src/eval.rs | 2 +- tests/ui/codegen/overflow-during-mono.rs | 1 + tests/ui/codegen/overflow-during-mono.stderr | 2 +- .../issue-58952-filter-type-length.rs | 1 + 22 files changed, 44 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 44ab762f66e0a..7ef53fa2078e4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3733,7 +3733,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { if tcx.is_diagnostic_item(sym::deref_method, method_did) { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_args) + Instance::try_resolve(tcx, self.param_env, deref_target, method_args) .transpose() }); if let Some(Ok(instance)) = deref_target { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index fba18c381466b..e1df5a8ec1655 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -948,7 +948,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { return; } - if let Ok(Some(instance)) = ty::Instance::resolve( + if let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, self.param_env, *fn_did, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ab60cc3792098..0d8a17775dd3d 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -768,7 +768,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { is_trait = true; if let Ok(Some(instance)) = - Instance::resolve(tcx, param_env, callee, fn_args) + Instance::try_resolve(tcx, param_env, callee, fn_args) && let InstanceKind::Item(def) = instance.def { // Resolve a trait method call to its concrete implementation, which may be in a diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 67eeb1b3b8712..830c4bd3e26e0 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -618,7 +618,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("resolve: {:?}, {:#?}", def, args); trace!("param_env: {:#?}", self.param_env); trace!("args: {:#?}", args); - match ty::Instance::resolve(*self.tcx, self.param_env, def, args) { + match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 71a86683c2123..9973646aecd6a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -534,7 +534,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let tcx = self.tcx(); // Find the method being called. - let Ok(Some(instance)) = ty::Instance::resolve( + let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, ctxt.param_env, ctxt.assoc_item.def_id, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 9110cccdc46f0..772cc2ff8b997 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -88,7 +88,7 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]); impl LateLintPass<'_> for QueryStability { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; - if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) { + if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { cx.emit_span_lint( @@ -393,7 +393,7 @@ impl LateLintPass<'_> for Diagnostics { }; // Is the callee marked with `#[rustc_lint_diagnostics]`? - let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args) + let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args) .ok() .flatten() .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics)); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 91441248e70fd..307e4bebe9a1b 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -96,7 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .tcx .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id)); // Resolve the trait method instance. - let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, cx.param_env, did, args) else { return }; + let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else { + return; + }; // (Re)check that it implements the noop diagnostic. let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return }; if !matches!( diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 95857e8579d9a..96613592bbcce 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -73,7 +73,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve( + match ty::Instance::try_resolve( self, param_env, // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? ct.def, ct.args, @@ -106,7 +106,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve(self, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 3f854ba74916f..ae54411d788ab 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -516,7 +516,7 @@ impl<'tcx> Instance<'tcx> { /// from `Ok(None)` to avoid misleading diagnostics when an error /// has already been/will be emitted, for the original cause #[instrument(level = "debug", skip(tcx), ret)] - pub fn resolve( + pub fn try_resolve( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, @@ -555,7 +555,7 @@ impl<'tcx> Instance<'tcx> { let span_or_local_def_span = || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span }; - match ty::Instance::resolve(tcx, param_env, def_id, args) { + match ty::Instance::try_resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, Ok(None) => { let type_length = type_length(args); @@ -605,7 +605,7 @@ impl<'tcx> Instance<'tcx> { // Use either `resolve_closure` or `resolve_for_vtable` assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); - Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { + Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); @@ -738,13 +738,25 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) + Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), + ) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) + Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), + ) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index dc1d73684f4f2..0815c291173de 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -98,7 +98,7 @@ pub fn call_kind<'tcx>( Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) }) } else if is_deref { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, param_env, deref_target, method_args).transpose() + Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose() }); if let Some(Ok(instance)) = deref_target { let deref_target_ty = instance.ty(tcx, param_env); diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 2c817d605af2a..1c7aa9f9ed095 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -141,7 +141,7 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { return false; }; let (callee, call_args) = if let Ok(Some(instance)) = - Instance::resolve(tcx, param_env, callee, normalized_args) + Instance::try_resolve(tcx, param_env, callee, normalized_args) { (instance.def_id(), instance.args) } else { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 93db1f618533b..fd778ef78a3ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -558,7 +558,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self .tcx .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id)); - let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, args) { + let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args) + { Ok(Some(i)) => i, Ok(None) => { // It should be assoc consts if there's no error but we cannot resolve it. diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 6fa31c1174d0b..5075e0727548f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -389,7 +389,7 @@ impl<'tcx> Inliner<'tcx> { // To resolve an instance its args have to be fully normalized. let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?; let callee = - Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; + Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { return None; diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 35bcd24ce95ba..d4477563e3adb 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -53,7 +53,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( trace!(?caller, ?param_env, ?args, "cannot normalize, skipping"); continue; }; - let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, args) else { + let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else { trace!(?callee, "cannot resolve, skipping"); continue; }; diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 0c3dd649997ef..839b96fb3de84 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -61,7 +61,7 @@ fn unwrap_fn_abi<'tcx>( fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, 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.into(), args) { + let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) { Ok(Some(instance)) => instance, Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 4eefd0eb17c40..b0ced8e920fe5 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -629,7 +629,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); let args_ref = args.internal(&mut *tables, tcx); - match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { Ok(Some(instance)) => Some(instance.stable(&mut *tables)), Ok(None) | Err(_) => None, } diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 05ea74b0d534f..406f38f411ecd 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -103,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< let args = cx.typeck_results().node_args(expr.hir_id); // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else { + let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else { return None; }; if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { @@ -119,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< // If we could not resolve the method, don't apply the lint let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args), + ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args), _ => Ok(None), }) else { return None; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 5cb8e7bfab2a9..b71ebe35eb6a8 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> { ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index c0827cce26301..9142b8b5fdbc0 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -375,7 +375,7 @@ pub fn create_ecx<'tcx>( }); let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( + let start_instance = ty::Instance::try_resolve( tcx, ty::ParamEnv::reveal_all(), start_id, diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 278298f27ff0e..4d3f2c18dc837 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ error-pattern: reached the type-length limit while instantiating #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index 9e463378004dc..e06fcd289669f 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,4 +1,4 @@ -error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:12:41: 12:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` +error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index b2c208ae28f19..4f3ddce69d822 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ error-pattern: reached the type-length limit while instantiating //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. From 9f32459c988dec799458f304bbc49ed5dc6ef772 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 Jul 2024 06:15:17 +0800 Subject: [PATCH 099/189] Fix incorrect suggestion for extra argument with a type error --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 26 ++++ .../suggest-better-removing-issue-126246.rs | 21 +++ ...uggest-better-removing-issue-126246.stderr | 124 ++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs create mode 100644 tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 63148ab517c5d..c6d72700b3fce 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -951,6 +951,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return err.emit(); } + // Special case, we found an extra argument is provided, which is very common in practice. + // but there is a obviously better removing suggestion compared to the current one, + // try to find the argument with Error type, if we removed it all the types will become good, + // then we will replace the current suggestion. + if let [Error::Extra(provided_idx)] = &errors[..] { + let remove_idx_is_perfect = |idx: usize| -> bool { + let removed_arg_tys = provided_arg_tys + .iter() + .enumerate() + .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) + .collect::>(); + std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( + |((expected_ty, _), (provided_ty, _))| { + !provided_ty.references_error() + && self.can_coerce(*provided_ty, *expected_ty) + }, + ) + }; + + if !remove_idx_is_perfect(provided_idx.as_usize()) { + if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) { + errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; + } + } + } + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { struct_span_code_err!( self.dcx(), diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs new file mode 100644 index 0000000000000..fa1802283c39c --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs @@ -0,0 +1,21 @@ +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i32, y: i32) -> i32 { + x + y +} + +fn main() { + add_one(2, 2); //~ ERROR this function takes 1 argument but 2 arguments were supplied + add_one(no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_one(10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_two(10, no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(no_such_local, 10, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(10, 10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied +} diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr new file mode 100644 index 0000000000000..7c4daa3ffe95b --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr @@ -0,0 +1,124 @@ +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:11:13 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:13:17 + | +LL | add_one(10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:15:17 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:17:13 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:19:21 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:10:5 + | +LL | add_one(2, 2); + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:11:5 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:13:5 + | +LL | add_one(10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:15:5 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:17:5 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:19:5 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0061, E0425. +For more information about an error, try `rustc --explain E0061`. From 64a3bd84d83a6138b6e7db82a53199246f292e53 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:01:15 -0500 Subject: [PATCH 100/189] Always preserve user-written comments in assembly --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 3 ++- tests/assembly/asm-comments.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/assembly/asm-comments.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index c4cfc0b6dc6a1..a868c56c4e625 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -436,7 +436,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Options.MCOptions.AsmVerbose = AsmComments; - Options.MCOptions.PreserveAsmComments = AsmComments; + // Always preserve comments that were written by the user + Options.MCOptions.PreserveAsmComments = true; Options.MCOptions.ABIName = ABIStr; if (SplitDwarfFile) { Options.MCOptions.SplitDwarfFile = SplitDwarfFile; diff --git a/tests/assembly/asm-comments.rs b/tests/assembly/asm-comments.rs new file mode 100644 index 0000000000000..557009975ddc9 --- /dev/null +++ b/tests/assembly/asm-comments.rs @@ -0,0 +1,12 @@ +//@ assembly-output: emit-asm +//@ only-x86_64 +// Check that comments in assembly get passed + +#![crate_type = "lib"] + +// CHECK-LABEL: test_comments: +#[no_mangle] +pub fn test_comments() { + // CHECK: example comment + unsafe { core::arch::asm!("nop // example comment") }; +} From c15a698f567356cea22e79686c2883f3557bae0b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:08:49 -0500 Subject: [PATCH 101/189] Rename the `asm-comments` compiler flag to `verbose-asm` Since this codegen flag now only controls LLVM-generated comments rather than all assembly comments, make the name more accurate (and also match Clang). --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 4 ++-- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ++-- compiler/rustc_session/src/options.rs | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 28a88dd2efea0..b72636a62248e 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -32,7 +32,7 @@ impl OwnedTargetMachine { unique_section_names: bool, trap_unreachable: bool, singletree: bool, - asm_comments: bool, + verbose_asm: bool, emit_stack_size_section: bool, relax_elf_relocations: bool, use_init_array: bool, @@ -64,7 +64,7 @@ impl OwnedTargetMachine { unique_section_names, trap_unreachable, singletree, - asm_comments, + verbose_asm, emit_stack_size_section, relax_elf_relocations, use_init_array, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 5e481eb98f55f..2fda19bf0c914 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -214,7 +214,7 @@ pub fn target_machine_factory( sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes; - let asm_comments = sess.opts.unstable_opts.asm_comments; + let verbose_asm = sess.opts.unstable_opts.verbose_asm; let relax_elf_relocations = sess.opts.unstable_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations); @@ -289,7 +289,7 @@ pub fn target_machine_factory( funique_section_names, trap_unreachable, singlethread, - asm_comments, + verbose_asm, emit_stack_size_section, relax_elf_relocations, use_init_array, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 132e1f9e8fd93..08e9e312827ce 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2185,7 +2185,7 @@ extern "C" { UniqueSectionNames: bool, TrapUnreachable: bool, Singlethread: bool, - AsmComments: bool, + VerboseAsm: bool, EmitStackSizeSection: bool, RelaxELFRelocations: bool, UseInitArray: bool, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9bd67a1154b7d..e2ba75dfd1902 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -757,7 +757,6 @@ fn test_unstable_options_tracking_hash() { // tidy-alphabetical-start tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); - tracked!(asm_comments, true); tracked!(assume_incomplete_release, true); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); @@ -862,6 +861,7 @@ fn test_unstable_options_tracking_hash() { tracked!(uninit_const_chunk_threshold, 123); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); + tracked!(verbose_asm, true); tracked!(verify_llvm_ir, true); tracked!(virtual_function_elimination, true); tracked!(wasi_exec_model, Some(WasiExecModel::Reactor)); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index a868c56c4e625..283c4fbbb7cf4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -407,7 +407,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, bool FunctionSections, bool DataSections, bool UniqueSectionNames, - bool TrapUnreachable, bool Singlethread, bool AsmComments, + bool TrapUnreachable, bool Singlethread, bool VerboseAsm, bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, const char *DebugInfoCompression, bool UseEmulatedTls, @@ -435,7 +435,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; - Options.MCOptions.AsmVerbose = AsmComments; + Options.MCOptions.AsmVerbose = VerboseAsm; // Always preserve comments that were written by the user Options.MCOptions.PreserveAsmComments = true; Options.MCOptions.ABIName = ABIStr; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2e4421d50e313..7421cae65e4f8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1630,8 +1630,6 @@ options! { "only allow the listed language features to be enabled in code (comma separated)"), always_encode_mir: bool = (false, parse_bool, [TRACKED], "encode MIR of all functions into the crate metadata (default: no)"), - asm_comments: bool = (false, parse_bool, [TRACKED], - "generate comments into the assembly (may change behavior) (default: no)"), assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), @@ -2107,6 +2105,8 @@ written to standard error output)"), "Generate sync unwind tables instead of async unwind tables (default: no)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), + verbose_asm: bool = (false, parse_bool, [TRACKED], + "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], "in general, enable more debug printouts (default: no)"), From 1a6893e14b7d08aee18acf82b9a08e1ba8534d7b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:17:47 -0500 Subject: [PATCH 102/189] Add documentation for -Zverbose-asm --- .../src/compiler-flags/verbose-asm.md | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/verbose-asm.md diff --git a/src/doc/unstable-book/src/compiler-flags/verbose-asm.md b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md new file mode 100644 index 0000000000000..84eb90a14cf53 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md @@ -0,0 +1,70 @@ +# `verbose-asm` + +The tracking issue for this feature is: [#126802](https://github.com/rust-lang/rust/issues/126802). + +------------------------ + +This enables passing `-Zverbose-asm` to get contextual comments added by LLVM. + +Sample code: + +```rust +#[no_mangle] +pub fn foo(a: i32, b: i32) -> i32 { + a + b +} +``` + +Default output: + +```asm +foo: + push rax + add edi, esi + mov dword ptr [rsp + 4], edi + seto al + jo .LBB0_2 + mov eax, dword ptr [rsp + 4] + pop rcx + ret +.LBB0_2: + lea rdi, [rip + .L__unnamed_1] + mov rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL] + call rax + +.L__unnamed_2: + .ascii "/app/example.rs" + +.L__unnamed_1: + .quad .L__unnamed_2 + .asciz "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000" +``` + +With `-Zverbose-asm`: + +```asm +foo: # @foo +# %bb.0: + push rax + add edi, esi + mov dword ptr [rsp + 4], edi # 4-byte Spill + seto al + jo .LBB0_2 +# %bb.1: + mov eax, dword ptr [rsp + 4] # 4-byte Reload + pop rcx + ret +.LBB0_2: + lea rdi, [rip + .L__unnamed_1] + mov rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL] + call rax + # -- End function +.L__unnamed_2: + .ascii "/app/example.rs" + +.L__unnamed_1: + .quad .L__unnamed_2 + .asciz "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000" + + # DW_AT_external +``` From 1ca7e24e3630e05dd1fbbe2a304a400f0aa521b8 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 2 Jul 2024 23:34:50 -0400 Subject: [PATCH 103/189] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 4ed7bee47f7dd..a515d463427b3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4ed7bee47f7dd4416b36fada1909e9a62c546246 +Subproject commit a515d463427b3912ec0365d106791f88c1c14e1b From a6c03ae6fe3dd93146be3a1f7fd65ccd58e3ab67 Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Mon, 1 Jul 2024 10:33:27 +0530 Subject: [PATCH 104/189] Fall back on remove dir implementation for vxworks --- library/std/src/sys/pal/unix/fs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 92c76ec4303fe..f9d6b5fbc86a4 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1976,13 +1976,14 @@ pub fn chroot(dir: &Path) -> io::Result<()> { pub use remove_dir_impl::remove_dir_all; -// Fallback for REDOX, ESP-ID, Horizon, Vita and Miri +// Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri #[cfg(any( target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nto", + target_os = "vxworks", miri ))] mod remove_dir_impl { @@ -1996,6 +1997,7 @@ mod remove_dir_impl { target_os = "horizon", target_os = "vita", target_os = "nto", + target_os = "vxworks", miri )))] mod remove_dir_impl { From d982844b47c88c2d78cde42de88f27ce75586972 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 1 Jul 2024 21:01:49 +0200 Subject: [PATCH 105/189] Implement the `_mm256_zeroupper` and `_mm256_zeroall` intrinsics --- src/tools/miri/src/shims/x86/avx.rs | 11 +++++++++++ .../miri/tests/pass/shims/x86/intrinsics-x86-avx.rs | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 0d2977b7b6fe8..f36bb4826e487 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -338,6 +338,17 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(res.into()), dest)?; } + // Used to implement the `_mm256_zeroupper` and `_mm256_zeroall` functions. + // These function clear out the upper 128 bits of all avx registers or + // zero out all avx registers respectively. + "vzeroupper" | "vzeroall" => { + // These functions are purely a performance hint for the CPU. + // Any registers currently in use will be saved beforehand by the + // compiler, making these functions no-ops. + + // The only thing that needs to be ensured is the correct calling convention. + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + } _ => return Ok(EmulateItemResult::NotSupported), } Ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs index 7d43cc596aedb..728f57d48f17e 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs @@ -1342,6 +1342,11 @@ unsafe fn test_avx() { assert_eq!(r, 1); } test_mm_testnzc_ps(); + + // These intrinsics are functionally no-ops. The only thing + // that needs to be tested is that they can be executed. + _mm256_zeroupper(); + _mm256_zeroall(); } #[target_feature(enable = "sse2")] From 9e71c7b5a98fb1f18eade36c9188467616550ffc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Jul 2024 11:34:39 +0200 Subject: [PATCH 106/189] Small `run-make-support` API improvements --- src/tools/run-make-support/src/lib.rs | 6 ++++-- src/tools/run-make-support/src/rustc.rs | 3 ++- tests/run-make/emit-named-files/rmake.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 294dae109425f..9a180fe4ad19a 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -321,8 +321,9 @@ pub fn set_host_rpath(cmd: &mut Command) { /// Read the contents of a file that cannot simply be read by /// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. #[track_caller] -pub fn invalid_utf8_contains>(path: P, expected: &str) { +pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); if !String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); eprintln!("{}", String::from_utf8_lossy(&buffer)); @@ -335,8 +336,9 @@ pub fn invalid_utf8_contains>(path: P, expected: &str) { /// Read the contents of a file that cannot simply be read by /// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. #[track_caller] -pub fn invalid_utf8_not_contains>(path: P, expected: &str) { +pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); if String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); eprintln!("{}", String::from_utf8_lossy(&buffer)); diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 3f23c1b8f9e76..054836e87cfbc 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -86,7 +86,8 @@ impl Rustc { } /// Specify type(s) of output files to generate. - pub fn emit(&mut self, kinds: &str) -> &mut Self { + pub fn emit>(&mut self, kinds: S) -> &mut Self { + let kinds = kinds.as_ref(); self.cmd.arg(format!("--emit={kinds}")); self } diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index 79c3ee90c9875..a02c97fec4cba 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{fs_wrapper, rustc}; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); - rustc().input("foo.rs").emit(&format!("{format}={}", out_file.display())).run(); + rustc().input("foo.rs").emit(format!("{format}={}", out_file.display())).run(); assert!(out_file.is_file()); } From bcbcbfff4452ca34c4cee6a7737141df39591668 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 3 Jul 2024 14:23:09 +0300 Subject: [PATCH 107/189] bootstrap: pass correct struct size to winapi --- src/bootstrap/src/bin/rustc.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 009e62469b4d1..46e845f77ae1b 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -317,9 +317,7 @@ fn format_rusage_data(child: Child) -> Option { use windows::{ Win32::Foundation::HANDLE, - Win32::System::ProcessStatus::{ - K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, - }, + Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, Win32::System::Threading::GetProcessTimes, Win32::System::Time::FileTimeToSystemTime, }; @@ -331,6 +329,7 @@ fn format_rusage_data(child: Child) -> Option { let mut kernel_filetime = Default::default(); let mut kernel_time = Default::default(); let mut memory_counters = PROCESS_MEMORY_COUNTERS::default(); + let memory_counters_size = std::mem::size_of_val(&memory_counters); unsafe { GetProcessTimes( @@ -347,15 +346,9 @@ fn format_rusage_data(child: Child) -> Option { // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process // with the given handle and none of that process's children. - unsafe { - K32GetProcessMemoryInfo( - handle, - &mut memory_counters, - std::mem::size_of::() as u32, - ) - } - .ok() - .ok()?; + unsafe { K32GetProcessMemoryInfo(handle, &mut memory_counters, memory_counters_size as u32) } + .ok() + .ok()?; // Guide on interpreting these numbers: // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information From 8b6435d5ce4efaecca51e530f0cb3c44d527f3c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 2 Jul 2024 17:35:49 -0300 Subject: [PATCH 108/189] Add parse fail test using safe trait/impl trait --- .../unsafe-extern-blocks/safe-impl-trait.gated.stderr | 8 ++++++++ .../ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs | 8 ++++++++ .../unsafe-extern-blocks/safe-impl-trait.ungated.stderr | 8 ++++++++ .../unsafe-extern-blocks/safe-trait.gated.stderr | 8 ++++++++ tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs | 7 +++++++ .../unsafe-extern-blocks/safe-trait.ungated.stderr | 8 ++++++++ 6 files changed, 47 insertions(+) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr new file mode 100644 index 0000000000000..80e7a45f57e79 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `impl` + --> $DIR/safe-impl-trait.rs:5:6 + | +LL | safe impl Bar for () { } + | ^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs new file mode 100644 index 0000000000000..57c03e4d896be --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs @@ -0,0 +1,8 @@ +//@ revisions: gated ungated +#![cfg_attr(gated, feature(unsafe_extern_blocks))] + +trait Bar {} +safe impl Bar for () { } +//~^ ERROR expected one of `!` or `::`, found keyword `impl` + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr new file mode 100644 index 0000000000000..80e7a45f57e79 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `impl` + --> $DIR/safe-impl-trait.rs:5:6 + | +LL | safe impl Bar for () { } + | ^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr new file mode 100644 index 0000000000000..de84037f28c58 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `trait` + --> $DIR/safe-trait.rs:4:6 + | +LL | safe trait Foo {} + | ^^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs new file mode 100644 index 0000000000000..e73cb45b18877 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs @@ -0,0 +1,7 @@ +//@ revisions: gated ungated +#![cfg_attr(gated, feature(unsafe_extern_blocks))] + +safe trait Foo {} +//~^ ERROR expected one of `!` or `::`, found keyword `trait` + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr new file mode 100644 index 0000000000000..de84037f28c58 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `trait` + --> $DIR/safe-trait.rs:4:6 + | +LL | safe trait Foo {} + | ^^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + From 403e2e2bbd4c3ae3460ab0d922cdb0fae15725a7 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 3 Jul 2024 10:12:39 -0700 Subject: [PATCH 109/189] Disable rmake test rustdoc-io-error on riscv64gc-gnu --- tests/run-make/inaccessible-temp-dir/rmake.rs | 2 +- tests/run-make/rustdoc-io-error/rmake.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index b98e151e90696..62b8479c32881 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -14,7 +14,7 @@ // See https://github.com/rust-lang/rust/issues/66530 //@ ignore-riscv64 -// FIXME: The riscv build container runs as root, and can always write +// FIXME: The riscv64gc-gnu build container runs as root, and can always write // into `inaccessible/tmp`. Ideally, the riscv64-gnu docker container // would use a non-root user, but this leads to issues with // `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs index d60e4438e6f27..69afea401622d 100644 --- a/tests/run-make/rustdoc-io-error/rmake.rs +++ b/tests/run-make/rustdoc-io-error/rmake.rs @@ -6,8 +6,13 @@ // permissions so that it is not writable. We have to take special care to set // the permissions back to normal so that it's able to be deleted later. +//@ ignore-riscv64 +//@ ignore-arm +// FIXME: The riscv64gc-gnu and armhf-gnu build containers run as root, +// and can always write into `inaccessible/tmp`. Ideally, these docker +// containers would use a non-root user, but this leads to issues with +// `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. //@ ignore-windows - the `set_readonly` functions doesn't work on folders. -//@ ignore-arm - weird file perms on armhf-gnu use run_make_support::{path, rustdoc}; use std::fs; From 9192479dc352c96927f3bfeda746d07c71a1a470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 28 Jun 2024 10:46:52 +0200 Subject: [PATCH 110/189] Improve documentation --- src/bootstrap/src/utils/exec.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 8bcb2301f1ace..87a3a2b0b284e 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -34,7 +34,8 @@ pub enum OutputMode { /// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap /// ([OutputMode::OnlyOutput]). If bootstrap uses verbose mode, then it will also print the /// command itself in case of failure ([OutputMode::All]). -/// If you want to handle the output programmatically, use `output_mode(OutputMode::OnlyOnFailure)`. +/// If you want to handle the output programmatically, use `output_mode(OutputMode::OnlyOnFailure)`, +/// which will print the output only if the command fails. /// /// [allow_failure]: BootstrapCommand::allow_failure /// [delay_failure]: BootstrapCommand::delay_failure @@ -113,7 +114,7 @@ impl BootstrapCommand { } } -/// This implementation is temporary, until all `Command` invocations are migrated to +/// FIXME: This implementation is temporary, until all `Command` invocations are migrated to /// `BootstrapCommand`. impl<'a> From<&'a mut Command> for BootstrapCommand { fn from(command: &'a mut Command) -> Self { @@ -138,7 +139,7 @@ impl<'a> From<&'a mut Command> for BootstrapCommand { } } -/// This implementation is temporary, until all `Command` invocations are migrated to +/// FIXME: This implementation is temporary, until all `Command` invocations are migrated to /// `BootstrapCommand`. impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand { fn from(command: &'a mut BootstrapCommand) -> Self { From a34d0a8d5f2abbbe4bf28d829bbf7490f23d5a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Jun 2024 17:21:33 +0200 Subject: [PATCH 111/189] Make `git` helper return `BootstrapCmd` --- src/bootstrap/src/core/build_steps/format.rs | 38 +++++++-------- src/bootstrap/src/core/build_steps/llvm.rs | 5 +- src/bootstrap/src/core/build_steps/perf.rs | 1 + src/bootstrap/src/core/build_steps/setup.rs | 1 + src/bootstrap/src/core/build_steps/test.rs | 2 +- .../src/core/build_steps/toolstate.rs | 19 ++++++-- src/bootstrap/src/core/config/config.rs | 26 +++++++---- src/bootstrap/src/lib.rs | 46 ++++++++++++------- src/bootstrap/src/utils/channel.rs | 14 +++--- src/bootstrap/src/utils/exec.rs | 36 ++++++++------- src/bootstrap/src/utils/helpers.rs | 4 +- 11 files changed, 112 insertions(+), 80 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index f5e346726868a..4583eb1c6cd85 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -7,7 +7,7 @@ use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; use std::collections::VecDeque; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Command; use std::sync::mpsc::SyncSender; use std::sync::Mutex; @@ -160,35 +160,29 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("!{ignore}")).expect(&ignore); } } - let git_available = match helpers::git(None) - .arg("--version") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - { - Ok(status) => status.success(), - Err(_) => false, - }; + let git_available = build + .run(helpers::git(None).print_on_failure().allow_failure().arg("--version")) + .is_success(); let mut adjective = None; if git_available { - let in_working_tree = match helpers::git(Some(&build.src)) - .arg("rev-parse") - .arg("--is-inside-work-tree") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - { - Ok(status) => status.success(), - Err(_) => false, - }; + let in_working_tree = build + .run( + helpers::git(Some(&build.src)) + .print_on_failure() + .allow_failure() + .arg("rev-parse") + .arg("--is-inside-work-tree"), + ) + .is_success(); if in_working_tree { let untracked_paths_output = output( - helpers::git(Some(&build.src)) + &mut helpers::git(Some(&build.src)) .arg("status") .arg("--porcelain") .arg("-z") - .arg("--untracked-files=normal"), + .arg("--untracked-files=normal") + .command, ); let untracked_paths: Vec<_> = untracked_paths_output .split_terminator('\0') diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 8e6795b11bd21..ba21e2ad32d05 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -172,7 +172,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` config.src.join("src/version"), ]); - output(&mut rev_list).trim().to_owned() + output(&mut rev_list.command).trim().to_owned() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { @@ -253,7 +253,8 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); - let head_sha = output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD")); + let head_sha = + output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command); let head_sha = head_sha.trim(); llvm_sha == head_sha } diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index f41b5fe10f1d9..20ab1836e0068 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -2,6 +2,7 @@ use crate::core::build_steps::compile::{Std, Sysroot}; use crate::core::build_steps::tool::{RustcPerf, Tool}; use crate::core::builder::Builder; use crate::core::config::DebuginfoLevel; +use crate::utils::exec::BootstrapCommand; /// Performs profiling using `rustc-perf` on a built version of the compiler. pub fn perf(builder: &Builder<'_>) { diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 947c74f32c99e..e6a09e8cb8e8c 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -484,6 +484,7 @@ impl Step for Hook { fn install_git_hook_maybe(config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) .args(["rev-parse", "--git-common-dir"]) + .command .output() .map(|output| { assert!(output.status.success(), "failed to run `git`"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 1460a2290197b..918e4e2b90726 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2349,7 +2349,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> cmd = cmd.delay_failure(); if !builder.config.verbose_tests { - cmd = cmd.quiet(); + cmd = cmd.print_on_failure(); } builder.run(cmd).is_success() } diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 9e6d03349b5fb..e3e7931a5a2ab 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -101,8 +101,13 @@ fn print_error(tool: &str, submodule: &str) { fn check_changed_files(toolstates: &HashMap, ToolState>) { // Changed files - let output = - helpers::git(None).arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output(); + let output = helpers::git(None) + .arg("diff") + .arg("--name-status") + .arg("HEAD") + .arg("HEAD^") + .command + .output(); let output = match output { Ok(o) => o, Err(e) => { @@ -324,6 +329,7 @@ fn checkout_toolstate_repo() { .arg("--depth=1") .arg(toolstate_repo()) .arg(TOOLSTATE_DIR) + .command .status(); let success = match status { Ok(s) => s.success(), @@ -337,7 +343,8 @@ fn checkout_toolstate_repo() { /// Sets up config and authentication for modifying the toolstate repo. fn prepare_toolstate_config(token: &str) { fn git_config(key: &str, value: &str) { - let status = helpers::git(None).arg("config").arg("--global").arg(key).arg(value).status(); + let status = + helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status(); let success = match status { Ok(s) => s.success(), Err(_) => false, @@ -406,6 +413,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("-a") .arg("-m") .arg(&message) + .command .status()); if !status.success() { success = true; @@ -416,6 +424,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("push") .arg("origin") .arg("master") + .command .status()); // If we successfully push, exit. if status.success() { @@ -428,12 +437,14 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { .arg("fetch") .arg("origin") .arg("master") + .command .status()); assert!(status.success()); let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") + .command .status()); assert!(status.success()); } @@ -449,7 +460,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").output()); + let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output()); let commit = t!(String::from_utf8(commit.stdout)); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 948f97e746f42..10ac6c93e9a43 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1259,6 +1259,7 @@ impl Config { cmd.arg("rev-parse").arg("--show-cdup"); // Discard stderr because we expect this to fail when building from a tarball. let output = cmd + .command .stderr(std::process::Stdio::null()) .output() .ok() @@ -2141,7 +2142,7 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); - output(&mut git) + output(&mut git.command) } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -2445,8 +2446,9 @@ impl Config { }; // Handle running from a directory other than the top level - let top_level = - output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); + let top_level = output( + &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, + ); let top_level = top_level.trim_end(); let compiler = format!("{top_level}/compiler/"); let library = format!("{top_level}/library/"); @@ -2454,10 +2456,11 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - helpers::git(Some(&self.src)) + &mut helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]), + .args(["-n1", "--first-parent", "HEAD"]) + .command, ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2471,6 +2474,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) .args(["diff-index", "--quiet", commit, "--", &compiler, &library]) + .command .status()) .success(); if has_changes { @@ -2542,17 +2546,19 @@ impl Config { if_unchanged: bool, ) -> Option { // Handle running from a directory other than the top level - let top_level = - output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); + let top_level = output( + &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command, + ); let top_level = top_level.trim_end(); // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - helpers::git(Some(&self.src)) + &mut helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]), + .args(["-n1", "--first-parent", "HEAD"]) + .command, ); let commit = merge_base.trim_end(); if commit.is_empty() { @@ -2571,7 +2577,7 @@ impl Config { git.arg(format!("{top_level}/{path}")); } - let has_changes = !t!(git.status()).success(); + let has_changes = !t!(git.command.status()).success(); if has_changes { if if_unchanged { if self.verbose > 0 { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index c12449fdc4ae0..ae2982ea56f09 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -494,11 +494,12 @@ impl Build { let submodule_git = || helpers::git(Some(&absolute_path)); // Determine commit checked out in submodule. - let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"])); + let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. - let recorded = - output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); + let recorded = output( + &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command, + ); let actual_hash = recorded .split_whitespace() .nth(2) @@ -521,6 +522,7 @@ impl Build { let current_branch = { let output = helpers::git(Some(&self.src)) .args(["symbolic-ref", "--short", "HEAD"]) + .command .stderr(Stdio::inherit()) .output(); let output = t!(output); @@ -546,7 +548,7 @@ impl Build { git }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. - if !update(true).status().map_or(false, |status| status.success()) { + if !update(true).command.status().map_or(false, |status| status.success()) { self.run(update(false)); } @@ -577,12 +579,15 @@ impl Build { if !self.config.submodules(self.rust_info()) { return; } - let output = output( - helpers::git(Some(&self.src)) - .args(["config", "--file"]) - .arg(self.config.src.join(".gitmodules")) - .args(["--get-regexp", "path"]), - ); + let output = self + .run( + helpers::git(Some(&self.src)) + .quiet() + .args(["config", "--file"]) + .arg(self.config.src.join(".gitmodules")) + .args(["--get-regexp", "path"]), + ) + .stdout(); for line in output.lines() { // Look for `submodule.$name.path = $path` // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` @@ -950,7 +955,10 @@ impl Build { command.command.status().map(|status| status.into()), matches!(mode, OutputMode::All), ), - OutputMode::OnlyOnFailure => (command.command.output().map(|o| o.into()), true), + mode @ (OutputMode::OnlyOnFailure | OutputMode::Quiet) => ( + command.command.output().map(|o| o.into()), + matches!(mode, OutputMode::OnlyOnFailure), + ), }; let output = match output { @@ -1480,14 +1488,18 @@ impl Build { // Figure out how many merge commits happened since we branched off master. // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) - output( - helpers::git(Some(&self.src)).arg("rev-list").arg("--count").arg("--merges").arg( - format!( + self.run( + helpers::git(Some(&self.src)) + .quiet() + .arg("rev-list") + .arg("--count") + .arg("--merges") + .arg(format!( "refs/remotes/origin/{}..HEAD", self.config.stage0_metadata.config.nightly_branch - ), - ), + )), ) + .stdout() }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); @@ -1914,6 +1926,7 @@ fn envify(s: &str) -> String { pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { let diff = helpers::git(Some(dir)) .arg("diff") + .command .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); @@ -1923,6 +1936,7 @@ pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") + .command .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index ce82c52f049e2..2ca86bdb0ed27 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -45,7 +45,7 @@ impl GitInfo { } // Make sure git commands work - match helpers::git(Some(dir)).arg("rev-parse").output() { + match helpers::git(Some(dir)).arg("rev-parse").command.output() { Ok(ref out) if out.status.success() => {} _ => return GitInfo::Absent, } @@ -58,15 +58,17 @@ impl GitInfo { // Ok, let's scrape some info let ver_date = output( - helpers::git(Some(dir)) + &mut helpers::git(Some(dir)) .arg("log") .arg("-1") .arg("--date=short") - .arg("--pretty=format:%cd"), + .arg("--pretty=format:%cd") + .command, + ); + let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command); + let short_ver_hash = output( + &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command, ); - let ver_hash = output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD")); - let short_ver_hash = - output(helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD")); GitInfo::Present(Some(Info { commit_date: ver_date.trim().to_string(), sha: ver_hash.trim().to_string(), diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 87a3a2b0b284e..dc30876601c6b 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -23,6 +23,8 @@ pub enum OutputMode { OnlyOutput, /// Suppress the output if the command succeeds, otherwise print the output. OnlyOnFailure, + /// Suppress the output of the command. + Quiet, } /// Wrapper around `std::process::Command`. @@ -105,10 +107,15 @@ impl BootstrapCommand { } /// Do not print the output of the command, unless it fails. - pub fn quiet(self) -> Self { + pub fn print_on_failure(self) -> Self { self.output_mode(OutputMode::OnlyOnFailure) } + /// Do not print the output of the command. + pub fn quiet(self) -> Self { + self.output_mode(OutputMode::Quiet) + } + pub fn output_mode(self, output_mode: OutputMode) -> Self { Self { output_mode: Some(output_mode), ..self } } @@ -116,15 +123,15 @@ impl BootstrapCommand { /// FIXME: This implementation is temporary, until all `Command` invocations are migrated to /// `BootstrapCommand`. -impl<'a> From<&'a mut Command> for BootstrapCommand { - fn from(command: &'a mut Command) -> Self { +impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand { + fn from(command: &'a mut BootstrapCommand) -> Self { // This is essentially a manual `Command::clone` - let mut cmd = Command::new(command.get_program()); - if let Some(dir) = command.get_current_dir() { + let mut cmd = Command::new(command.command.get_program()); + if let Some(dir) = command.command.get_current_dir() { cmd.current_dir(dir); } - cmd.args(command.get_args()); - for (key, value) in command.get_envs() { + cmd.args(command.command.get_args()); + for (key, value) in command.command.get_envs() { match value { Some(value) => { cmd.env(key, value); @@ -134,16 +141,11 @@ impl<'a> From<&'a mut Command> for BootstrapCommand { } } } - - cmd.into() - } -} - -/// FIXME: This implementation is temporary, until all `Command` invocations are migrated to -/// `BootstrapCommand`. -impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand { - fn from(command: &'a mut BootstrapCommand) -> Self { - BootstrapCommand::from(&mut command.command) + Self { + command: cmd, + output_mode: command.output_mode, + failure_behavior: command.failure_behavior, + } } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index adf18c0ace1b4..9c40065dfc4fa 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -498,8 +498,8 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { /// manually building a git `Command`. This approach allows us to manage bootstrap-specific /// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`, /// which is painful to ensure that the required change is applied on each one of them correctly. -pub fn git(source_dir: Option<&Path>) -> Command { - let mut git = Command::new("git"); +pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { + let mut git = BootstrapCommand::new("git"); if let Some(source_dir) = source_dir { git.current_dir(source_dir); From b14ff77c044652246809e197a3b0a0f23f0e1f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Jun 2024 12:32:55 +0200 Subject: [PATCH 112/189] Remove temporary `BootstrapCommand` trait impls --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/doc.rs | 6 +- src/bootstrap/src/core/build_steps/format.rs | 7 +- src/bootstrap/src/core/build_steps/run.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 52 +++++------ src/bootstrap/src/core/build_steps/tool.rs | 4 +- src/bootstrap/src/core/builder.rs | 10 +- src/bootstrap/src/lib.rs | 81 ++++++++-------- src/bootstrap/src/utils/exec.rs | 93 +++++++------------ 9 files changed, 114 insertions(+), 143 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index de3b938e42731..c267d3b0c0cf6 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2080,7 +2080,7 @@ pub fn stream_cargo( tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { - let mut cargo = BootstrapCommand::from(cargo).command; + let mut cargo = cargo.into_cmd().command; // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 4a5af25b3b2f8..823e842693e96 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -738,7 +738,7 @@ fn doc_std( format!("library{} in {} format", crate_description(requested_crates), format.as_str()); let _guard = builder.msg_doc(compiler, description, target); - builder.run(cargo); + builder.run(cargo.into_cmd()); builder.cp_link_r(&out_dir, out); } @@ -863,7 +863,7 @@ impl Step for Rustc { let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc"); symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); - builder.run(cargo); + builder.run(cargo.into_cmd()); if !builder.config.dry_run() { // Sanity check on linked compiler crates @@ -996,7 +996,7 @@ macro_rules! tool_doc { symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); let _guard = builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target); - builder.run(cargo); + builder.run(cargo.into_cmd()); if !builder.config.dry_run() { // Sanity check on linked doc directories diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 4583eb1c6cd85..0372360c3cb74 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -160,16 +160,15 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("!{ignore}")).expect(&ignore); } } - let git_available = build - .run(helpers::git(None).print_on_failure().allow_failure().arg("--version")) - .is_success(); + let git_available = + build.run(helpers::git(None).capture().allow_failure().arg("--version")).is_success(); let mut adjective = None; if git_available { let in_working_tree = build .run( helpers::git(Some(&build.src)) - .print_on_failure() + .capture() .allow_failure() .arg("rev-parse") .arg("--is-inside-work-tree"), diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 22d5efa5d95dd..496fe446d724e 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -158,7 +158,7 @@ impl Step for Miri { // after another --, so this must be at the end. miri.args(builder.config.args()); - builder.run(miri); + builder.run(miri.into_cmd()); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 918e4e2b90726..9fc337dfd50db 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -26,7 +26,7 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; -use crate::utils::exec::{BootstrapCommand, OutputMode}; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date, @@ -150,16 +150,13 @@ You can skip linkcheck with --skip src/tools/linkchecker" builder.default_doc(&[]); // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups. - let mut linkchecker = builder.tool_cmd(Tool::Linkchecker); + let linkchecker = builder.tool_cmd(Tool::Linkchecker); // Run the linkchecker. let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); let _time = helpers::timeit(builder); - builder.run( - BootstrapCommand::from(linkchecker.arg(builder.out.join(host.triple).join("doc"))) - .delay_failure(), - ); + builder.run(linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc"))); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -217,10 +214,7 @@ impl Step for HtmlCheck { )); builder.run( - BootstrapCommand::from( - builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), - ) - .delay_failure(), + builder.tool_cmd(Tool::HtmlChecker).delay_failure().arg(builder.doc_out(self.target)), ); } } @@ -260,14 +254,13 @@ impl Step for Cargotest { let _time = helpers::timeit(builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - let cmd = cmd - .arg(&cargo) + cmd.arg(&cargo) .arg(&out_dir) .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); - add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No); - builder.run(BootstrapCommand::from(cmd).delay_failure()); + add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No); + builder.run(cmd.delay_failure()); } } @@ -763,12 +756,12 @@ impl Step for Clippy { cargo.env("HOST_LIBS", host_libs); cargo.add_rustc_lib_path(builder); - let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); + let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); // Clippy reports errors if it blessed the outputs - if builder.run(BootstrapCommand::from(&mut cargo).allow_failure()).is_success() { + if builder.run(cargo.allow_failure()).is_success() { // The tests succeeded; nothing to do. return; } @@ -821,7 +814,7 @@ impl Step for RustdocTheme { .env("RUSTC_BOOTSTRAP", "1"); cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); - builder.run(BootstrapCommand::from(&mut cmd).delay_failure()); + builder.run(cmd.delay_failure()); } } @@ -1099,7 +1092,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } builder.info("tidy check"); - builder.run(BootstrapCommand::from(&mut cmd).delay_failure()); + builder.run(cmd.delay_failure()); builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] @@ -1306,7 +1299,7 @@ impl Step for RunMakeSupport { &[], ); - builder.run(cargo); + builder.run(cargo.into_cmd()); let lib_name = "librun_make_support.rlib"; let lib = builder.tools_dir(self.compiler).join(lib_name); @@ -2187,7 +2180,7 @@ impl BookTest { compiler.host, ); let _time = helpers::timeit(builder); - let cmd = BootstrapCommand::from(&mut rustbook_cmd).delay_failure(); + let cmd = rustbook_cmd.delay_failure(); let toolstate = if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail }; builder.save_toolstate(self.name, toolstate); @@ -2318,7 +2311,7 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - builder.run(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure)); + builder.run(tool.capture()); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2349,7 +2342,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> cmd = cmd.delay_failure(); if !builder.config.verbose_tests { - cmd = cmd.print_on_failure(); + cmd = cmd.capture(); } builder.run(cmd).is_success() } @@ -2375,10 +2368,13 @@ impl Step for RustcGuide { builder.update_submodule(&relative_path); let src = builder.src.join(relative_path); - let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - let cmd = BootstrapCommand::from(rustbook_cmd.arg("linkcheck").arg(&src)).delay_failure(); - let toolstate = - if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail }; + let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure(); + rustbook_cmd.arg("linkcheck").arg(&src); + let toolstate = if builder.run(rustbook_cmd).is_success() { + ToolState::TestPass + } else { + ToolState::TestFail + }; builder.save_toolstate("rustc-dev-guide", toolstate); } } @@ -3347,7 +3343,7 @@ impl Step for CodegenCranelift { .arg("testsuite.extended_sysroot"); cargo.args(builder.config.test_args()); - builder.run(cargo); + builder.run(cargo.into_cmd()); } } @@ -3472,6 +3468,6 @@ impl Step for CodegenGCC { .arg("--std-tests"); cargo.args(builder.config.test_args()); - builder.run(cargo); + builder.run(cargo.into_cmd()); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index b34640439121a..20c7a30f1a823 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -603,7 +603,7 @@ impl Step for Rustdoc { &self.compiler.host, &target, ); - builder.run(cargo); + builder.run(cargo.into_cmd()); // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" @@ -858,7 +858,7 @@ impl Step for LlvmBitcodeLinker { &self.extra_features, ); - builder.run(cargo); + builder.run(cargo.into_cmd()); let tool_out = builder .cargo_out(self.compiler, Mode::ToolRustc, self.target) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 58d6e7a58e308..35de91c41d4f1 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2398,6 +2398,10 @@ impl Cargo { cargo } + pub fn into_cmd(self) -> BootstrapCommand { + self.into() + } + /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker` pub fn new_for_mir_opt_tests( builder: &Builder<'_>, @@ -2622,9 +2626,3 @@ impl From for BootstrapCommand { cargo.command } } - -impl From for Command { - fn from(cargo: Cargo) -> Command { - BootstrapCommand::from(cargo).command - } -} diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ae2982ea56f09..ae3d18e8774bc 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -555,10 +555,7 @@ impl Build { // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status let has_local_modifications = self - .run( - BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) - .allow_failure(), - ) + .run(submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"])) .is_failure(); if has_local_modifications { self.run(submodule_git().args(["stash", "push"])); @@ -582,7 +579,7 @@ impl Build { let output = self .run( helpers::git(Some(&self.src)) - .quiet() + .capture() .args(["config", "--file"]) .arg(self.config.src.join(".gitmodules")) .args(["--get-regexp", "path"]), @@ -937,69 +934,71 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. - fn run>(&self, command: C) -> CommandOutput { + fn run>(&self, mut command: C) -> CommandOutput { if self.config.dry_run() { return CommandOutput::default(); } - let mut command = command.into(); + let command = command.as_mut(); self.verbose(|| println!("running: {command:?}")); - let output_mode = command.output_mode.unwrap_or_else(|| match self.is_verbose() { - true => OutputMode::All, - false => OutputMode::OnlyOutput, - }); - let (output, print_error): (io::Result, bool) = match output_mode { - mode @ (OutputMode::All | OutputMode::OnlyOutput) => ( - command.command.status().map(|status| status.into()), - matches!(mode, OutputMode::All), - ), - mode @ (OutputMode::OnlyOnFailure | OutputMode::Quiet) => ( - command.command.output().map(|o| o.into()), - matches!(mode, OutputMode::OnlyOnFailure), - ), + let output: io::Result = match command.output_mode { + OutputMode::Print => command.command.status().map(|status| status.into()), + OutputMode::CaptureAll => command.command.output().map(|o| o.into()), + OutputMode::CaptureStdout => { + command.command.stderr(Stdio::inherit()); + command.command.output().map(|o| o.into()) + } }; let output = match output { Ok(output) => output, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)), + Err(e) => fail(&format!("failed to execute command: {command:?}\nerror: {e}")), }; if !output.is_success() { - if print_error { - println!( - "\n\nCommand did not execute successfully.\ - \nExpected success, got: {}", - output.status(), - ); + use std::fmt::Write; + + // Here we build an error message, and below we decide if it should be printed or not. + let mut message = String::new(); + writeln!( + message, + "\n\nCommand {command:?} did not execute successfully.\ + \nExpected success, got: {}", + output.status(), + ) + .unwrap(); - if !self.is_verbose() { - println!("Add `-v` to see more details.\n"); - } + // If the output mode is OutputMode::Print, the output has already been printed to + // stdout/stderr, and we thus don't have anything captured to print anyway. + if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout) { + writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); - self.verbose(|| { - println!( - "\nSTDOUT ----\n{}\n\ - STDERR ----\n{}\n", - output.stdout(), - output.stderr(), - ) - }); + // Stderr is added to the message only if it was captured + if matches!(command.output_mode, OutputMode::CaptureAll) { + writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); + } } match command.failure_behavior { BehaviorOnFailure::DelayFail => { if self.fail_fast { + println!("{message}"); exit!(1); } let mut failures = self.delayed_failures.borrow_mut(); - failures.push(format!("{command:?}")); + failures.push(message); } BehaviorOnFailure::Exit => { + println!("{message}"); exit!(1); } - BehaviorOnFailure::Ignore => {} + BehaviorOnFailure::Ignore => { + // If failures are allowed, either the error has been printed already + // (OutputMode::Print) or the user used a capture output mode and wants to + // handle the error output on their own. + } } } output @@ -1490,7 +1489,7 @@ impl Build { // (Note that we use a `..` range, not the `...` symmetric difference.) self.run( helpers::git(Some(&self.src)) - .quiet() + .capture() .arg("rev-list") .arg("--count") .arg("--merges") diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index dc30876601c6b..5f9e164816179 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -13,18 +13,19 @@ pub enum BehaviorOnFailure { Ignore, } -/// How should the output of the command be handled. +/// How should the output of the command be handled (whether it should be captured or printed). #[derive(Debug, Copy, Clone)] pub enum OutputMode { - /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it - /// fails. - All, - /// Print the output (by inheriting stdout/stderr). - OnlyOutput, - /// Suppress the output if the command succeeds, otherwise print the output. - OnlyOnFailure, - /// Suppress the output of the command. - Quiet, + /// Prints the stdout/stderr of the command to stdout/stderr of bootstrap (by inheriting these + /// streams). + /// Corresponds to calling `cmd.status()`. + Print, + /// Captures the stdout and stderr of the command into memory. + /// Corresponds to calling `cmd.output()`. + CaptureAll, + /// Captures the stdout of the command into memory, inherits stderr. + /// Corresponds to calling `cmd.output()`. + CaptureStdout, } /// Wrapper around `std::process::Command`. @@ -34,10 +35,10 @@ pub enum OutputMode { /// If you want to delay failures until the end of bootstrap, use [delay_failure]. /// /// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap -/// ([OutputMode::OnlyOutput]). If bootstrap uses verbose mode, then it will also print the -/// command itself in case of failure ([OutputMode::All]). -/// If you want to handle the output programmatically, use `output_mode(OutputMode::OnlyOnFailure)`, -/// which will print the output only if the command fails. +/// ([OutputMode::Print]). +/// If you want to handle the output programmatically, use [BootstrapCommand::capture]. +/// +/// Bootstrap will print a debug log to stdout if the command fails and failure is not allowed. /// /// [allow_failure]: BootstrapCommand::allow_failure /// [delay_failure]: BootstrapCommand::delay_failure @@ -45,12 +46,16 @@ pub enum OutputMode { pub struct BootstrapCommand { pub command: Command, pub failure_behavior: BehaviorOnFailure, - pub output_mode: Option, + pub output_mode: OutputMode, } impl BootstrapCommand { pub fn new>(program: S) -> Self { - Command::new(program).into() + Self { + command: Command::new(program), + failure_behavior: BehaviorOnFailure::Exit, + output_mode: OutputMode::Print, + } } pub fn arg>(&mut self, arg: S) -> &mut Self { @@ -106,52 +111,22 @@ impl BootstrapCommand { Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } } - /// Do not print the output of the command, unless it fails. - pub fn print_on_failure(self) -> Self { - self.output_mode(OutputMode::OnlyOnFailure) - } - - /// Do not print the output of the command. - pub fn quiet(self) -> Self { - self.output_mode(OutputMode::Quiet) + /// Capture the output of the command, do not print it. + pub fn capture(self) -> Self { + Self { output_mode: OutputMode::CaptureAll, ..self } } - pub fn output_mode(self, output_mode: OutputMode) -> Self { - Self { output_mode: Some(output_mode), ..self } + /// Capture stdout of the command, do not print it. + pub fn capture_stdout(self) -> Self { + Self { output_mode: OutputMode::CaptureStdout, ..self } } } -/// FIXME: This implementation is temporary, until all `Command` invocations are migrated to -/// `BootstrapCommand`. -impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand { - fn from(command: &'a mut BootstrapCommand) -> Self { - // This is essentially a manual `Command::clone` - let mut cmd = Command::new(command.command.get_program()); - if let Some(dir) = command.command.get_current_dir() { - cmd.current_dir(dir); - } - cmd.args(command.command.get_args()); - for (key, value) in command.command.get_envs() { - match value { - Some(value) => { - cmd.env(key, value); - } - None => { - cmd.env_remove(key); - } - } - } - Self { - command: cmd, - output_mode: command.output_mode, - failure_behavior: command.failure_behavior, - } - } -} - -impl From for BootstrapCommand { - fn from(command: Command) -> Self { - Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: None } +/// This implementation exists to make it possible to pass both [BootstrapCommand] and +/// `&mut BootstrapCommand` to `Build.run()`. +impl AsMut for BootstrapCommand { + fn as_mut(&mut self) -> &mut BootstrapCommand { + self } } @@ -176,6 +151,10 @@ impl CommandOutput { String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8") } + pub fn stdout_if_ok(&self) -> Option { + if self.is_success() { Some(self.stdout()) } else { None } + } + pub fn stderr(&self) -> String { String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8") } From 3ef77cc42cb1ea1f07c1bd8c2ac514d15291106b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Jun 2024 17:47:11 +0200 Subject: [PATCH 113/189] Remove various usages of the `output` function --- src/bootstrap/src/core/build_steps/compile.rs | 13 ++-- src/bootstrap/src/core/build_steps/dist.rs | 19 ++--- src/bootstrap/src/core/build_steps/format.rs | 33 ++++----- src/bootstrap/src/core/build_steps/llvm.rs | 14 ++-- src/bootstrap/src/core/build_steps/run.rs | 6 +- src/bootstrap/src/core/build_steps/suggest.rs | 25 +++---- .../src/core/build_steps/synthetic_targets.rs | 14 ++-- src/bootstrap/src/core/build_steps/test.rs | 70 ++++++++----------- src/bootstrap/src/core/build_steps/tool.rs | 5 +- src/bootstrap/src/core/builder.rs | 7 +- src/bootstrap/src/core/metadata.rs | 8 +-- src/bootstrap/src/core/sanity.rs | 4 +- src/bootstrap/src/lib.rs | 6 +- src/bootstrap/src/utils/cc_detect.rs | 8 +-- src/bootstrap/src/utils/exec.rs | 12 ++-- src/bootstrap/src/utils/helpers.rs | 8 ++- 16 files changed, 120 insertions(+), 132 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c267d3b0c0cf6..01b25224de4cd 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -29,7 +29,7 @@ use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, T use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ - exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date, + exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; @@ -1488,10 +1488,10 @@ pub fn compiler_file( if builder.config.dry_run() { return PathBuf::new(); } - let mut cmd = Command::new(compiler); + let mut cmd = BootstrapCommand::new(compiler); cmd.args(builder.cflags(target, GitRepo::Rustc, c)); cmd.arg(format!("-print-file-name={file}")); - let out = output(&mut cmd); + let out = builder.run(cmd.capture_stdout()).stdout(); PathBuf::from(out.trim()) } @@ -1836,7 +1836,9 @@ impl Step for Assemble { let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: target_compiler.host }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { - let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir")); + let llvm_bin_dir = builder + .run(BootstrapCommand::new(llvm_config).capture_stdout().arg("--bindir")) + .stdout(); let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); // Since we've already built the LLVM tools, install them to the sysroot. @@ -2161,8 +2163,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) } let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap()); - // NOTE: `output` will propagate any errors here. - output(Command::new("strip").arg("--strip-debug").arg(path)); + builder.run(BootstrapCommand::new("strip").capture().arg("--strip-debug").arg(path)); // After running `strip`, we have to set the file modification time to what it was before, // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 08795efe5bb4c..3dc871b1ca9dd 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -14,7 +14,6 @@ use std::ffi::OsStr; use std::fs; use std::io::Write; use std::path::{Path, PathBuf}; -use std::process::Command; use object::read::archive::ArchiveFile; use object::BinaryFormat; @@ -28,7 +27,7 @@ use crate::core::config::TargetSelection; use crate::utils::channel::{self, Info}; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ - exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit, + exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; @@ -181,9 +180,9 @@ fn make_win_dist( } //Ask gcc where it keeps its stuff - let mut cmd = Command::new(builder.cc(target)); + let mut cmd = BootstrapCommand::new(builder.cc(target)); cmd.arg("-print-search-dirs"); - let gcc_out = output(&mut cmd); + let gcc_out = builder.run(cmd.capture_stdout()).stdout(); let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); let mut lib_path = Vec::new(); @@ -1024,7 +1023,7 @@ impl Step for PlainSourceTarball { } // Vendor all Cargo dependencies - let mut cmd = Command::new(&builder.initial_cargo); + let mut cmd = BootstrapCommand::new(&builder.initial_cargo); cmd.arg("vendor") .arg("--versioned-dirs") .arg("--sync") @@ -1062,7 +1061,7 @@ impl Step for PlainSourceTarball { } let config = if !builder.config.dry_run() { - t!(String::from_utf8(t!(cmd.output()).stdout)) + builder.run(cmd.capture()).stdout() } else { String::new() }; @@ -2079,10 +2078,14 @@ fn maybe_install_llvm( } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = llvm::prebuilt_llvm_config(builder, target) { - let mut cmd = Command::new(llvm_config); + let mut cmd = BootstrapCommand::new(llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); - let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) }; + let files = if builder.config.dry_run() { + "".into() + } else { + builder.run(cmd.capture_stdout()).stdout() + }; let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); for file in files.trim_end().split(' ') { diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 0372360c3cb74..66286a52813f4 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -1,7 +1,8 @@ //! Runs rustfmt on the repository. use crate::core::builder::Builder; -use crate::utils::helpers::{self, output, program_out_of_date, t}; +use crate::utils::exec::BootstrapCommand; +use crate::utils::helpers::{self, program_out_of_date, t}; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; @@ -53,19 +54,17 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> { let stamp_file = build.out.join("rustfmt.stamp"); - let mut cmd = Command::new(match build.initial_rustfmt() { + let mut cmd = BootstrapCommand::new(match build.initial_rustfmt() { Some(p) => p, None => return None, }); cmd.arg("--version"); - let output = match cmd.output() { - Ok(status) => status, - Err(_) => return None, - }; - if !output.status.success() { + + let output = build.run(cmd.capture().allow_failure()); + if output.is_failure() { return None; } - Some((String::from_utf8(output.stdout).unwrap(), stamp_file)) + Some((output.stdout(), stamp_file)) } /// Return whether the format cache can be reused. @@ -175,14 +174,16 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { ) .is_success(); if in_working_tree { - let untracked_paths_output = output( - &mut helpers::git(Some(&build.src)) - .arg("status") - .arg("--porcelain") - .arg("-z") - .arg("--untracked-files=normal") - .command, - ); + let untracked_paths_output = build + .run( + helpers::git(Some(&build.src)) + .capture_stdout() + .arg("status") + .arg("--porcelain") + .arg("-z") + .arg("--untracked-files=normal"), + ) + .stdout(); let untracked_paths: Vec<_> = untracked_paths_output .split_terminator('\0') .filter_map( diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index ba21e2ad32d05..4f1c1f87d1c6c 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -14,7 +14,6 @@ use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::Command; use std::sync::OnceLock; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; @@ -25,6 +24,7 @@ use crate::utils::helpers::{ }; use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; +use crate::utils::exec::BootstrapCommand; use build_helper::ci::CiEnv; use build_helper::git::get_git_merge_base; @@ -478,7 +478,9 @@ impl Step for Llvm { let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build }); if !builder.config.dry_run() { - let llvm_bindir = output(Command::new(&llvm_config).arg("--bindir")); + let llvm_bindir = builder + .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--bindir")) + .stdout(); let host_bin = Path::new(llvm_bindir.trim()); cfg.define( "LLVM_TABLEGEN", @@ -528,8 +530,8 @@ impl Step for Llvm { // Helper to find the name of LLVM's shared library on darwin and linux. let find_llvm_lib_name = |extension| { - let mut cmd = Command::new(&res.llvm_config); - let version = output(cmd.arg("--version")); + let cmd = BootstrapCommand::new(&res.llvm_config); + let version = builder.run(cmd.capture_stdout().arg("--version")).stdout(); let major = version.split('.').next().unwrap(); match &llvm_version_suffix { @@ -585,8 +587,8 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { return; } - let mut cmd = Command::new(llvm_config); - let version = output(cmd.arg("--version")); + let cmd = BootstrapCommand::new(llvm_config); + let version = builder.run(cmd.capture_stdout().arg("--version")).stdout(); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { if major >= 17 { diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 496fe446d724e..316a03a2171b5 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -4,7 +4,6 @@ //! If it can be reached from `./x.py run` it can go here. use std::path::PathBuf; -use std::process::Command; use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; @@ -12,7 +11,7 @@ use crate::core::build_steps::tool::{self, SourceType, Tool}; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::TargetSelection; -use crate::utils::helpers::output; +use crate::utils::exec::BootstrapCommand; use crate::Mode; #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] @@ -41,7 +40,8 @@ impl Step for BuildManifest { panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") }); - let today = output(Command::new("date").arg("+%Y-%m-%d")); + let today = + builder.run(BootstrapCommand::new("date").capture_stdout().arg("+%Y-%m-%d")).stdout(); cmd.arg(sign); cmd.arg(distdir(builder)); diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 7c5e0d4e13ebb..5412b3c807b62 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -13,24 +13,15 @@ use crate::core::builder::Builder; pub fn suggest(builder: &Builder<'_>, run: bool) { let git_config = builder.config.git_config(); let suggestions = builder - .tool_cmd(Tool::SuggestTests) - .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) - .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) - .command - .output() - .expect("failed to run `suggest-tests` tool"); + .run( + builder + .tool_cmd(Tool::SuggestTests) + .capture_stdout() + .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) + .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch), + ) + .stdout(); - if !suggestions.status.success() { - println!("failed to run `suggest-tests` tool ({})", suggestions.status); - println!( - "`suggest_tests` stdout:\n{}`suggest_tests` stderr:\n{}", - String::from_utf8(suggestions.stdout).unwrap(), - String::from_utf8(suggestions.stderr).unwrap() - ); - panic!("failed to run `suggest-tests`"); - } - - let suggestions = String::from_utf8(suggestions.stdout).unwrap(); let suggestions = suggestions .lines() .map(|line| { diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 281a9b093b90b..a115ba2d8b27a 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -9,8 +9,8 @@ use crate::core::builder::{Builder, ShouldRun, Step}; use crate::core::config::TargetSelection; +use crate::utils::exec::BootstrapCommand; use crate::Compiler; -use std::process::{Command, Stdio}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct MirOptPanicAbortSyntheticTarget { @@ -56,7 +56,7 @@ fn create_synthetic_target( return TargetSelection::create_synthetic(&name, path.to_str().unwrap()); } - let mut cmd = Command::new(builder.rustc(compiler)); + let mut cmd = BootstrapCommand::new(builder.rustc(compiler)); cmd.arg("--target").arg(base.rustc_target_arg()); cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); @@ -64,14 +64,8 @@ fn create_synthetic_target( // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. cmd.env("RUSTC_BOOTSTRAP", "1"); - cmd.stdout(Stdio::piped()); - - let output = cmd.spawn().unwrap().wait_with_output().unwrap(); - if !output.status.success() { - panic!("failed to gather the target spec for {base}"); - } - - let mut spec: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + let output = builder.run(cmd.capture()).stdout(); + let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap(); let spec_map = spec.as_object_mut().unwrap(); // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9fc337dfd50db..b063d0aaf4f16 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -29,8 +29,7 @@ use crate::core::config::TargetSelection; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, - linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date, - LldThreads, + linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, LldThreads, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{envify, CLang, DocTests, GitRepo, Mode}; @@ -470,19 +469,12 @@ impl Miri { // We re-use the `cargo` from above. cargo.arg("--print-sysroot"); - // FIXME: Is there a way in which we can re-use the usual `run` helpers? if builder.config.dry_run() { String::new() } else { builder.verbose(|| println!("running: {cargo:?}")); - let out = cargo - .command - .output() - .expect("We already ran `cargo miri setup` before and that worked"); - assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code"); + let stdout = builder.run(cargo.capture_stdout()).stdout(); // Output is "\n". - let stdout = String::from_utf8(out.stdout) - .expect("`cargo miri setup` stdout is not valid UTF-8"); let sysroot = stdout.trim_end(); builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); sysroot.to_owned() @@ -911,25 +903,26 @@ impl Step for RustdocJSNotStd { } } -fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option { - let mut command = Command::new(npm); +fn get_browser_ui_test_version_inner( + builder: &Builder<'_>, + npm: &Path, + global: bool, +) -> Option { + let mut command = BootstrapCommand::new(npm).capture(); command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); if global { command.arg("--global"); } - let lines = command - .output() - .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) - .unwrap_or_default(); + let lines = builder.run(command.allow_failure()).stdout(); lines .lines() .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) .map(|v| v.to_owned()) } -fn get_browser_ui_test_version(npm: &Path) -> Option { - get_browser_ui_test_version_inner(npm, false) - .or_else(|| get_browser_ui_test_version_inner(npm, true)) +fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option { + get_browser_ui_test_version_inner(builder, npm, false) + .or_else(|| get_browser_ui_test_version_inner(builder, npm, true)) } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -953,7 +946,7 @@ impl Step for RustdocGUI { .config .npm .as_ref() - .map(|p| get_browser_ui_test_version(p).is_some()) + .map(|p| get_browser_ui_test_version(builder, p).is_some()) .unwrap_or(false) })) } @@ -1811,26 +1804,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); - let lldb_version = Command::new(&lldb_exe) - .arg("--version") - .output() - .map(|output| { - (String::from_utf8_lossy(&output.stdout).to_string(), output.status.success()) - }) - .ok() - .and_then(|(output, success)| if success { Some(output) } else { None }); + let lldb_version = builder + .run(BootstrapCommand::new(&lldb_exe).capture().allow_failure().arg("--version")) + .stdout_if_ok(); if let Some(ref vers) = lldb_version { - let run = |cmd: &mut Command| { - cmd.output().map(|output| { - String::from_utf8_lossy(&output.stdout) - .lines() - .next() - .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output)) - .to_string() - }) - }; cmd.arg("--lldb-version").arg(vers); - let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok(); + let lldb_python_dir = builder + .run(BootstrapCommand::new(&lldb_exe).allow_failure().capture_stdout().arg("-P")) + .stdout_if_ok() + .map(|p| p.lines().next().expect("lldb Python dir not found").to_string()); if let Some(ref dir) = lldb_python_dir { cmd.arg("--lldb-python-dir").arg(dir); } @@ -1886,8 +1868,12 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: builder.config.build }); if !builder.config.dry_run() { - let llvm_version = output(Command::new(&llvm_config).arg("--version")); - let llvm_components = output(Command::new(&llvm_config).arg("--components")); + let llvm_version = builder + .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--version")) + .stdout(); + let llvm_components = builder + .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--components")) + .stdout(); // Remove trailing newline from llvm-config output. cmd.arg("--llvm-version") .arg(llvm_version.trim()) @@ -1906,7 +1892,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // separate compilations. We can add LLVM's library path to the // platform-specific environment variable as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { - let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir")); + let llvm_libdir = builder + .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--libdir")) + .stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 20c7a30f1a823..40184e016a634 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,7 +1,6 @@ use std::env; use std::fs; use std::path::{Path, PathBuf}; -use std::process::Command; use crate::core::build_steps::compile; use crate::core::build_steps::toolstate::ToolState; @@ -10,7 +9,6 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::BootstrapCommand; -use crate::utils::helpers::output; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -926,7 +924,8 @@ impl Step for LibcxxVersionTool { } } - let version_output = output(&mut Command::new(executable)); + let version_output = + builder.run(BootstrapCommand::new(executable).capture_stdout()).stdout(); let version_str = version_output.split_once("version:").unwrap().1; let version = version_str.trim().parse::().unwrap(); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 35de91c41d4f1..4da912994c3ee 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -8,7 +8,6 @@ use std::fs; use std::hash::Hash; use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::process::Command; use std::time::{Duration, Instant}; use crate::core::build_steps::tool::{self, SourceType}; @@ -20,7 +19,7 @@ use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection}; use crate::prepare_behaviour_dump_dir; use crate::utils::cache::Cache; use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, linker_args}; -use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, output, t, LldThreads}; +use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, t, LldThreads}; use crate::EXTRA_CHECK_CFGS; use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode}; @@ -1919,7 +1918,9 @@ impl<'a> Builder<'a> { // platform-specific environment variable as a workaround. if mode == Mode::ToolRustc || mode == Mode::Codegen { if let Some(llvm_config) = self.llvm_config(target) { - let llvm_libdir = output(Command::new(llvm_config).arg("--libdir")); + let llvm_libdir = self + .run(BootstrapCommand::new(llvm_config).capture_stdout().arg("--libdir")) + .stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo); } } diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 220eb5ba126e4..da269959e7b43 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -1,9 +1,8 @@ use std::path::PathBuf; -use std::process::Command; use serde_derive::Deserialize; -use crate::utils::helpers::output; +use crate::utils::exec::BootstrapCommand; use crate::{t, Build, Crate}; /// For more information, see the output of @@ -71,7 +70,7 @@ pub fn build(build: &mut Build) { /// particular crate (e.g., `x build sysroot` to build library/sysroot). fn workspace_members(build: &Build) -> Vec { let collect_metadata = |manifest_path| { - let mut cargo = Command::new(&build.initial_cargo); + let mut cargo = BootstrapCommand::new(&build.initial_cargo); cargo // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -82,7 +81,8 @@ fn workspace_members(build: &Build) -> Vec { .arg("--no-deps") .arg("--manifest-path") .arg(build.src.join(manifest_path)); - let metadata_output = output(&mut cargo); + // FIXME: fix stderr + let metadata_output = build.run(cargo.capture()).stdout(); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages }; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 5a0be2948a19e..d64923e69cbd0 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -24,6 +24,7 @@ use std::collections::HashSet; use crate::builder::Kind; use crate::core::config::Target; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::output; use crate::Build; @@ -352,7 +353,8 @@ than building it. // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. - let out = output(Command::new("cmake").arg("--help")); + let out = + build.run(BootstrapCommand::new("cmake").capture_stdout().arg("--help")).stdout(); if !out.contains("Visual Studio") { panic!( " diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ae3d18e8774bc..dfaa1e5eb1294 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -861,14 +861,16 @@ impl Build { if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { s.to_path_buf() } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - let llvm_bindir = output(Command::new(s).arg("--bindir")); + let llvm_bindir = + self.run(BootstrapCommand::new(s).capture_stdout().arg("--bindir")).stdout(); let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)); if filecheck.exists() { filecheck } else { // On Fedora the system LLVM installs FileCheck in the // llvm subdirectory of the libdir. - let llvm_libdir = output(Command::new(s).arg("--libdir")); + let llvm_libdir = + self.run(BootstrapCommand::new(s).capture_stdout().arg("--libdir")).stdout(); let lib_filecheck = Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target)); if lib_filecheck.exists() { diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 540b8671333a9..b80df54520264 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -23,11 +23,10 @@ use std::collections::HashSet; use std::path::{Path, PathBuf}; -use std::process::Command; use std::{env, iter}; use crate::core::config::TargetSelection; -use crate::utils::helpers::output; +use crate::utils::exec::BootstrapCommand; use crate::{Build, CLang, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, @@ -183,14 +182,15 @@ fn default_compiler( return None; } - let output = output(c.to_command().arg("--version")); + let cmd = BootstrapCommand::from(c.to_command()); + let output = build.run(cmd.capture_stdout().arg("--version")).stdout(); let i = output.find(" 4.")?; match output[i + 3..].chars().next().unwrap() { '0'..='6' => {} _ => return None, } let alternative = format!("e{gnu_compiler}"); - if Command::new(&alternative).output().is_ok() { + if build.run(BootstrapCommand::new(&alternative).capture()).is_success() { Some(PathBuf::from(alternative)) } else { None diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 5f9e164816179..bda6e0bfbac02 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -51,11 +51,7 @@ pub struct BootstrapCommand { impl BootstrapCommand { pub fn new>(program: S) -> Self { - Self { - command: Command::new(program), - failure_behavior: BehaviorOnFailure::Exit, - output_mode: OutputMode::Print, - } + Command::new(program).into() } pub fn arg>(&mut self, arg: S) -> &mut Self { @@ -130,6 +126,12 @@ impl AsMut for BootstrapCommand { } } +impl From for BootstrapCommand { + fn from(command: Command) -> Self { + Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: OutputMode::Print } + } +} + /// Represents the output of an executed process. #[allow(unused)] pub struct CommandOutput(Output); diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 9c40065dfc4fa..bbd4185874f4f 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -360,7 +360,7 @@ pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { /// Returns a flag that configures LLD to use only a single thread. /// If we use an external LLD, we need to find out which version is it to know which flag should we /// pass to it (LLD older than version 10 had a different flag). -fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str { +fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: bool) -> &'static str { static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new(); let new_flags = ("/threads:1", "--threads=1"); @@ -369,7 +369,9 @@ fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str { let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| { let newer_version = match lld_mode { LldMode::External => { - let out = output(Command::new("lld").arg("-flavor").arg("ld").arg("--version")); + let mut cmd = BootstrapCommand::new("lld").capture_stdout(); + cmd.arg("-flavor").arg("ld").arg("--version"); + let out = builder.run(cmd).stdout(); match (out.find(char::is_numeric), out.find('.')) { (Some(b), Some(e)) => out.as_str()[b..e].parse::().ok().unwrap_or(14) > 10, _ => true, @@ -431,7 +433,7 @@ pub fn linker_flags( if matches!(lld_threads, LldThreads::No) { args.push(format!( "-Clink-arg=-Wl,{}", - lld_flag_no_threads(builder.config.lld_mode, target.is_windows()) + lld_flag_no_threads(builder, builder.config.lld_mode, target.is_windows()) )); } } From e8c8860142a999d086efe579e8e17df8437a9730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Jun 2024 17:54:44 +0200 Subject: [PATCH 114/189] Allow unused `Tool` variants --- src/bootstrap/src/core/build_steps/tool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 40184e016a634..5fb282db90a7c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -244,6 +244,7 @@ macro_rules! bootstrap_tool { ; )+) => { #[derive(PartialEq, Eq, Clone)] + #[allow(dead_code)] pub enum Tool { $( $name, From 60c20bfe0c6e34d36d9a40d835ce6946a10f0238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 29 Jun 2024 16:00:23 +0200 Subject: [PATCH 115/189] Refactor command outcome handling To handle the case of failing to start a `BootstrapCommand`. --- src/bootstrap/src/core/sanity.rs | 15 ++++--- src/bootstrap/src/lib.rs | 77 +++++++++++++++++++------------- src/bootstrap/src/utils/exec.rs | 52 +++++++++++++++------ 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index d64923e69cbd0..78862ccb8cd68 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -13,7 +13,6 @@ use std::env; use std::ffi::{OsStr, OsString}; use std::fs; use std::path::PathBuf; -use std::process::Command; #[cfg(not(feature = "bootstrap-self-test"))] use crate::builder::Builder; @@ -25,7 +24,6 @@ use std::collections::HashSet; use crate::builder::Kind; use crate::core::config::Target; use crate::utils::exec::BootstrapCommand; -use crate::utils::helpers::output; use crate::Build; pub struct Finder { @@ -210,11 +208,14 @@ than building it. .or_else(|| cmd_finder.maybe_have("reuse")); #[cfg(not(feature = "bootstrap-self-test"))] - let stage0_supported_target_list: HashSet = - output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"])) - .lines() - .map(|s| s.to_string()) - .collect(); + let stage0_supported_target_list: HashSet = crate::utils::helpers::output( + &mut BootstrapCommand::new(&build.config.initial_rustc) + .args(["--print", "target-list"]) + .command, + ) + .lines() + .map(|s| s.to_string()) + .collect(); // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index dfaa1e5eb1294..309fec474a14b 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,14 +23,13 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Output, Stdio}; use std::str; use std::sync::OnceLock; use std::time::SystemTime; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; -use build_helper::util::fail; use filetime::FileTime; use sha2::digest::Digest; use termcolor::{ColorChoice, StandardStream, WriteColor}; @@ -945,43 +944,61 @@ impl Build { self.verbose(|| println!("running: {command:?}")); - let output: io::Result = match command.output_mode { - OutputMode::Print => command.command.status().map(|status| status.into()), - OutputMode::CaptureAll => command.command.output().map(|o| o.into()), + let output: io::Result = match command.output_mode { + OutputMode::Print => command.command.status().map(|status| Output { + status, + stdout: vec![], + stderr: vec![], + }), + OutputMode::CaptureAll => command.command.output(), OutputMode::CaptureStdout => { command.command.stderr(Stdio::inherit()); - command.command.output().map(|o| o.into()) + command.command.output() } }; - let output = match output { - Ok(output) => output, - Err(e) => fail(&format!("failed to execute command: {command:?}\nerror: {e}")), - }; - if !output.is_success() { - use std::fmt::Write; - - // Here we build an error message, and below we decide if it should be printed or not. - let mut message = String::new(); - writeln!( - message, - "\n\nCommand {command:?} did not execute successfully.\ + use std::fmt::Write; + + let mut message = String::new(); + let output: CommandOutput = match output { + // Command has succeeded + Ok(output) if output.status.success() => output.into(), + // Command has started, but then it failed + Ok(output) => { + writeln!( + message, + "\n\nCommand {command:?} did not execute successfully.\ \nExpected success, got: {}", - output.status(), - ) - .unwrap(); - - // If the output mode is OutputMode::Print, the output has already been printed to - // stdout/stderr, and we thus don't have anything captured to print anyway. - if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout) { - writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); + output.status, + ) + .unwrap(); + + let output: CommandOutput = output.into(); + // If the output mode is OutputMode::Print, the output has already been printed to + // stdout/stderr, and we thus don't have anything captured to print anyway. + if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout) + { + writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); - // Stderr is added to the message only if it was captured - if matches!(command.output_mode, OutputMode::CaptureAll) { - writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); + // Stderr is added to the message only if it was captured + if matches!(command.output_mode, OutputMode::CaptureAll) { + writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); + } } + output } - + // The command did not even start + Err(e) => { + writeln!( + message, + "\n\nCommand {command:?} did not execute successfully.\ + \nIt was not possible to execute the command: {e:?}" + ) + .unwrap(); + CommandOutput::did_not_start() + } + }; + if !output.is_success() { match command.failure_behavior { BehaviorOnFailure::DelayFail => { if self.fail_fast { diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index bda6e0bfbac02..78a3b917e459a 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -132,25 +132,47 @@ impl From for BootstrapCommand { } } +/// Represents the outcome of starting a command. +enum CommandOutcome { + /// The command has started and finished with some status. + Finished(ExitStatus), + /// It was not even possible to start the command. + DidNotStart, +} + /// Represents the output of an executed process. #[allow(unused)] -pub struct CommandOutput(Output); +pub struct CommandOutput { + outcome: CommandOutcome, + stdout: Vec, + stderr: Vec, +} impl CommandOutput { + pub fn did_not_start() -> Self { + Self { outcome: CommandOutcome::DidNotStart, stdout: vec![], stderr: vec![] } + } + pub fn is_success(&self) -> bool { - self.0.status.success() + match self.outcome { + CommandOutcome::Finished(status) => status.success(), + CommandOutcome::DidNotStart => false, + } } pub fn is_failure(&self) -> bool { !self.is_success() } - pub fn status(&self) -> ExitStatus { - self.0.status + pub fn status(&self) -> Option { + match self.outcome { + CommandOutcome::Finished(status) => Some(status), + CommandOutcome::DidNotStart => None, + } } pub fn stdout(&self) -> String { - String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8") + String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8") } pub fn stdout_if_ok(&self) -> Option { @@ -158,24 +180,26 @@ impl CommandOutput { } pub fn stderr(&self) -> String { - String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8") + String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8") } } impl Default for CommandOutput { fn default() -> Self { - Self(Output { status: Default::default(), stdout: vec![], stderr: vec![] }) + Self { + outcome: CommandOutcome::Finished(ExitStatus::default()), + stdout: vec![], + stderr: vec![], + } } } impl From for CommandOutput { fn from(output: Output) -> Self { - Self(output) - } -} - -impl From for CommandOutput { - fn from(status: ExitStatus) -> Self { - Self(Output { status, stdout: vec![], stderr: vec![] }) + Self { + outcome: CommandOutcome::Finished(output.status), + stdout: output.stdout, + stderr: output.stderr, + } } } From 70b6e044523b0a2bc89b748a389c04277b5b9da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 29 Jun 2024 22:07:59 +0200 Subject: [PATCH 116/189] Handle execution of dry run commands --- src/bootstrap/src/core/build_steps/perf.rs | 1 - src/bootstrap/src/core/build_steps/test.rs | 8 +++++++- src/bootstrap/src/core/metadata.rs | 3 +-- src/bootstrap/src/lib.rs | 5 ++--- src/bootstrap/src/utils/exec.rs | 14 +++++++++++++- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 20ab1836e0068..f41b5fe10f1d9 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -2,7 +2,6 @@ use crate::core::build_steps::compile::{Std, Sysroot}; use crate::core::build_steps::tool::{RustcPerf, Tool}; use crate::core::builder::Builder; use crate::core::config::DebuginfoLevel; -use crate::utils::exec::BootstrapCommand; /// Performs profiling using `rustc-perf` on a built version of the compiler. pub fn perf(builder: &Builder<'_>) { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index b063d0aaf4f16..998e45848a1c3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1805,7 +1805,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); let lldb_version = builder - .run(BootstrapCommand::new(&lldb_exe).capture().allow_failure().arg("--version")) + .run( + BootstrapCommand::new(&lldb_exe) + .capture() + .allow_failure() + .run_always() + .arg("--version"), + ) .stdout_if_ok(); if let Some(ref vers) = lldb_version { cmd.arg("--lldb-version").arg(vers); diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index da269959e7b43..49d17107125aa 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -81,8 +81,7 @@ fn workspace_members(build: &Build) -> Vec { .arg("--no-deps") .arg("--manifest-path") .arg(build.src.join(manifest_path)); - // FIXME: fix stderr - let metadata_output = build.run(cargo.capture()).stdout(); + let metadata_output = build.run(cargo.capture_stdout().run_always()).stdout(); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages }; diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 309fec474a14b..ce139a0bc59df 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -936,12 +936,11 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. fn run>(&self, mut command: C) -> CommandOutput { - if self.config.dry_run() { + let command = command.as_mut(); + if self.config.dry_run() && !command.run_always { return CommandOutput::default(); } - let command = command.as_mut(); - self.verbose(|| println!("running: {command:?}")); let output: io::Result = match command.output_mode { diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 78a3b917e459a..98d194e64d3ab 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -47,6 +47,8 @@ pub struct BootstrapCommand { pub command: Command, pub failure_behavior: BehaviorOnFailure, pub output_mode: OutputMode, + // Run the command even during dry run + pub run_always: bool, } impl BootstrapCommand { @@ -107,6 +109,11 @@ impl BootstrapCommand { Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } } + pub fn run_always(&mut self) -> &mut Self { + self.run_always = true; + self + } + /// Capture the output of the command, do not print it. pub fn capture(self) -> Self { Self { output_mode: OutputMode::CaptureAll, ..self } @@ -128,7 +135,12 @@ impl AsMut for BootstrapCommand { impl From for BootstrapCommand { fn from(command: Command) -> Self { - Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: OutputMode::Print } + Self { + command, + failure_behavior: BehaviorOnFailure::Exit, + output_mode: OutputMode::Print, + run_always: false, + } } } From b90129dd21edb7492c7c4fc58883e849be8deff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 3 Jul 2024 11:33:43 +0200 Subject: [PATCH 117/189] Review changes --- src/bootstrap/src/utils/exec.rs | 27 +++++++++++++-------------- src/bootstrap/src/utils/helpers.rs | 9 +++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 98d194e64d3ab..74fb483773e3a 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -34,8 +34,7 @@ pub enum OutputMode { /// If you want to allow failures, use [allow_failure]. /// If you want to delay failures until the end of bootstrap, use [delay_failure]. /// -/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap -/// ([OutputMode::Print]). +/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap ([OutputMode::Print]). /// If you want to handle the output programmatically, use [BootstrapCommand::capture]. /// /// Bootstrap will print a debug log to stdout if the command fails and failure is not allowed. @@ -144,8 +143,8 @@ impl From for BootstrapCommand { } } -/// Represents the outcome of starting a command. -enum CommandOutcome { +/// Represents the current status of `BootstrapCommand`. +enum CommandStatus { /// The command has started and finished with some status. Finished(ExitStatus), /// It was not even possible to start the command. @@ -155,20 +154,20 @@ enum CommandOutcome { /// Represents the output of an executed process. #[allow(unused)] pub struct CommandOutput { - outcome: CommandOutcome, + status: CommandStatus, stdout: Vec, stderr: Vec, } impl CommandOutput { pub fn did_not_start() -> Self { - Self { outcome: CommandOutcome::DidNotStart, stdout: vec![], stderr: vec![] } + Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] } } pub fn is_success(&self) -> bool { - match self.outcome { - CommandOutcome::Finished(status) => status.success(), - CommandOutcome::DidNotStart => false, + match self.status { + CommandStatus::Finished(status) => status.success(), + CommandStatus::DidNotStart => false, } } @@ -177,9 +176,9 @@ impl CommandOutput { } pub fn status(&self) -> Option { - match self.outcome { - CommandOutcome::Finished(status) => Some(status), - CommandOutcome::DidNotStart => None, + match self.status { + CommandStatus::Finished(status) => Some(status), + CommandStatus::DidNotStart => None, } } @@ -199,7 +198,7 @@ impl CommandOutput { impl Default for CommandOutput { fn default() -> Self { Self { - outcome: CommandOutcome::Finished(ExitStatus::default()), + status: CommandStatus::Finished(ExitStatus::default()), stdout: vec![], stderr: vec![], } @@ -209,7 +208,7 @@ impl Default for CommandOutput { impl From for CommandOutput { fn from(output: Output) -> Self { Self { - outcome: CommandOutcome::Finished(output.status), + status: CommandStatus::Finished(output.status), stdout: output.stdout, stderr: output.stderr, } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index bbd4185874f4f..2575b7939b44c 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -494,12 +494,13 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { format!("--check-cfg=cfg({name}{next})") } -/// Prepares `Command` that runs git inside the source directory if given. +/// Prepares `BootstrapCommand` that runs git inside the source directory if given. /// /// Whenever a git invocation is needed, this function should be preferred over -/// manually building a git `Command`. This approach allows us to manage bootstrap-specific -/// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`, -/// which is painful to ensure that the required change is applied on each one of them correctly. +/// manually building a git `BootstrapCommand`. This approach allows us to manage +/// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every +/// `BootstrapCommand::new("git")`, which is painful to ensure that the required change is applied +/// on each one of them correctly. pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { let mut git = BootstrapCommand::new("git"); From b618fea358147080a27f3984a3be078f8b49e519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 3 Jul 2024 21:04:02 +0200 Subject: [PATCH 118/189] Simplify and generalize implementation of output mode --- src/bootstrap/src/lib.rs | 35 ++++++++++--------------- src/bootstrap/src/utils/exec.rs | 45 +++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ce139a0bc59df..ffdd9bc885a62 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,7 +23,7 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Output, Stdio}; +use std::process::{Command, Stdio}; use std::str; use std::sync::OnceLock; use std::time::SystemTime; @@ -41,7 +41,7 @@ use crate::core::builder::Kind; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; -use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode}; +use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; @@ -943,18 +943,10 @@ impl Build { self.verbose(|| println!("running: {command:?}")); - let output: io::Result = match command.output_mode { - OutputMode::Print => command.command.status().map(|status| Output { - status, - stdout: vec![], - stderr: vec![], - }), - OutputMode::CaptureAll => command.command.output(), - OutputMode::CaptureStdout => { - command.command.stderr(Stdio::inherit()); - command.command.output() - } - }; + command.command.stdout(command.stdout.stdio()); + command.command.stderr(command.stderr.stdio()); + + let output = command.command.output(); use std::fmt::Write; @@ -973,16 +965,15 @@ impl Build { .unwrap(); let output: CommandOutput = output.into(); - // If the output mode is OutputMode::Print, the output has already been printed to + + // If the output mode is OutputMode::Capture, we can now print the output. + // If it is OutputMode::Print, then the output has already been printed to // stdout/stderr, and we thus don't have anything captured to print anyway. - if matches!(command.output_mode, OutputMode::CaptureAll | OutputMode::CaptureStdout) - { + if command.stdout.captures() { writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); - - // Stderr is added to the message only if it was captured - if matches!(command.output_mode, OutputMode::CaptureAll) { - writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); - } + } + if command.stderr.captures() { + writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); } output } diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 74fb483773e3a..086d10c63511a 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,6 +1,6 @@ use std::ffi::OsStr; use std::path::Path; -use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output}; +use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; /// What should be done when the command fails. #[derive(Debug, Copy, Clone)] @@ -13,19 +13,30 @@ pub enum BehaviorOnFailure { Ignore, } -/// How should the output of the command be handled (whether it should be captured or printed). +/// How should the output of a specific stream of the command (stdout/stderr) be handled +/// (whether it should be captured or printed). #[derive(Debug, Copy, Clone)] pub enum OutputMode { - /// Prints the stdout/stderr of the command to stdout/stderr of bootstrap (by inheriting these - /// streams). - /// Corresponds to calling `cmd.status()`. + /// Prints the stream by inheriting it from the bootstrap process. Print, - /// Captures the stdout and stderr of the command into memory. - /// Corresponds to calling `cmd.output()`. - CaptureAll, - /// Captures the stdout of the command into memory, inherits stderr. - /// Corresponds to calling `cmd.output()`. - CaptureStdout, + /// Captures the stream into memory. + Capture, +} + +impl OutputMode { + pub fn captures(&self) -> bool { + match self { + OutputMode::Print => false, + OutputMode::Capture => true, + } + } + + pub fn stdio(&self) -> Stdio { + match self { + OutputMode::Print => Stdio::inherit(), + OutputMode::Capture => Stdio::piped(), + } + } } /// Wrapper around `std::process::Command`. @@ -45,7 +56,8 @@ pub enum OutputMode { pub struct BootstrapCommand { pub command: Command, pub failure_behavior: BehaviorOnFailure, - pub output_mode: OutputMode, + pub stdout: OutputMode, + pub stderr: OutputMode, // Run the command even during dry run pub run_always: bool, } @@ -113,14 +125,14 @@ impl BootstrapCommand { self } - /// Capture the output of the command, do not print it. + /// Capture all output of the command, do not print it. pub fn capture(self) -> Self { - Self { output_mode: OutputMode::CaptureAll, ..self } + Self { stdout: OutputMode::Capture, stderr: OutputMode::Capture, ..self } } /// Capture stdout of the command, do not print it. pub fn capture_stdout(self) -> Self { - Self { output_mode: OutputMode::CaptureStdout, ..self } + Self { stdout: OutputMode::Capture, ..self } } } @@ -137,7 +149,8 @@ impl From for BootstrapCommand { Self { command, failure_behavior: BehaviorOnFailure::Exit, - output_mode: OutputMode::Print, + stdout: OutputMode::Print, + stderr: OutputMode::Print, run_always: false, } } From 54952b444566956b12058162eae383c692da0147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 3 Jul 2024 21:14:46 +0200 Subject: [PATCH 119/189] Rebase on master --- src/bootstrap/src/utils/tarball.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 3c15bb296f39a..1a35dc1fd3896 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -370,7 +370,11 @@ impl<'a> Tarball<'a> { if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date let timestamp = helpers::output( - helpers::git(Some(&self.builder.src)).arg("log").arg("-1").arg("--format=%ct"), + &mut helpers::git(Some(&self.builder.src)) + .arg("log") + .arg("-1") + .arg("--format=%ct") + .command, ); cmd.args(["--override-file-mtime", timestamp.trim()]); } From ccc8baf08aa5a204a7df55e67022aa6c5254966c Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 3 Jul 2024 19:38:19 +0000 Subject: [PATCH 120/189] jsondocck: Use correct index for error message. If you misused a count command like `@count $some.selector '"T'"`, you would panic with OOB: ``` thread 'main' panicked at src/tools/jsondocck/src/main.rs:76:92: index out of bounds: the len is 2 but the index is 2 ``` Fixing this typo, we now get. ``` Invalid command: Second argument to @count must be a valid usize (got `"T"`) on line 20 ``` As some point I want to rewrite this code to avoid indexing in general, but this is a nice small fix. --- src/tools/jsondocck/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 688b403bf0e0a..429c6151796fe 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -56,6 +56,8 @@ pub enum CommandKind { impl CommandKind { fn validate(&self, args: &[String], lineno: usize) -> bool { + // FIXME(adotinthevoid): We should "parse, don't validate" here, so we avoid ad-hoc + // indexing in check_command. let count = match self { CommandKind::Has => (1..=2).contains(&args.len()), CommandKind::IsMany => args.len() >= 2, @@ -71,7 +73,7 @@ impl CommandKind { if let CommandKind::Count = self { if args[1].parse::().is_err() { print_err( - &format!("Second argument to @count must be a valid usize (got `{}`)", args[2]), + &format!("Second argument to @count must be a valid usize (got `{}`)", args[1]), lineno, ); return false; From 7e8aac553e756b0eb03fe98e1a65ffc47836ec51 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 3 Jul 2024 19:57:15 +0000 Subject: [PATCH 121/189] rustdoc-json: Better representation of lifetime bounds in where clauses. As suggested [on zulip][1], there's no need to use `GenericBound` here, as the only bound a lifetime can have is that it outlives other lifetimes. While we're making breaking changes here, I also renamed it from using "region" to "lifetime", as this is more user-aligned. See [this comment][2] for details. [1]: https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/.60ItemEnum.3A.3AOpaqueTy.60/near/448871430 [2]: https://github.com/rust-lang/rust/issues/100961#issuecomment-2206565556 --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/json/conversions.rs | 11 +++++++-- src/rustdoc-json-types/lib.rs | 6 ++--- src/tools/jsondoclint/src/validator.rs | 4 ++-- .../lifetime/outlives_in_param.rs | 8 +++++++ .../lifetime/outlives_in_where.rs | 24 +++++++++++++++++++ 6 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 tests/rustdoc-json/lifetime/outlives_in_param.rs create mode 100644 tests/rustdoc-json/lifetime/outlives_in_where.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9050a1c12078b..6aa3da2719a80 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1286,7 +1286,7 @@ impl GenericBound { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub(crate) struct Lifetime(pub Symbol); impl Lifetime { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index b965ab019cc4f..5111e363c522e 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -10,6 +10,7 @@ use rustc_ast::ast; use rustc_attr::DeprecatedSince; use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId}; use rustc_metadata::rendered_const; +use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::{Pos, Symbol}; @@ -512,9 +513,15 @@ impl FromWithTcx for WherePredicate { }) .collect(), }, - RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { + RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate { lifetime: convert_lifetime(lifetime), - bounds: bounds.into_tcx(tcx), + outlives: bounds + .iter() + .map(|bound| match bound { + clean::GenericBound::Outlives(lt) => convert_lifetime(*lt), + _ => bug!("found non-outlives-bound on lifetime predicate"), + }) + .collect(), }, EqPredicate { lhs, rhs } => { WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 68030493e9cfd..89115d4d7d667 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 30; +pub const FORMAT_VERSION: u32 = 31; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -511,9 +511,9 @@ pub enum WherePredicate { /// ``` generic_params: Vec, }, - RegionPredicate { + LifetimePredicate { lifetime: String, - bounds: Vec, + outlives: Vec, }, EqPredicate { lhs: Type, diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 1713a4d812c4b..cd011dce7844e 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -374,8 +374,8 @@ impl<'a> Validator<'a> { bounds.iter().for_each(|b| self.check_generic_bound(b)); generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd)); } - WherePredicate::RegionPredicate { lifetime: _, bounds } => { - bounds.iter().for_each(|b| self.check_generic_bound(b)); + WherePredicate::LifetimePredicate { lifetime: _, outlives: _ } => { + // nop, all strings. } WherePredicate::EqPredicate { lhs, rhs } => { self.check_type(lhs); diff --git a/tests/rustdoc-json/lifetime/outlives_in_param.rs b/tests/rustdoc-json/lifetime/outlives_in_param.rs new file mode 100644 index 0000000000000..f6db93c918329 --- /dev/null +++ b/tests/rustdoc-json/lifetime/outlives_in_param.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength + +// @count '$.index[*][?(@.name=="outlives")].inner.function.generics.params[*]' 2 +// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\" +// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' [] +// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"' +// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]' +pub fn outlives<'a, T: 'a>() {} diff --git a/tests/rustdoc-json/lifetime/outlives_in_where.rs b/tests/rustdoc-json/lifetime/outlives_in_where.rs new file mode 100644 index 0000000000000..ca3e1a150ce8e --- /dev/null +++ b/tests/rustdoc-json/lifetime/outlives_in_where.rs @@ -0,0 +1,24 @@ +// ignore-tidy-linelength + +// @is '$.index[*][?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]' +pub fn on_lifetimes<'a, 'b, 'c, 'all>() +where + 'all: 'a + 'b + 'c, +{ +} + +// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[*]' 2 +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\" +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' [] +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"' +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1 +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"' +// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1 +// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\" +pub fn on_trait<'a, T>() +where + T: 'a, +{ +} From 529a3f4ce609f4bc98215185838351d9815fbdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 3 Jul 2024 19:36:14 +0000 Subject: [PATCH 122/189] cache type sizes in type-size limit visitor --- compiler/rustc_middle/src/ty/instance.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index ae54411d788ab..c50a98e88fd63 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -5,6 +5,7 @@ use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -388,13 +389,25 @@ impl<'tcx> InstanceKind<'tcx> { } fn type_length<'tcx>(item: impl TypeVisitable>) -> usize { - struct Visitor { + struct Visitor<'tcx> { type_length: usize, + cache: FxHashMap, usize>, } - impl<'tcx> TypeVisitor> for Visitor { + impl<'tcx> TypeVisitor> for Visitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) { + if let Some(&value) = self.cache.get(&t) { + self.type_length += value; + return; + } + + let prev = self.type_length; self.type_length += 1; t.super_visit_with(self); + + // We don't try to use the cache if the type is fairly small. + if self.type_length > 16 { + self.cache.insert(t, self.type_length - prev); + } } fn visit_const(&mut self, ct: ty::Const<'tcx>) { @@ -402,7 +415,7 @@ fn type_length<'tcx>(item: impl TypeVisitable>) -> usize { ct.super_visit_with(self); } } - let mut visitor = Visitor { type_length: 0 }; + let mut visitor = Visitor { type_length: 0, cache: Default::default() }; item.visit_with(&mut visitor); visitor.type_length From a9194f30eb5b80bd659f3f8e8357fd19b771063e Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Thu, 4 Jul 2024 04:52:01 +0800 Subject: [PATCH 123/189] Use `IndexVec` for coroutine local mapping --- compiler/rustc_index/src/vec.rs | 5 +++ compiler/rustc_mir_transform/src/coroutine.rs | 35 +++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 88298150a79dc..b866c8b8433d9 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -208,6 +208,11 @@ impl IndexVec> { pub fn remove(&mut self, index: I) -> Option { self.get_mut(index)?.take() } + + #[inline] + pub fn contains(&self, index: I) -> bool { + self.get(index).and_then(Option::as_ref).is_some() + } } impl fmt::Debug for IndexVec { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 05674792426f1..41c9c55cef595 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -58,7 +58,7 @@ use crate::deref_separator::deref_finder; use crate::errors; use crate::pass_manager as pm; use crate::simplify; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; @@ -236,8 +236,7 @@ struct TransformVisitor<'tcx> { discr_ty: Ty<'tcx>, // Mapping from Local to (type of local, coroutine struct index) - // FIXME(eddyb) This should use `IndexVec>`. - remap: FxHashMap, VariantIdx, FieldIdx)>, + remap: IndexVec, VariantIdx, FieldIdx)>>, // A map from a suspension point in a block to the locals which have live storage at that point storage_liveness: IndexVec>>, @@ -485,7 +484,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_eq!(self.remap.get(local), None); + assert!(!self.remap.contains(*local)); } fn visit_place( @@ -495,7 +494,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { _location: Location, ) { // Replace an Local in the remap with a coroutine struct access - if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) { + if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) { replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } } @@ -504,7 +503,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { // Remove StorageLive and StorageDead statements for remapped locals data.retain_statements(|s| match s.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - !self.remap.contains_key(&l) + !self.remap.contains(l) } _ => true, }); @@ -529,13 +528,9 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { // The resume arg target location might itself be remapped if its base local is // live across a yield. - let resume_arg = - if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { - replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); - resume_arg - } else { - resume_arg - }; + if let Some(&Some((ty, variant, idx))) = self.remap.get(resume_arg.local) { + replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); + } let storage_liveness: GrowableBitSet = self.storage_liveness[block].clone().unwrap().into(); @@ -543,7 +538,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { for i in 0..self.always_live_locals.domain_size() { let l = Local::new(i); let needs_storage_dead = storage_liveness.contains(l) - && !self.remap.contains_key(&l) + && !self.remap.contains(l) && !self.always_live_locals.contains(l); if needs_storage_dead { data.statements @@ -1037,7 +1032,7 @@ fn compute_layout<'tcx>( liveness: LivenessInfo, body: &Body<'tcx>, ) -> ( - FxHashMap, VariantIdx, FieldIdx)>, + IndexVec, VariantIdx, FieldIdx)>>, CoroutineLayout<'tcx>, IndexVec>>, ) { @@ -1098,7 +1093,7 @@ fn compute_layout<'tcx>( // Create a map from local indices to coroutine struct indices. let mut variant_fields: IndexVec> = iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); - let mut remap = FxHashMap::default(); + let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); let mut fields = IndexVec::new(); @@ -1109,7 +1104,7 @@ fn compute_layout<'tcx>( // around inside coroutines, so it doesn't matter which variant // index we access them by. let idx = FieldIdx::from_usize(idx); - remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); + remap[locals[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); @@ -1121,7 +1116,9 @@ fn compute_layout<'tcx>( for var in &body.var_debug_info { let VarDebugInfoContents::Place(place) = &var.value else { continue }; let Some(local) = place.as_local() else { continue }; - let Some(&(_, variant, field)) = remap.get(&local) else { continue }; + let Some(&Some((_, variant, field))) = remap.get(local) else { + continue; + }; let saved_local = variant_fields[variant][field]; field_names.get_or_insert_with(saved_local, || var.name); @@ -1524,7 +1521,7 @@ fn create_cases<'tcx>( for i in 0..(body.local_decls.len()) { let l = Local::new(i); let needs_storage_live = point.storage_liveness.contains(l) - && !transform.remap.contains_key(&l) + && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); if needs_storage_live { statements From 493093796014201f8b519324d45f00c8b2e7f2b2 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Thu, 4 Jul 2024 04:41:37 +0800 Subject: [PATCH 124/189] Less magic number for corountine --- compiler/rustc_middle/src/ty/sty.rs | 6 +++++- compiler/rustc_mir_transform/src/coroutine.rs | 7 ++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ff40a726fbc38..52690ae678d6c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -68,6 +68,10 @@ impl<'tcx> ty::CoroutineArgs> { const RETURNED: usize = 1; /// Coroutine has been poisoned. const POISONED: usize = 2; + /// Number of variants to reserve in coroutine state. Corresponds to + /// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED` + /// (end of a coroutine) states. + const RESERVED_VARIANTS: usize = 3; const UNRESUMED_NAME: &'static str = "Unresumed"; const RETURNED_NAME: &'static str = "Returned"; @@ -116,7 +120,7 @@ impl<'tcx> ty::CoroutineArgs> { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), Self::POISONED => Cow::from(Self::POISONED_NAME), - _ => Cow::from(format!("Suspend{}", v.as_usize() - 3)), + _ => Cow::from(format!("Suspend{}", v.as_usize() - Self::RESERVED_VARIANTS)), } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 05674792426f1..4c00038365b73 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -208,11 +208,8 @@ const UNRESUMED: usize = CoroutineArgs::UNRESUMED; const RETURNED: usize = CoroutineArgs::RETURNED; /// Coroutine has panicked and is poisoned. const POISONED: usize = CoroutineArgs::POISONED; - -/// Number of variants to reserve in coroutine state. Corresponds to -/// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED` -/// (end of a coroutine) states. -const RESERVED_VARIANTS: usize = 3; +/// Number of reserved variants of coroutine state. +const RESERVED_VARIANTS: usize = CoroutineArgs::RESERVED_VARIANTS; /// A `yield` point in the coroutine. struct SuspensionPoint<'tcx> { From 140392b0418825c77ba68ab693dc18494ab27405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 20:00:04 +0000 Subject: [PATCH 125/189] Adjust rustdoc automatic link suggestion Use more accurate spans for multipart suggestion. --- src/librustdoc/passes/lint/bare_urls.rs | 36 +++---- tests/rustdoc-ui/diagnostic-width.stderr | 6 +- tests/rustdoc-ui/include-str-bare-urls.stderr | 6 +- tests/rustdoc-ui/lints/bare-urls.stderr | 102 +++++++++++++++--- .../lints/renamed-lint-still-applies.stderr | 6 +- 5 files changed, 117 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 8f68f6ff4764a..a148f046f94b7 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -19,22 +19,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { }; let dox = item.doc_value(); if !dox.is_empty() { - let report_diag = - |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range| { - let sp = - source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings) - .unwrap_or_else(|| item.attr_span(cx.tcx)); - cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| { - lint.primary_message(msg) - .note("bare URLs are not automatically turned into clickable links") - .span_suggestion( - sp, - "use an automatic link instead", - format!("<{url}>"), - Applicability::MachineApplicable, - ); - }); - }; + let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range| { + let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings) + .unwrap_or_else(|| item.attr_span(cx.tcx)); + cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| { + lint.primary_message(msg) + .note("bare URLs are not automatically turned into clickable links") + .multipart_suggestion( + "use an automatic link instead", + vec![ + (sp.shrink_to_lo(), "<".to_string()), + (sp.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + }); + }; let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter(); @@ -74,17 +74,15 @@ fn find_raw_urls( cx: &DocContext<'_>, text: &str, range: Range, - f: &impl Fn(&DocContext<'_>, &'static str, &str, Range), + f: &impl Fn(&DocContext<'_>, &'static str, Range), ) { trace!("looking for raw urls in {text}"); // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). for match_ in URL_REGEX.find_iter(text) { - let url = match_.as_str(); let url_range = match_.range(); f( cx, "this URL is not a hyperlink", - url, Range { start: range.start + url_range.start, end: range.start + url_range.end }, ); } diff --git a/tests/rustdoc-ui/diagnostic-width.stderr b/tests/rustdoc-ui/diagnostic-width.stderr index c1cc4898ac584..d8c4934a576cf 100644 --- a/tests/rustdoc-ui/diagnostic-width.stderr +++ b/tests/rustdoc-ui/diagnostic-width.stderr @@ -2,7 +2,7 @@ error: this URL is not a hyperlink --> $DIR/diagnostic-width.rs:4:41 | LL | ... a http://link.com - | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links note: the lint level is defined here @@ -10,6 +10,10 @@ note: the lint level is defined here | LL | ...ny(rustdoc::bare_url... | ^^^^^^^^^^^^^^^^^^ +help: use an automatic link instead + | +LL | /// This is a long line that contains a + | + + error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/include-str-bare-urls.stderr b/tests/rustdoc-ui/include-str-bare-urls.stderr index a4234196b2310..53da2411874a5 100644 --- a/tests/rustdoc-ui/include-str-bare-urls.stderr +++ b/tests/rustdoc-ui/include-str-bare-urls.stderr @@ -2,7 +2,7 @@ error: this URL is not a hyperlink --> $DIR/auxiliary/include-str-bare-urls.md:1:11 | LL | HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE! - | ^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links note: the lint level is defined here @@ -10,6 +10,10 @@ note: the lint level is defined here | LL | #![deny(rustdoc::bare_urls)] | ^^^^^^^^^^^^^^^^^^ +help: use an automatic link instead + | +LL | HEADS UP! MUST SHOW UP IN THE STDERR FILE! + | + + error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr index ccf52cd0b933f..ddfc387eaf66e 100644 --- a/tests/rustdoc-ui/lints/bare-urls.stderr +++ b/tests/rustdoc-ui/lints/bare-urls.stderr @@ -2,7 +2,7 @@ error: this URL is not a hyperlink --> $DIR/bare-urls.rs:5:5 | LL | /// https://somewhere.com - | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links note: the lint level is defined here @@ -10,134 +10,202 @@ note: the lint level is defined here | LL | #![deny(rustdoc::bare_urls)] | ^^^^^^^^^^^^^^^^^^ +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:7:5 | LL | /// https://somewhere.com/a - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:9:5 | LL | /// https://www.somewhere.com - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:11:5 | LL | /// https://www.somewhere.com/a - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:13:5 | LL | /// https://subdomain.example.com - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:15:5 | LL | /// https://somewhere.com? - | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:17:5 | LL | /// https://somewhere.com/a? - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:19:5 | LL | /// https://somewhere.com?hello=12 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:21:5 | LL | /// https://somewhere.com/a?hello=12 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:23:5 | LL | /// https://example.com?hello=12#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:25:5 | LL | /// https://example.com/a?hello=12#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:27:5 | LL | /// https://example.com#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:29:5 | LL | /// https://example.com/a#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:31:5 | LL | /// https://somewhere.com?hello=12&bye=11 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:33:5 | LL | /// https://somewhere.com/a?hello=12&bye=11 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:35:5 | LL | /// https://somewhere.com?hello=12&bye=11#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + error: this URL is not a hyperlink --> $DIR/bare-urls.rs:37:10 | LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// hey! + | + + error: aborting due to 17 previous errors diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr index ee9b67cb91be6..88807dfb495d0 100644 --- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr +++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr @@ -29,7 +29,7 @@ error: this URL is not a hyperlink --> $DIR/renamed-lint-still-applies.rs:9:5 | LL | //! http://example.com - | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` + | ^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links note: the lint level is defined here @@ -37,6 +37,10 @@ note: the lint level is defined here | LL | #![deny(rustdoc::non_autolinks)] | ^^^^^^^^^^^^^^^^^^^^^^ +help: use an automatic link instead + | +LL | //! + | + + error: aborting due to 2 previous errors; 2 warnings emitted From 89ecae5d852a7346ee4e8240ae7a1130f1f6f458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 21:01:29 +0000 Subject: [PATCH 126/189] Better span for "make binding mutable" suggestion --- .../src/diagnostics/conflict_errors.rs | 25 +++++++-------- tests/ui/assign-imm-local-twice.rs | 2 +- tests/ui/assign-imm-local-twice.stderr | 8 +++-- tests/ui/async-await/issue-61452.stderr | 10 +++--- ...orrowck-match-binding-is-assignment.stderr | 20 ++++++------ tests/ui/borrowck/immutable-arg.stderr | 7 ++-- tests/ui/borrowck/issue-45199.rs | 6 ++-- tests/ui/borrowck/issue-45199.stderr | 26 +++++++++------ .../suggest-ref-mut-issue-118596.stderr | 8 ++--- tests/ui/borrowck/tainted-promoteds.stderr | 10 +++--- tests/ui/command-line-diagnostics.stderr | 10 +++--- ...3-both-anon-regions-one-is-struct-2.stderr | 7 ++-- .../liveness-assign-imm-local-notes.stderr | 32 ++++++++++++------- .../liveness-assign-imm-local-in-loop.rs | 2 +- .../liveness-assign-imm-local-in-loop.stderr | 8 +++-- .../liveness-assign-imm-local-in-op-eq.rs | 2 +- .../liveness-assign-imm-local-in-op-eq.stderr | 8 +++-- .../liveness-assign-imm-local-with-drop.rs | 2 +- ...liveness-assign-imm-local-with-drop.stderr | 10 +++--- .../liveness-assign-imm-local-with-init.rs | 2 +- ...liveness-assign-imm-local-with-init.stderr | 10 +++--- .../mut-pattern-internal-mutability.stderr | 4 +-- .../pat-at-same-name-both.stderr | 4 +-- .../borrowck-move-ref-pattern.stderr | 8 ++--- tests/ui/pattern/mut-ref-mut-2021.stderr | 4 +-- 25 files changed, 134 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7ef53fa2078e4..e291ebd9bb832 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3757,13 +3757,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { assigned_span: Span, err_place: Place<'tcx>, ) { - let (from_arg, local_decl, local_name) = match err_place.as_local() { - Some(local) => ( - self.body.local_kind(local) == LocalKind::Arg, - Some(&self.body.local_decls[local]), - self.local_names[local], - ), - None => (false, None, None), + let (from_arg, local_decl) = match err_place.as_local() { + Some(local) => { + (self.body.local_kind(local) == LocalKind::Arg, Some(&self.body.local_decls[local])) + } + None => (false, None), }; // If root local is initialized immediately (everything apart from let @@ -3795,13 +3793,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { err.span_label(assigned_span, format!("first assignment to {place_description}")); } if let Some(decl) = local_decl - && let Some(name) = local_name && decl.can_be_made_mutable() { - err.span_suggestion( - decl.source_info.span, + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), "consider making this binding mutable", - format!("mut {name}"), + "mut ".to_string(), Applicability::MachineApplicable, ); if !from_arg @@ -3813,10 +3810,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { })) ) { - err.span_suggestion( - decl.source_info.span, + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), "to modify the original value, take a borrow instead", - format!("ref mut {name}"), + "ref mut ".to_string(), Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/assign-imm-local-twice.rs b/tests/ui/assign-imm-local-twice.rs index b50f6ab5deb15..b2dfeb564d9f9 100644 --- a/tests/ui/assign-imm-local-twice.rs +++ b/tests/ui/assign-imm-local-twice.rs @@ -1,7 +1,7 @@ fn test() { let v: isize; //~^ HELP consider making this binding mutable - //~| SUGGESTION mut v + //~| SUGGESTION mut v = 1; //~ NOTE first assignment println!("v={}", v); v = 2; //~ ERROR cannot assign twice to immutable variable diff --git a/tests/ui/assign-imm-local-twice.stderr b/tests/ui/assign-imm-local-twice.stderr index d92485de68fe7..fda3aa3de1b4b 100644 --- a/tests/ui/assign-imm-local-twice.stderr +++ b/tests/ui/assign-imm-local-twice.stderr @@ -1,14 +1,16 @@ error[E0384]: cannot assign twice to immutable variable `v` --> $DIR/assign-imm-local-twice.rs:7:5 | -LL | let v: isize; - | - help: consider making this binding mutable: `mut v` -... LL | v = 1; | ----- first assignment to `v` LL | println!("v={}", v); LL | v = 2; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut v: isize; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/issue-61452.stderr b/tests/ui/async-await/issue-61452.stderr index 3f623ba8ad274..b7b1e380c9e54 100644 --- a/tests/ui/async-await/issue-61452.stderr +++ b/tests/ui/async-await/issue-61452.stderr @@ -13,12 +13,14 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/issue-61452.rs:9:5 | LL | pub async fn g(x: usize) { - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | pub async fn g(mut x: usize) { + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr index 98ffa7f6ffa75..e164ea44aa4b8 100644 --- a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr +++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr @@ -9,11 +9,11 @@ LL | x += 1; help: consider making this binding mutable | LL | mut x => { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | ref mut x => { - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:20:13 @@ -26,11 +26,11 @@ LL | x += 1; help: consider making this binding mutable | LL | E::Foo(mut x) => { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | E::Foo(ref mut x) => { - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:26:13 @@ -43,11 +43,11 @@ LL | x += 1; help: consider making this binding mutable | LL | S { bar: mut x } => { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | S { bar: ref mut x } => { - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:32:13 @@ -60,11 +60,11 @@ LL | x += 1; help: consider making this binding mutable | LL | (mut x,) => { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | (ref mut x,) => { - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 @@ -77,11 +77,11 @@ LL | x += 1; help: consider making this binding mutable | LL | [mut x,_,_] => { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | [ref mut x,_,_] => { - | ~~~~~~~~~ + | +++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/borrowck/immutable-arg.stderr b/tests/ui/borrowck/immutable-arg.stderr index 84a480f641071..fb75172532f54 100644 --- a/tests/ui/borrowck/immutable-arg.stderr +++ b/tests/ui/borrowck/immutable-arg.stderr @@ -1,10 +1,13 @@ error[E0384]: cannot assign to immutable argument `_x` --> $DIR/immutable-arg.rs:2:5 | -LL | fn foo(_x: u32) { - | -- help: consider making this binding mutable: `mut _x` LL | _x = 4; | ^^^^^^ cannot assign to immutable argument + | +help: consider making this binding mutable + | +LL | fn foo(mut _x: u32) { + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs index ded46e56e3451..b38967524fa6f 100644 --- a/tests/ui/borrowck/issue-45199.rs +++ b/tests/ui/borrowck/issue-45199.rs @@ -1,7 +1,7 @@ fn test_drop_replace() { let b: Box; //~^ HELP consider making this binding mutable - //~| SUGGESTION mut b + //~| SUGGESTION mut b = Box::new(1); //~ NOTE first assignment b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable @@ -10,13 +10,13 @@ fn test_drop_replace() { fn test_call() { let b = Box::new(1); //~ NOTE first assignment //~| HELP consider making this binding mutable - //~| SUGGESTION mut b + //~| SUGGESTION mut b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable } fn test_args(b: Box) { //~ HELP consider making this binding mutable - //~| SUGGESTION mut b + //~| SUGGESTION mut b = Box::new(2); //~ ERROR cannot assign to immutable argument `b` //~| NOTE cannot assign to immutable argument } diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr index 47aa30908270d..8886e618e18b6 100644 --- a/tests/ui/borrowck/issue-45199.stderr +++ b/tests/ui/borrowck/issue-45199.stderr @@ -1,34 +1,40 @@ error[E0384]: cannot assign twice to immutable variable `b` --> $DIR/issue-45199.rs:6:5 | -LL | let b: Box; - | - help: consider making this binding mutable: `mut b` -... LL | b = Box::new(1); | - first assignment to `b` LL | b = Box::new(2); | ^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut b: Box; + | +++ error[E0384]: cannot assign twice to immutable variable `b` --> $DIR/issue-45199.rs:14:5 | LL | let b = Box::new(1); - | - - | | - | first assignment to `b` - | help: consider making this binding mutable: `mut b` + | - first assignment to `b` ... LL | b = Box::new(2); | ^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut b = Box::new(1); + | +++ error[E0384]: cannot assign to immutable argument `b` --> $DIR/issue-45199.rs:20:5 | -LL | fn test_args(b: Box) { - | - help: consider making this binding mutable: `mut b` -LL | LL | b = Box::new(2); | ^ cannot assign to immutable argument + | +help: consider making this binding mutable + | +LL | fn test_args(mut b: Box) { + | +++ error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr index fd2a775a099cb..aec3d66316085 100644 --- a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr +++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr @@ -9,11 +9,11 @@ LL | x = 2; help: consider making this binding mutable | LL | if let Some(mut x) = y { - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | if let Some(ref mut x) = y { - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/suggest-ref-mut-issue-118596.rs:9:5 @@ -26,11 +26,11 @@ LL | x = 0; help: consider making this binding mutable | LL | let [mut x, ref xs_hold @ ..] = arr; - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | let [ref mut x, ref xs_hold @ ..] = arr; - | ~~~~~~~~~ + | +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/tainted-promoteds.stderr b/tests/ui/borrowck/tainted-promoteds.stderr index a5c448fdcdbef..04669a290979b 100644 --- a/tests/ui/borrowck/tainted-promoteds.stderr +++ b/tests/ui/borrowck/tainted-promoteds.stderr @@ -2,12 +2,14 @@ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/tainted-promoteds.rs:7:5 | LL | let a = 0; - | - - | | - | first assignment to `a` - | help: consider making this binding mutable: `mut a` + | - first assignment to `a` LL | a = &0 * &1 * &2 * &3; | ^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut a = 0; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/command-line-diagnostics.stderr b/tests/ui/command-line-diagnostics.stderr index b719a00ad5ddd..6d33fb4172f8d 100644 --- a/tests/ui/command-line-diagnostics.stderr +++ b/tests/ui/command-line-diagnostics.stderr @@ -2,12 +2,14 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/command-line-diagnostics.rs:6:5 | LL | let x = 42; - | - - | | - | first assignment to `x` - | help: consider making this binding mutable: `mut x` + | - first assignment to `x` LL | x = 43; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x = 42; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr index 0980de92d350e..29bf7e62985a3 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr @@ -16,10 +16,13 @@ LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) { error[E0384]: cannot assign to immutable argument `y` --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5 | -LL | fn foo(mut x: Ref, y: &u32) { - | - help: consider making this binding mutable: `mut y` LL | y = x.b; | ^^^^^^^ cannot assign to immutable argument + | +help: consider making this binding mutable + | +LL | fn foo(mut x: Ref, mut y: &u32) { + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr index b47a47d631e5f..3fbd863467dcb 100644 --- a/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr +++ b/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr @@ -1,45 +1,53 @@ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/liveness-assign-imm-local-notes.rs:10:9 | -LL | let x; - | - help: consider making this binding mutable: `mut x` -... LL | x = 2; | ----- first assignment to `x` LL | x = 3; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x; + | +++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/liveness-assign-imm-local-notes.rs:21:13 | -LL | let x; - | - help: consider making this binding mutable: `mut x` -... LL | x = 2; | ----- first assignment to `x` LL | x = 3; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x; + | +++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/liveness-assign-imm-local-notes.rs:30:13 | -LL | let x; - | - help: consider making this binding mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x; + | +++ error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/liveness-assign-imm-local-notes.rs:32:13 | -LL | let x; - | - help: consider making this binding mutable: `mut x` -... LL | x = 1; | ----- first assignment to `x` LL | } else { LL | x = 2; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut x; + | +++ error: aborting due to 4 previous errors diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs index 08911c5bde781..d2f32a47122c2 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs @@ -1,7 +1,7 @@ fn test() { let v: isize; //~^ HELP consider making this binding mutable - //~| SUGGESTION mut v + //~| SUGGESTION mut loop { v = 1; //~ ERROR cannot assign twice to immutable variable `v` //~| NOTE cannot assign twice to immutable variable diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr index f0174560fd58c..e8c0721b903c9 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr @@ -1,11 +1,13 @@ error[E0384]: cannot assign twice to immutable variable `v` --> $DIR/liveness-assign-imm-local-in-loop.rs:6:9 | -LL | let v: isize; - | - help: consider making this binding mutable: `mut v` -... LL | v = 1; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut v: isize; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs index 1752d969086e8..fd6b4bcdf84c0 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs @@ -1,7 +1,7 @@ fn test() { let v: isize; //~^ HELP consider making this binding mutable - //~| SUGGESTION mut v + //~| SUGGESTION mut v = 2; //~ NOTE first assignment v += 1; //~ ERROR cannot assign twice to immutable variable `v` //~| NOTE cannot assign twice to immutable diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr index 578a40e4070d0..b7373d7cf1d7e 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr @@ -1,13 +1,15 @@ error[E0384]: cannot assign twice to immutable variable `v` --> $DIR/liveness-assign-imm-local-in-op-eq.rs:6:5 | -LL | let v: isize; - | - help: consider making this binding mutable: `mut v` -... LL | v = 2; | ----- first assignment to `v` LL | v += 1; | ^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut v: isize; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs index c9b16e43910e8..b7050d69306d0 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs @@ -1,7 +1,7 @@ fn test() { let b = Box::new(1); //~ NOTE first assignment //~| HELP consider making this binding mutable - //~| SUGGESTION mut b + //~| SUGGESTION mut drop(b); b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr index 2f55b50f0baf4..35b47bd6d91a5 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr @@ -2,13 +2,15 @@ error[E0384]: cannot assign twice to immutable variable `b` --> $DIR/liveness-assign-imm-local-with-drop.rs:6:5 | LL | let b = Box::new(1); - | - - | | - | first assignment to `b` - | help: consider making this binding mutable: `mut b` + | - first assignment to `b` ... LL | b = Box::new(2); | ^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut b = Box::new(1); + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs index 4bb2db27a1652..67c97e38546dc 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs @@ -1,7 +1,7 @@ fn test() { let v: isize = 1; //~ NOTE first assignment //~| HELP consider making this binding mutable - //~| SUGGESTION mut v + //~| SUGGESTION mut v.clone(); v = 2; //~ ERROR cannot assign twice to immutable variable `v` //~| NOTE cannot assign twice to immutable diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr index 8eb71cd99bfc1..d1f9e1573e4b7 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr @@ -2,13 +2,15 @@ error[E0384]: cannot assign twice to immutable variable `v` --> $DIR/liveness-assign-imm-local-with-init.rs:6:5 | LL | let v: isize = 1; - | - - | | - | first assignment to `v` - | help: consider making this binding mutable: `mut v` + | - first assignment to `v` ... LL | v = 2; | ^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut v: isize = 1; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/mut/mut-pattern-internal-mutability.stderr b/tests/ui/mut/mut-pattern-internal-mutability.stderr index ab80af17a085f..f3a8aa0126caf 100644 --- a/tests/ui/mut/mut-pattern-internal-mutability.stderr +++ b/tests/ui/mut/mut-pattern-internal-mutability.stderr @@ -9,11 +9,11 @@ LL | x += 1; help: consider making this binding mutable | LL | let &mut mut x = foo; - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | let &mut ref mut x = foo; - | ~~~~~~~~~ + | +++++++ error[E0506]: cannot assign to `*foo` because it is borrowed --> $DIR/mut-pattern-internal-mutability.rs:13:5 diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr index 41d1b79d97d1c..ed71a39ff7eed 100644 --- a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr +++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -78,11 +78,11 @@ LL | | Err(a @ b @ a) help: consider making this binding mutable | LL | Ok(a @ b @ mut a) - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | Ok(a @ b @ ref mut a) - | ~~~~~~~~~ + | +++++++ error: aborting due to 12 previous errors diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index 1e7b990b67cf3..a1049701dc3b8 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -22,11 +22,11 @@ LL | _x1 = U; help: consider making this binding mutable | LL | let [ref _x0_hold, mut _x1, ref xs_hold @ ..] = arr; - | ~~~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | let [ref _x0_hold, ref mut _x1, ref xs_hold @ ..] = arr; - | ~~~~~~~~~~~ + | +++++++ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:11:10 @@ -86,11 +86,11 @@ LL | _x1 = U; help: consider making this binding mutable | LL | let (ref _x0, mut _x1, ref _x2, ..) = tup; - | ~~~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | let (ref _x0, ref mut _x1, ref _x2, ..) = tup; - | ~~~~~~~~~~~ + | +++++++ error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable --> $DIR/borrowck-move-ref-pattern.rs:24:20 diff --git a/tests/ui/pattern/mut-ref-mut-2021.stderr b/tests/ui/pattern/mut-ref-mut-2021.stderr index ebf7979edb6ea..228afed2026ee 100644 --- a/tests/ui/pattern/mut-ref-mut-2021.stderr +++ b/tests/ui/pattern/mut-ref-mut-2021.stderr @@ -9,11 +9,11 @@ LL | a = 42; help: consider making this binding mutable | LL | let Foo(mut a) = Foo(0); - | ~~~~~ + | +++ help: to modify the original value, take a borrow instead | LL | let Foo(ref mut a) = Foo(0); - | ~~~~~~~~~ + | +++++++ error[E0384]: cannot assign twice to immutable variable `a` --> $DIR/mut-ref-mut-2021.rs:15:5 From f63d2bc657f2158bc37c747bb0835a9d02b864d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 21:02:27 +0000 Subject: [PATCH 127/189] Better suggestion span for missing type parameter --- compiler/rustc_hir_analysis/src/errors.rs | 7 +++---- tests/ui/associated-types/issue-22560.stderr | 12 ++++++++++-- ...dy-to-be-a-closure-or-coroutine-ice-113776.stderr | 12 ++++++++++-- tests/ui/error-codes/E0393.stderr | 6 +++++- tests/ui/issues/issue-21950.stderr | 6 +++++- tests/ui/issues/issue-22370.stderr | 6 +++++- .../type-parameter-defaults-referencing-Self.stderr | 6 +++++- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 3ffb51fa9926a..c2d86efd517aa 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -453,12 +453,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { } else { // The user wrote `Iterator`, so we don't have a type we can suggest, but at // least we can clue them to the correct syntax `Iterator`. - err.span_suggestion( - self.span, + err.span_suggestion_verbose( + self.span.shrink_to_hi(), fluent::hir_analysis_suggestion, format!( - "{}<{}>", - snippet, + "<{}>", self.missing_type_params .iter() .map(|n| n.to_string()) diff --git a/tests/ui/associated-types/issue-22560.stderr b/tests/ui/associated-types/issue-22560.stderr index 46e6e3951a5bd..834040490f940 100644 --- a/tests/ui/associated-types/issue-22560.stderr +++ b/tests/ui/associated-types/issue-22560.stderr @@ -35,9 +35,13 @@ LL | trait Add { | ------------------- type parameter `Rhs` must be specified for this ... LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Add` + | ^^^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | type Test = dyn Add + Sub; + | +++++ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-22560.rs:9:23 @@ -46,9 +50,13 @@ LL | trait Sub { | ------------------- type parameter `Rhs` must be specified for this ... LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Sub` + | ^^^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | type Test = dyn Add + Sub; + | +++++ error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr index be79450a3ce31..416a938112424 100644 --- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr +++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr @@ -20,24 +20,32 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 | LL | ) -> impl Iterator { - | ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign` + | ^^^^^^^^^ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | = note: type parameter `Rhs` must be specified for this | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | ) -> impl Iterator> { + | +++++ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27 | LL | ) -> impl Iterator { - | ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign` + | ^^^^^^^^^ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | = note: type parameter `Rhs` must be specified for this | = note: because of the default `Self` reference, type parameters must be specified on object types = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: set the type parameter to the desired type + | +LL | ) -> impl Iterator> { + | +++++ error[E0277]: `()` is not an iterator --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:6 diff --git a/tests/ui/error-codes/E0393.stderr b/tests/ui/error-codes/E0393.stderr index 4083fa23e87aa..489398b7be59e 100644 --- a/tests/ui/error-codes/E0393.stderr +++ b/tests/ui/error-codes/E0393.stderr @@ -5,9 +5,13 @@ LL | trait A {} | --------------- type parameter `T` must be specified for this LL | LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} - | ^ help: set the type parameter to the desired type: `A` + | ^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-21950.stderr b/tests/ui/issues/issue-21950.stderr index e498565d4e653..584370c717827 100644 --- a/tests/ui/issues/issue-21950.stderr +++ b/tests/ui/issues/issue-21950.stderr @@ -14,9 +14,13 @@ LL | trait Add { | ------------------- type parameter `Rhs` must be specified for this ... LL | let x = &10 as &dyn Add; - | ^^^ help: set the type parameter to the desired type: `Add` + | ^^^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | let x = &10 as &dyn Add; + | +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-22370.stderr b/tests/ui/issues/issue-22370.stderr index 977cfe06bb8b9..3dc060963f920 100644 --- a/tests/ui/issues/issue-22370.stderr +++ b/tests/ui/issues/issue-22370.stderr @@ -5,9 +5,13 @@ LL | trait A {} | --------------- type parameter `T` must be specified for this LL | LL | fn f(a: &dyn A) {} - | ^ help: set the type parameter to the desired type: `A` + | ^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | fn f(a: &dyn A) {} + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr index 16d08b2672267..c81405f03f8fa 100644 --- a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr +++ b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr @@ -5,9 +5,13 @@ LL | trait Foo { | ----------------- type parameter `T` must be specified for this ... LL | fn foo(x: &dyn Foo) { } - | ^^^ help: set the type parameter to the desired type: `Foo` + | ^^^ | = note: because of the default `Self` reference, type parameters must be specified on object types +help: set the type parameter to the desired type + | +LL | fn foo(x: &dyn Foo) { } + | +++ error: aborting due to 1 previous error From 9344779f718e847283a1ada901bad1222bd5d55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 21:02:55 +0000 Subject: [PATCH 128/189] Fix `&mut` removal suggestion --- .../src/diagnostics/mutability_errors.rs | 4 ++-- tests/ui/borrowck/issue-33819.stderr | 11 +++++++---- tests/ui/did_you_mean/issue-34337.stderr | 11 +++++++---- tests/ui/did_you_mean/issue-37139.stderr | 11 +++++++---- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 19a4df0cd7b43..4174c75b2846f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -449,8 +449,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { .is_ok_and(|snippet| snippet.starts_with("&mut ")) => { err.span_label(span, format!("cannot {act}")); - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(5)), "try removing `&mut` here", "", Applicability::MaybeIncorrect, diff --git a/tests/ui/borrowck/issue-33819.stderr b/tests/ui/borrowck/issue-33819.stderr index 41c9d6aac760b..e5f6df26bc190 100644 --- a/tests/ui/borrowck/issue-33819.stderr +++ b/tests/ui/borrowck/issue-33819.stderr @@ -2,10 +2,13 @@ error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/issue-33819.rs:4:34 | LL | Some(ref v) => { let a = &mut v; }, - | ^^^^^^ - | | - | cannot borrow as mutable - | help: try removing `&mut` here + | ^^^^^^ cannot borrow as mutable + | +help: try removing `&mut` here + | +LL - Some(ref v) => { let a = &mut v; }, +LL + Some(ref v) => { let a = v; }, + | error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-34337.stderr b/tests/ui/did_you_mean/issue-34337.stderr index c727a565dbe34..7bb651c47d049 100644 --- a/tests/ui/did_you_mean/issue-34337.stderr +++ b/tests/ui/did_you_mean/issue-34337.stderr @@ -2,10 +2,13 @@ error[E0596]: cannot borrow `key` as mutable, as it is not declared as mutable --> $DIR/issue-34337.rs:6:9 | LL | get(&mut key); - | ^^^^^^^^ - | | - | cannot borrow as mutable - | help: try removing `&mut` here + | ^^^^^^^^ cannot borrow as mutable + | +help: try removing `&mut` here + | +LL - get(&mut key); +LL + get(key); + | error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-37139.stderr b/tests/ui/did_you_mean/issue-37139.stderr index a07d83b31db1d..dbaab70d8bc23 100644 --- a/tests/ui/did_you_mean/issue-37139.stderr +++ b/tests/ui/did_you_mean/issue-37139.stderr @@ -2,10 +2,13 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/issue-37139.rs:12:18 | LL | test(&mut x); - | ^^^^^^ - | | - | cannot borrow as mutable - | help: try removing `&mut` here + | ^^^^^^ cannot borrow as mutable + | +help: try removing `&mut` here + | +LL - test(&mut x); +LL + test(x); + | error: aborting due to 1 previous error From 5c2946a4beb927d5c34519d5310b6507efb91724 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 4 Jul 2024 04:54:26 +0000 Subject: [PATCH 129/189] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 912aa11ded053..5a35166769e89 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7d97c59438e933e86f557ed999da3b8dfc6855a7 +66b4f0021bfb11a8c20d084c99a40f4a78ce1d38 From a06a18a47fc36b6c2c7c317c7611fe0a2960765b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 21:03:37 +0000 Subject: [PATCH 130/189] Properly handle removal suggestion rendering Do not leave a `+ ` line with only whitespace. In reality, the user will want to remove the entire line. --- compiler/rustc_errors/src/emitter.rs | 23 ++++++++++++++++--- .../tests/ui/dbg_macro/dbg_macro.stderr | 2 -- .../ui/dbg_macro/dbg_macro_unfixable.stderr | 1 - .../clippy/tests/ui/manual_split_once.stderr | 10 -------- .../ui/significant_drop_tightening.stderr | 2 -- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 45118bcc58abe..aa47ca166764b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2273,9 +2273,26 @@ impl HumanEmitter { &normalize_whitespace(last_line), Style::NoStyle, ); - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); - buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); - buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + if !line_to_add.trim().is_empty() { + // Check if after the removal, the line is left with only whitespace. If so, we + // will not show an "addition" line, as removing the whole line is what the user + // would really want. + // For example, for the following: + // | + // 2 - .await + // 2 + (note the left over whitepsace) + // | + // We really want + // | + // 2 - .await + // | + // *row_num -= 1; + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + } else { + *row_num -= 1; + } } else { *row_num -= 2; } diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr index 86667701da0f3..7d3c3f7c918e8 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr @@ -86,7 +86,6 @@ LL | dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool @@ -146,7 +145,6 @@ LL | expand_to_dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr index d21595c2fcd42..16e51f4742e34 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr @@ -9,7 +9,6 @@ LL | dbg!(); help: remove the invocation before committing it to a version control system | LL - dbg!(); -LL + | error: the `dbg!` macro is intended as a debugging tool diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr index b4e51f473cf4d..c5c9be3ac63df 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.stderr +++ b/src/tools/clippy/tests/ui/manual_split_once.stderr @@ -96,12 +96,10 @@ LL | let (l, r) = "a.b.c".split_once('.').unwrap(); help: remove the `iter` usages | LL - let l = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let r = iter.next().unwrap(); -LL + | error: manual implementation of `split_once` @@ -121,12 +119,10 @@ LL | let (l, r) = "a.b.c".split_once('.')?; help: remove the `iter` usages | LL - let l = iter.next()?; -LL + | help: remove the `iter` usages | LL - let r = iter.next()?; -LL + | error: manual implementation of `rsplit_once` @@ -146,12 +142,10 @@ LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap(); help: remove the `iter` usages | LL - let r = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let l = iter.next().unwrap(); -LL + | error: manual implementation of `rsplit_once` @@ -171,12 +165,10 @@ LL | let (l, r) = "a.b.c".rsplit_once('.')?; help: remove the `iter` usages | LL - let r = iter.next()?; -LL + | help: remove the `iter` usages | LL - let l = iter.next()?; -LL + | error: manual implementation of `split_once` @@ -202,12 +194,10 @@ LL | let (a, b) = "a.b.c".split_once('.').unwrap(); help: remove the `iter` usages | LL - let a = iter.next().unwrap(); -LL + | help: remove the `iter` usages | LL - let b = iter.next().unwrap(); -LL + | error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr index f818a14cbe68b..5fc66279f00e7 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr @@ -64,7 +64,6 @@ LL + let rslt0 = mutex.lock().unwrap().abs(); help: remove separated single usage | LL - let rslt0 = lock.abs(); -LL + | error: temporary with significant `Drop` can be early dropped @@ -88,7 +87,6 @@ LL + mutex.lock().unwrap().clear(); help: remove separated single usage | LL - lock.clear(); -LL + | error: aborting due to 4 previous errors From 57e76d45960770e45e20a76019c96643b7ef0845 Mon Sep 17 00:00:00 2001 From: tison Date: Wed, 3 Jul 2024 22:12:55 -0700 Subject: [PATCH 131/189] impl PathBuf::add_extension and Path::with_added_extension Signed-off-by: tison --- library/std/src/path.rs | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index caae8f924d2b1..a6f6042eaefaf 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1519,6 +1519,77 @@ impl PathBuf { true } + /// Append [`self.extension`] with `extension`. + /// + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. + /// + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is appended. + /// + /// # Caveats + /// + /// The appended `extension` may contain dots and will be used in its entirety, + /// but only the part after the final dot will be reflected in + /// [`self.extension`]. + /// + /// See the examples below. + /// + /// [`self.file_name`]: Path::file_name + /// [`self.extension`]: Path::extension + /// + /// # Examples + /// + /// ``` + /// #![feature(path_add_extension)] + /// + /// use std::path::{Path, PathBuf}; + /// + /// let mut p = PathBuf::from("/feel/the"); + /// + /// p.add_extension("formatted"); + /// assert_eq!(Path::new("/feel/the.formatted"), p.as_path()); + /// + /// p.add_extension("dark.side"); + /// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path()); + /// + /// p.set_extension("cookie"); + /// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path()); + /// + /// p.set_extension(""); + /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); + /// + /// p.add_extension(""); + /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); + /// ``` + #[unstable(feature = "path_add_extension", issue = "127292")] + pub fn add_extension>(&mut self, extension: S) -> bool { + self._add_extension(extension.as_ref()) + } + + fn _add_extension(&mut self, extension: &OsStr) -> bool { + let file_name = match self.file_name() { + None => return false, + Some(f) => f.as_encoded_bytes(), + }; + + let new = extension; + if !new.is_empty() { + // truncate until right after the file name + // this is necessary for trimming the trailing slash + let end_file_name = file_name[file_name.len()..].as_ptr().addr(); + let start = self.inner.as_encoded_bytes().as_ptr().addr(); + self.inner.truncate(end_file_name.wrapping_sub(start)); + + // append the new extension + self.inner.reserve_exact(new.len() + 1); + self.inner.push(OsStr::new(".")); + self.inner.push(new); + } + + true + } + /// Yields a mutable reference to the underlying [`OsString`] instance. /// /// # Examples @@ -2656,6 +2727,32 @@ impl Path { new_path } + /// Creates an owned [`PathBuf`] like `self` but with an extra extension. + /// + /// See [`PathBuf::add_extension`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_add_extension)] + /// + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("foo.rs"); + /// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt")); + /// + /// let path = Path::new("foo.tar.gz"); + /// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz")); + /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); + /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt")); + /// ``` + #[unstable(feature = "path_add_extension", issue = "127292")] + pub fn with_added_extension>(&self, extension: S) -> PathBuf { + let mut new_path = self.to_path_buf(); + new_path.add_extension(extension); + new_path + } + /// Produces an iterator over the [`Component`]s of the path. /// /// When parsing the path, there is a small amount of normalization: From 2699d8108cee47a86de22d8ac29344bcadfdbd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 23:23:38 +0000 Subject: [PATCH 132/189] Use shorter span for float literal suggestion --- .../infer/error_reporting/note_and_explain.rs | 6 +- tests/ui/consts/issue-39974.stderr | 10 ++- ...xpected-float-found-integer-literal.stderr | 33 +++++--- ...loat-literal-inference-restrictions.stderr | 11 ++- ...structure-constructor-type-mismatch.stderr | 80 +++++++++++-------- .../ui/try-block/try-block-type-error.stderr | 10 ++- 6 files changed, 91 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index bc59b5e033baa..fd50d1eb438aa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -52,10 +52,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) = tcx.sess.source_map().span_to_snippet(sp) => { if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - diag.span_suggestion( - sp, + diag.span_suggestion_verbose( + sp.shrink_to_hi(), "use a float literal", - format!("{snippet}.0"), + ".0", MachineApplicable, ); } diff --git a/tests/ui/consts/issue-39974.stderr b/tests/ui/consts/issue-39974.stderr index 114c4cfeaf7c0..a371ea5709e1b 100644 --- a/tests/ui/consts/issue-39974.stderr +++ b/tests/ui/consts/issue-39974.stderr @@ -2,10 +2,12 @@ error[E0308]: mismatched types --> $DIR/issue-39974.rs:1:21 | LL | const LENGTH: f64 = 2; - | ^ - | | - | expected `f64`, found integer - | help: use a float literal: `2.0` + | ^ expected `f64`, found integer + | +help: use a float literal + | +LL | const LENGTH: f64 = 2.0; + | ++ error[E0308]: mismatched types --> $DIR/issue-39974.rs:5:19 diff --git a/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr b/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr index 6f853ccab378a..6e32483aee49b 100644 --- a/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr +++ b/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr @@ -2,31 +2,40 @@ error[E0308]: mismatched types --> $DIR/issue-53280-expected-float-found-integer-literal.rs:2:24 | LL | let sixteen: f32 = 16; - | --- ^^ - | | | - | | expected `f32`, found integer - | | help: use a float literal: `16.0` + | --- ^^ expected `f32`, found integer + | | | expected due to this + | +help: use a float literal + | +LL | let sixteen: f32 = 16.0; + | ++ error[E0308]: mismatched types --> $DIR/issue-53280-expected-float-found-integer-literal.rs:5:38 | LL | let a_million_and_seventy: f64 = 1_000_070; - | --- ^^^^^^^^^ - | | | - | | expected `f64`, found integer - | | help: use a float literal: `1_000_070.0` + | --- ^^^^^^^^^ expected `f64`, found integer + | | | expected due to this + | +help: use a float literal + | +LL | let a_million_and_seventy: f64 = 1_000_070.0; + | ++ error[E0308]: mismatched types --> $DIR/issue-53280-expected-float-found-integer-literal.rs:8:30 | LL | let negative_nine: f32 = -9; - | --- ^^ - | | | - | | expected `f32`, found integer - | | help: use a float literal: `-9.0` + | --- ^^ expected `f32`, found integer + | | | expected due to this + | +help: use a float literal + | +LL | let negative_nine: f32 = -9.0; + | ++ error[E0308]: mismatched types --> $DIR/issue-53280-expected-float-found-integer-literal.rs:15:30 diff --git a/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr b/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr index 454373c322e9b..6b3e0cb505fe8 100644 --- a/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr +++ b/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr @@ -2,11 +2,14 @@ error[E0308]: mismatched types --> $DIR/float-literal-inference-restrictions.rs:2:18 | LL | let x: f32 = 1; - | --- ^ - | | | - | | expected `f32`, found integer - | | help: use a float literal: `1.0` + | --- ^ expected `f32`, found integer + | | | expected due to this + | +help: use a float literal + | +LL | let x: f32 = 1.0; + | ++ error[E0308]: mismatched types --> $DIR/float-literal-inference-restrictions.rs:3:18 diff --git a/tests/ui/structs/structure-constructor-type-mismatch.stderr b/tests/ui/structs/structure-constructor-type-mismatch.stderr index 63dda459396b8..cb9574873473f 100644 --- a/tests/ui/structs/structure-constructor-type-mismatch.stderr +++ b/tests/ui/structs/structure-constructor-type-mismatch.stderr @@ -2,55 +2,67 @@ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:17:12 | LL | x: 1, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `1.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | x: 1.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:20:12 | LL | y: 2, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `2.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | y: 2.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:26:12 | LL | x: 3, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `3.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | x: 3.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:29:12 | LL | y: 4, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `4.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | y: 4.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:35:12 | LL | x: 5, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `5.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | x: 5.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:42:12 | LL | x: 7, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `7.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | x: 7.0, + | ++ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied --> $DIR/structure-constructor-type-mismatch.rs:48:15 @@ -70,19 +82,23 @@ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:49:12 | LL | x: 9, - | ^ - | | - | expected `f32`, found integer - | help: use a float literal: `9.0` + | ^ expected `f32`, found integer + | +help: use a float literal + | +LL | x: 9.0, + | ++ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:50:12 | LL | y: 10, - | ^^ - | | - | expected `f32`, found integer - | help: use a float literal: `10.0` + | ^^ expected `f32`, found integer + | +help: use a float literal + | +LL | y: 10.0, + | ++ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied --> $DIR/structure-constructor-type-mismatch.rs:54:9 diff --git a/tests/ui/try-block/try-block-type-error.stderr b/tests/ui/try-block/try-block-type-error.stderr index 3e9a584a5510a..2cdb5fdee79a1 100644 --- a/tests/ui/try-block/try-block-type-error.stderr +++ b/tests/ui/try-block/try-block-type-error.stderr @@ -2,10 +2,12 @@ error[E0271]: type mismatch resolving ` as Try>::Output == {integer} --> $DIR/try-block-type-error.rs:10:9 | LL | 42 - | ^^ - | | - | expected `f32`, found integer - | help: use a float literal: `42.0` + | ^^ expected `f32`, found integer + | +help: use a float literal + | +LL | 42.0 + | ++ error[E0271]: type mismatch resolving ` as Try>::Output == ()` --> $DIR/try-block-type-error.rs:16:5 From ff92ab09033d2b08689e8a1fafe607d51b01d8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jul 2024 23:26:10 +0000 Subject: [PATCH 133/189] More accurate mutability suggestion --- .../src/diagnostics/mutability_errors.rs | 25 ++++---- .../borrow-raw-address-of-mutability.stderr | 8 ++- .../borrowck/borrowck-closures-unique.stderr | 7 +- tests/ui/borrowck/issue-111554.stderr | 7 +- ...5492-borrowck-migrate-scans-parents.stderr | 48 ++++++++------ tests/ui/borrowck/mutability-errors.stderr | 64 ++++++++++++------- .../cannot-mutate-captured-non-mut-var.stderr | 14 ++-- .../array_subslice.stderr | 8 ++- .../diagnostics/cant-mutate-imm.stderr | 16 +++-- .../closure-immutable-outer-variable.stderr | 7 +- tests/ui/fn/suggest-return-closure.stderr | 8 ++- tests/ui/nll/closure-captures.stderr | 48 ++++++++------ .../ui/nll/coroutine-upvar-mutability.stderr | 8 ++- tests/ui/nll/issue-46023.stderr | 8 ++- .../patkind-ref-binding-issue-114896.stderr | 7 +- .../patkind-ref-binding-issue-122415.stderr | 7 +- .../unboxed-closure-immutable-capture.stderr | 63 +++++++++++------- ...es-infer-fnmut-calling-fnmut-no-mut.stderr | 7 +- .../unboxed-closures-mutate-upvar.stderr | 24 ++++--- 19 files changed, 244 insertions(+), 140 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 4174c75b2846f..677029f9d3f95 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -408,10 +408,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { fn_decl.implicit_self, hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut ) { - err.span_suggestion( - upvar_ident.span, + err.span_suggestion_verbose( + upvar_ident.span.shrink_to_lo(), "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), + "mut ", Applicability::MachineApplicable, ); break; @@ -419,10 +419,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } } else { - err.span_suggestion( - upvar_ident.span, + err.span_suggestion_verbose( + upvar_ident.span.shrink_to_lo(), "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), + "mut ", Applicability::MachineApplicable, ); } @@ -755,13 +755,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. }) = node - && let Ok(name) = - self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { - err.span_suggestion( - pat_span, + err.multipart_suggestion( "consider changing this to be mutable", - format!("&(mut {name})"), + vec![ + (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()), + ( + local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()), + ")".to_string(), + ), + ], Applicability::MachineApplicable, ); return; diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr index a774820918712..4b5b368287e16 100644 --- a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr +++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -12,11 +12,13 @@ LL | let mut x = 0; error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrow-raw-address-of-mutability.rs:11:17 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -LL | let mut f = || { LL | let y = &raw mut x; | ^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable --> $DIR/borrow-raw-address-of-mutability.rs:21:5 diff --git a/tests/ui/borrowck/borrowck-closures-unique.stderr b/tests/ui/borrowck/borrowck-closures-unique.stderr index 23d3cc0e76ff7..613df9f2100c9 100644 --- a/tests/ui/borrowck/borrowck-closures-unique.stderr +++ b/tests/ui/borrowck/borrowck-closures-unique.stderr @@ -43,10 +43,13 @@ LL | c1; error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/borrowck-closures-unique.rs:43:38 | -LL | fn e(x: &'static mut isize) { - | - help: consider changing this to be mutable: `mut x` LL | let c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn e(mut x: &'static mut isize) { + | +++ error: aborting due to 4 previous errors diff --git a/tests/ui/borrowck/issue-111554.stderr b/tests/ui/borrowck/issue-111554.stderr index 6b7a42e495999..b3e8caae34304 100644 --- a/tests/ui/borrowck/issue-111554.stderr +++ b/tests/ui/borrowck/issue-111554.stderr @@ -19,10 +19,13 @@ LL | || bar(&mut self); error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-111554.rs:21:16 | -LL | pub fn quux(self) { - | ---- help: consider changing this to be mutable: `mut self` LL | || bar(&mut self); | ^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | pub fn quux(mut self) { + | +++ error: aborting due to 4 previous errors diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index 098a2964e9fc7..ff5ec1db34634 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -44,56 +44,68 @@ LL | borrowck_closures_unique::e(addr_of_mut!(X)); error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 | -LL | pub fn e(x: &'static mut isize) { - | - help: consider changing this to be mutable: `mut x` -LL | static mut Y: isize = 3; LL | let mut c1 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | pub fn e(mut x: &'static mut isize) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50 | -LL | pub fn ee(x: &'static mut isize) { - | - help: consider changing this to be mutable: `mut x` -... LL | let mut c2 = |y: &'static mut isize| x = y; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | pub fn ee(mut x: &'static mut isize) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13 | -LL | pub fn capture_assign_whole(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { LL | x = (1,); | ^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | pub fn capture_assign_whole(mut x: (i32,)) { + | +++ error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13 | -LL | pub fn capture_assign_part(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { LL | x.0 = 1; | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | pub fn capture_assign_part(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13 | -LL | pub fn capture_reborrow_whole(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { LL | &mut x; | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | pub fn capture_reborrow_whole(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13 | -LL | pub fn capture_reborrow_part(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { LL | &mut x.0; | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | pub fn capture_reborrow_part(mut x: (i32,)) { + | +++ error: aborting due to 6 previous errors; 3 warnings emitted diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr index b39e57d70ec65..3cab3ccb993c9 100644 --- a/tests/ui/borrowck/mutability-errors.stderr +++ b/tests/ui/borrowck/mutability-errors.stderr @@ -262,74 +262,90 @@ LL | fn imm_local(mut x: (i32,)) { error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/mutability-errors.rs:60:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -LL | || { LL | x = (1,); | ^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable --> $DIR/mutability-errors.rs:61:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | x.0 = 1; | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/mutability-errors.rs:62:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | &mut x; | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable --> $DIR/mutability-errors.rs:63:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | &mut x.0; | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/mutability-errors.rs:66:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = (1,); | ^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable --> $DIR/mutability-errors.rs:67:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | x.0 = 1; | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/mutability-errors.rs:68:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | &mut x; | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable --> $DIR/mutability-errors.rs:69:9 | -LL | fn imm_capture(x: (i32,)) { - | - help: consider changing this to be mutable: `mut x` -... LL | &mut x.0; | ^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn imm_capture(mut x: (i32,)) { + | +++ error[E0594]: cannot assign to immutable static item `X` --> $DIR/mutability-errors.rs:76:5 diff --git a/tests/ui/cannot-mutate-captured-non-mut-var.stderr b/tests/ui/cannot-mutate-captured-non-mut-var.stderr index 2d6e83c9e82f9..8d794f8251f14 100644 --- a/tests/ui/cannot-mutate-captured-non-mut-var.stderr +++ b/tests/ui/cannot-mutate-captured-non-mut-var.stderr @@ -1,18 +1,24 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/cannot-mutate-captured-non-mut-var.rs:9:25 | -LL | let x = 1; - | - help: consider changing this to be mutable: `mut x` LL | to_fn_once(move|| { x = 2; }); | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 1; + | +++ error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25 | -LL | let s = std::io::stdin(); - | - help: consider changing this to be mutable: `mut s` LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut s = std::io::stdin(); + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/closures/2229_closure_analysis/array_subslice.stderr b/tests/ui/closures/2229_closure_analysis/array_subslice.stderr index 888c60d5e91fb..ee941caa77373 100644 --- a/tests/ui/closures/2229_closure_analysis/array_subslice.stderr +++ b/tests/ui/closures/2229_closure_analysis/array_subslice.stderr @@ -1,11 +1,13 @@ error[E0596]: cannot borrow `x[..]` as mutable, as `x` is not declared as mutable --> $DIR/array_subslice.rs:7:21 | -LL | pub fn subslice_array(x: [u8; 3]) { - | - help: consider changing this to be mutable: `mut x` -... LL | let [ref y, ref mut z @ ..] = x; | ^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | pub fn subslice_array(mut x: [u8; 3]) { + | +++ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable --> $DIR/array_subslice.rs:10:5 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr index 98414fa8a3d5f..6f5043ef08de1 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr @@ -1,20 +1,24 @@ error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:12:9 | -LL | let z = (y, 10); - | - help: consider changing this to be mutable: `mut z` -... LL | z.0.0.0 = 20; | ^^^^^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut z = (y, 10); + | +++ error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:24:9 | -LL | let bx = Box::new(x); - | -- help: consider changing this to be mutable: `mut bx` -... LL | bx.0 = 20; | ^^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut bx = Box::new(x); + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/closures/closure-immutable-outer-variable.stderr b/tests/ui/closures/closure-immutable-outer-variable.stderr index 23bd0020db6b3..c4b0e5449579d 100644 --- a/tests/ui/closures/closure-immutable-outer-variable.stderr +++ b/tests/ui/closures/closure-immutable-outer-variable.stderr @@ -1,10 +1,13 @@ error[E0594]: cannot assign to `y`, as it is not declared as mutable --> $DIR/closure-immutable-outer-variable.rs:11:26 | -LL | let y = true; - | - help: consider changing this to be mutable: `mut y` LL | foo(Box::new(move || y = !y) as Box<_>); | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut y = true; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index d276ce8be2ba5..45c12b548e678 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -34,11 +34,13 @@ LL | fn fun() -> _ { error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/suggest-return-closure.rs:23:9 | -LL | let x = String::new(); - | - help: consider changing this to be mutable: `mut x` -... LL | x.push(c); | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = String::new(); + | +++ error[E0597]: `x` does not live long enough --> $DIR/suggest-return-closure.rs:23:9 diff --git a/tests/ui/nll/closure-captures.stderr b/tests/ui/nll/closure-captures.stderr index 5233f0b246261..828974c517e60 100644 --- a/tests/ui/nll/closure-captures.stderr +++ b/tests/ui/nll/closure-captures.stderr @@ -1,38 +1,46 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:7:5 | -LL | fn one_closure(x: i32) { - | - help: consider changing this to be mutable: `mut x` -LL | || LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn one_closure(mut x: i32) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:9:5 | -LL | fn one_closure(x: i32) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn one_closure(mut x: i32) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:15:9 | -LL | fn two_closures(x: i32) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn two_closures(mut x: i32) { + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:19:9 | -LL | fn two_closures(x: i32) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn two_closures(mut x: i32) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:27:9 @@ -67,11 +75,13 @@ LL | x = 1;}); error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:39:10 | -LL | fn two_closures_ref(x: i32) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1;} | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn two_closures_ref(mut x: i32) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:38:9 @@ -91,11 +101,13 @@ LL | x = 1;} error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:43:5 | -LL | fn two_closures_ref(x: i32) { - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1;}); | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn two_closures_ref(mut x: i32) { + | +++ error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:42:9 diff --git a/tests/ui/nll/coroutine-upvar-mutability.stderr b/tests/ui/nll/coroutine-upvar-mutability.stderr index 8b9be877c8f39..02c011301761c 100644 --- a/tests/ui/nll/coroutine-upvar-mutability.stderr +++ b/tests/ui/nll/coroutine-upvar-mutability.stderr @@ -1,11 +1,13 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/coroutine-upvar-mutability.rs:10:9 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-46023.stderr b/tests/ui/nll/issue-46023.stderr index 062e07407ce09..d071c29271c58 100644 --- a/tests/ui/nll/issue-46023.stderr +++ b/tests/ui/nll/issue-46023.stderr @@ -1,11 +1,13 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-46023.rs:5:9 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr index 68538255eddf0..e9c2fccaba284 100644 --- a/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr @@ -1,10 +1,13 @@ error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable --> $DIR/patkind-ref-binding-issue-114896.rs:7:9 | -LL | let &b = a; - | -- help: consider changing this to be mutable: `&(mut b)` LL | b.make_ascii_uppercase(); | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let &(mut b) = a; + | ~~~~~ + error: aborting due to 1 previous error diff --git a/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr index 39283133ac7c8..e93b8bbacccdd 100644 --- a/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr +++ b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr @@ -1,10 +1,13 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/patkind-ref-binding-issue-122415.rs:7:12 | -LL | fn foo(&x: &i32) { - | -- help: consider changing this to be mutable: `&(mut x)` LL | mutate(&mut x); | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn foo(&(mut x): &i32) { + | ~~~~~ + error: aborting due to 1 previous error diff --git a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr index ad5451ced55d0..04f9ab246b315 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr @@ -1,73 +1,90 @@ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:9:13 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` LL | move || x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:10:17 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -LL | move || x = 1; LL | move || set(&mut x); | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:11:13 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | move || x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:12:17 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | move || set(&mut x); | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:13:8 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | || x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:14:12 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | || set(&mut x); | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:15:8 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | || x = 1; | ^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/unboxed-closure-immutable-capture.rs:16:12 | -LL | let x = 0; - | - help: consider changing this to be mutable: `mut x` -... LL | || set(&mut x); | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ error: aborting due to 8 previous errors diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr index 5c93ed6d7f70f..07c66276eaf05 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr @@ -1,13 +1,16 @@ error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:16:9 | -LL | let tick1 = || { - | ----- help: consider changing this to be mutable: `mut tick1` LL | counter += 1; | ------- calling `tick1` requires mutable binding due to mutable borrow of `counter` ... LL | tick1(); | ^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut tick1 = || { + | +++ error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5 diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr index 26f97b51913df..80caddb2a11e1 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -1,29 +1,35 @@ error[E0594]: cannot assign to `n`, as it is not declared as mutable --> $DIR/unboxed-closures-mutate-upvar.rs:15:9 | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -LL | let mut f = to_fn_mut(|| { LL | n += 1; | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut n = 0; + | +++ error[E0594]: cannot assign to `n`, as it is not declared as mutable --> $DIR/unboxed-closures-mutate-upvar.rs:32:9 | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -... LL | n += 1; | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut n = 0; + | +++ error[E0594]: cannot assign to `n`, as it is not declared as mutable --> $DIR/unboxed-closures-mutate-upvar.rs:46:9 | -LL | let n = 0; - | - help: consider changing this to be mutable: `mut n` -LL | let mut f = to_fn(move || { LL | n += 1; | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut n = 0; + | +++ error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 From 8ea1066fe6605d85969d403080b2c5d93376797e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Jul 2024 00:22:26 +0000 Subject: [PATCH 134/189] Tweak slice and as_deref suggestion span Use multispan suggestion. --- compiler/rustc_hir_typeck/src/pat.rs | 13 +++--- .../ui/let-else/let-else-slicing-error.stderr | 9 ++-- tests/ui/suggestions/match-ergonomics.stderr | 14 ++++-- tests/ui/suggestions/pattern-slice-vec.stderr | 44 ++++++++++++------- ...press-consider-slicing-issue-120605.stderr | 9 ++-- tests/ui/typeck/issue-53712.rs | 2 +- tests/ui/typeck/issue-91328.stderr | 32 +++++++++----- 7 files changed, 78 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f932a27e9a287..478bbc0ed9855 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2499,7 +2499,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) && let Some(span) = ti.span && let Some(_) = ti.origin_expr - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let resolved_ty = self.resolve_vars_if_possible(ti.expected); let (is_slice_or_array_or_vector, resolved_ty) = @@ -2510,10 +2509,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) => { // Slicing won't work here, but `.as_deref()` might (issue #91328). - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.shrink_to_hi(), "consider using `as_deref` here", - format!("{snippet}.as_deref()"), + ".as_deref()", Applicability::MaybeIncorrect, ); } @@ -2522,10 +2521,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_top_level = current_depth <= 1; if is_slice_or_array_or_vector && is_top_level { - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.shrink_to_hi(), "consider slicing here", - format!("{snippet}[..]"), + "[..]", Applicability::MachineApplicable, ); } diff --git a/tests/ui/let-else/let-else-slicing-error.stderr b/tests/ui/let-else/let-else-slicing-error.stderr index 73c357dd5d462..4daae861965cd 100644 --- a/tests/ui/let-else/let-else-slicing-error.stderr +++ b/tests/ui/let-else/let-else-slicing-error.stderr @@ -2,9 +2,12 @@ error[E0529]: expected an array or slice, found `Vec<{integer}>` --> $DIR/let-else-slicing-error.rs:6:9 | LL | let [x, y] = nums else { - | ^^^^^^ ---- help: consider slicing here: `nums[..]` - | | - | pattern cannot match with input type `Vec<{integer}>` + | ^^^^^^ pattern cannot match with input type `Vec<{integer}>` + | +help: consider slicing here + | +LL | let [x, y] = nums[..] else { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/match-ergonomics.stderr b/tests/ui/suggestions/match-ergonomics.stderr index a3e059e8ac646..2cd43c26ca378 100644 --- a/tests/ui/suggestions/match-ergonomics.stderr +++ b/tests/ui/suggestions/match-ergonomics.stderr @@ -17,18 +17,24 @@ LL + [v] => {}, error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:8:9 | -LL | match x { - | - help: consider slicing here: `x[..]` LL | [&v] => {}, | ^^^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | match x[..] { + | ++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:20:9 | -LL | match x { - | - help: consider slicing here: `x[..]` LL | [v] => {}, | ^^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | match x[..] { + | ++++ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 diff --git a/tests/ui/suggestions/pattern-slice-vec.stderr b/tests/ui/suggestions/pattern-slice-vec.stderr index f69e7de971a96..36a9df3f7505e 100644 --- a/tests/ui/suggestions/pattern-slice-vec.stderr +++ b/tests/ui/suggestions/pattern-slice-vec.stderr @@ -2,42 +2,56 @@ error[E0529]: expected an array or slice, found `Vec` --> $DIR/pattern-slice-vec.rs:8:12 | LL | if let [_, _, _] = foo() {} - | ^^^^^^^^^ ----- help: consider slicing here: `foo()[..]` - | | - | pattern cannot match with input type `Vec` + | ^^^^^^^^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | if let [_, _, _] = foo()[..] {} + | ++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/pattern-slice-vec.rs:12:12 | LL | if let [] = &foo() {} - | ^^ ------ help: consider slicing here: `&foo()[..]` - | | - | pattern cannot match with input type `Vec` + | ^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | if let [] = &foo()[..] {} + | ++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/pattern-slice-vec.rs:16:12 | LL | if let [] = foo() {} - | ^^ ----- help: consider slicing here: `foo()[..]` - | | - | pattern cannot match with input type `Vec` + | ^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | if let [] = foo()[..] {} + | ++++ error[E0529]: expected an array or slice, found `Vec<_>` --> $DIR/pattern-slice-vec.rs:23:9 | -LL | match &v { - | -- help: consider slicing here: `&v[..]` -LL | LL | [5] => {} | ^^^ pattern cannot match with input type `Vec<_>` + | +help: consider slicing here + | +LL | match &v[..] { + | ++++ error[E0529]: expected an array or slice, found `Vec<{integer}>` --> $DIR/pattern-slice-vec.rs:28:9 | LL | let [..] = vec![1, 2, 3]; - | ^^^^ ------------- help: consider slicing here: `vec![1, 2, 3][..]` - | | - | pattern cannot match with input type `Vec<{integer}>` + | ^^^^ pattern cannot match with input type `Vec<{integer}>` + | +help: consider slicing here + | +LL | let [..] = vec![1, 2, 3][..]; + | ++++ error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr index c28d67604da9f..cab9bbb72df3b 100644 --- a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr +++ b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr @@ -2,9 +2,12 @@ error[E0529]: expected an array or slice, found `Vec` --> $DIR/suppress-consider-slicing-issue-120605.rs:7:16 | LL | if let [Struct { a: [] }] = &self.a { - | ^^^^^^^^^^^^^^^^^^ ------- help: consider slicing here: `&self.a[..]` - | | - | pattern cannot match with input type `Vec` + | ^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | if let [Struct { a: [] }] = &self.a[..] { + | ++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/suppress-consider-slicing-issue-120605.rs:7:29 diff --git a/tests/ui/typeck/issue-53712.rs b/tests/ui/typeck/issue-53712.rs index 2353904d79d75..49db4fa306a7c 100644 --- a/tests/ui/typeck/issue-53712.rs +++ b/tests/ui/typeck/issue-53712.rs @@ -5,5 +5,5 @@ fn main() { arr.0; //~^ ERROR no field `0` on type `[{integer}; 5]` [E0609] //~| HELP instead of using tuple indexing, use array indexing - //~| SUGGESTION arr[0] + //~| SUGGESTION [ } diff --git a/tests/ui/typeck/issue-91328.stderr b/tests/ui/typeck/issue-91328.stderr index f2f407bcafff2..f9016400fd7af 100644 --- a/tests/ui/typeck/issue-91328.stderr +++ b/tests/ui/typeck/issue-91328.stderr @@ -1,38 +1,46 @@ error[E0529]: expected an array or slice, found `Vec` --> $DIR/issue-91328.rs:10:12 | -LL | match r { - | - help: consider using `as_deref` here: `r.as_deref()` -LL | LL | Ok([a, b]) => a + b, | ^^^^^^ pattern cannot match with input type `Vec` + | +help: consider using `as_deref` here + | +LL | match r.as_deref() { + | +++++++++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/issue-91328.rs:20:14 | -LL | match o { - | - help: consider using `as_deref` here: `o.as_deref()` -LL | LL | Some([a, b]) => a + b, | ^^^^^^ pattern cannot match with input type `Vec` + | +help: consider using `as_deref` here + | +LL | match o.as_deref() { + | +++++++++++ error[E0529]: expected an array or slice, found `Vec` --> $DIR/issue-91328.rs:30:9 | -LL | match v { - | - help: consider slicing here: `v[..]` -LL | LL | [a, b] => a + b, | ^^^^^^ pattern cannot match with input type `Vec` + | +help: consider slicing here + | +LL | match v[..] { + | ++++ error[E0529]: expected an array or slice, found `Box<[i32; 2]>` --> $DIR/issue-91328.rs:40:14 | -LL | match a { - | - help: consider using `as_deref` here: `a.as_deref()` -LL | LL | Some([a, b]) => a + b, | ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>` + | +help: consider using `as_deref` here + | +LL | match a.as_deref() { + | +++++++++++ error: aborting due to 4 previous errors From a5e7da0cf6cd7b03ad9d1079aab978b52007b221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Jul 2024 00:24:10 +0000 Subject: [PATCH 135/189] Tweak raw-pointer field access and array indexing suggestions --- compiler/rustc_hir_typeck/src/expr.rs | 44 +++++++++++-------- tests/ui/issues/issue-11004.stderr | 20 +++++---- .../parenthesized-deref-suggestion.stderr | 14 +++--- tests/ui/typeck/issue-53712.stderr | 10 +++-- tests/ui/unsafe/unsafe-fn-autoderef.stderr | 10 +++-- 5 files changed, 58 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f3aece4e1d8aa..bd5e5294983d2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2551,10 +2551,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *base_ty.peel_refs().kind() { ty::Array(_, len) => { - self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len); + self.maybe_suggest_array_indexing(&mut err, base, ident, len); } ty::RawPtr(..) => { - self.suggest_first_deref_field(&mut err, expr, base, ident); + self.suggest_first_deref_field(&mut err, base, ident); } ty::Param(param_ty) => { err.span_label(ident.span, "unknown field"); @@ -2721,7 +2721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_array_indexing( &self, err: &mut Diag<'_>, - expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, len: ty::Const<'tcx>, @@ -2729,32 +2728,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(field.span, "unknown field"); if let (Some(len), Ok(user_index)) = (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::()) - && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { let help = "instead of using tuple indexing, use array indexing"; - let suggestion = format!("{base}[{field}]"); let applicability = if len < user_index { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }; - err.span_suggestion(expr.span, help, suggestion, applicability); + err.multipart_suggestion( + help, + vec![ + (base.span.between(field.span), "[".to_string()), + (field.span.shrink_to_hi(), "]".to_string()), + ], + applicability, + ); } } - fn suggest_first_deref_field( - &self, - err: &mut Diag<'_>, - expr: &hir::Expr<'_>, - base: &hir::Expr<'_>, - field: Ident, - ) { + fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, field: Ident) { err.span_label(field.span, "unknown field"); - if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { - let msg = format!("`{base}` is a raw pointer; try dereferencing it"); - let suggestion = format!("(*{base}).{field}"); - err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect); - } + let val = if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) + && base.len() < 20 + { + format!("`{base}`") + } else { + "the value".to_string() + }; + err.multipart_suggestion( + format!("{val} is a raw pointer; try dereferencing it"), + vec![ + (base.span.shrink_to_lo(), "(*".to_string()), + (base.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); } fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> { diff --git a/tests/ui/issues/issue-11004.stderr b/tests/ui/issues/issue-11004.stderr index ea141e61df8d3..6d157c9113024 100644 --- a/tests/ui/issues/issue-11004.stderr +++ b/tests/ui/issues/issue-11004.stderr @@ -2,19 +2,23 @@ error[E0609]: no field `x` on type `*mut A` --> $DIR/issue-11004.rs:7:21 | LL | let x : i32 = n.x; - | --^ - | | | - | | unknown field - | help: `n` is a raw pointer; try dereferencing it: `(*n).x` + | ^ unknown field + | +help: `n` is a raw pointer; try dereferencing it + | +LL | let x : i32 = (*n).x; + | ++ + error[E0609]: no field `y` on type `*mut A` --> $DIR/issue-11004.rs:8:21 | LL | let y : f64 = n.y; - | --^ - | | | - | | unknown field - | help: `n` is a raw pointer; try dereferencing it: `(*n).y` + | ^ unknown field + | +help: `n` is a raw pointer; try dereferencing it + | +LL | let y : f64 = (*n).y; + | ++ + error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/parenthesized-deref-suggestion.stderr b/tests/ui/suggestions/parenthesized-deref-suggestion.stderr index 9f185f5dd52b3..29e973b3a1730 100644 --- a/tests/ui/suggestions/parenthesized-deref-suggestion.stderr +++ b/tests/ui/suggestions/parenthesized-deref-suggestion.stderr @@ -4,19 +4,21 @@ error[E0609]: no field `opts` on type `*const Session` LL | (sess as *const Session).opts; | ^^^^ unknown field | -help: `(sess as *const Session)` is a raw pointer; try dereferencing it +help: the value is a raw pointer; try dereferencing it | LL | (*(sess as *const Session)).opts; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++ + error[E0609]: no field `0` on type `[u32; 1]` --> $DIR/parenthesized-deref-suggestion.rs:10:21 | LL | (x as [u32; 1]).0; - | ----------------^ - | | | - | | unknown field - | help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]` + | ^ unknown field + | +help: instead of using tuple indexing, use array indexing + | +LL | (x as [u32; 1])[0]; + | ~ + error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-53712.stderr b/tests/ui/typeck/issue-53712.stderr index ec31766324b26..ffaf5cde1d71e 100644 --- a/tests/ui/typeck/issue-53712.stderr +++ b/tests/ui/typeck/issue-53712.stderr @@ -2,10 +2,12 @@ error[E0609]: no field `0` on type `[{integer}; 5]` --> $DIR/issue-53712.rs:5:9 | LL | arr.0; - | ----^ - | | | - | | unknown field - | help: instead of using tuple indexing, use array indexing: `arr[0]` + | ^ unknown field + | +help: instead of using tuple indexing, use array indexing + | +LL | arr[0]; + | ~ + error: aborting due to 1 previous error diff --git a/tests/ui/unsafe/unsafe-fn-autoderef.stderr b/tests/ui/unsafe/unsafe-fn-autoderef.stderr index c3ab802022267..c19028ac8661b 100644 --- a/tests/ui/unsafe/unsafe-fn-autoderef.stderr +++ b/tests/ui/unsafe/unsafe-fn-autoderef.stderr @@ -2,10 +2,12 @@ error[E0609]: no field `f` on type `*const Rec` --> $DIR/unsafe-fn-autoderef.rs:19:14 | LL | return p.f; - | --^ - | | | - | | unknown field - | help: `p` is a raw pointer; try dereferencing it: `(*p).f` + | ^ unknown field + | +help: `p` is a raw pointer; try dereferencing it + | +LL | return (*p).f; + | ++ + error: aborting due to 1 previous error From b50e9155781d767c8edb487fe9d19e5b701961d5 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Thu, 4 Jul 2024 14:56:08 +0800 Subject: [PATCH 136/189] chore: remove repeat words Signed-off-by: cuishuang --- library/core/src/hint.rs | 2 +- library/core/src/slice/sort/stable/drift.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 976a6c04ca6fa..b3e36e6fbc4ac 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -189,7 +189,7 @@ pub const unsafe fn unreachable_unchecked() -> ! { /// ``` /// /// This example is quite unlike anything that would be used in the real world: it is redundant -/// to put an an assertion right next to code that checks the same thing, and dereferencing a +/// to put an assertion right next to code that checks the same thing, and dereferencing a /// pointer already has the builtin assumption that it is nonnull. However, it illustrates the /// kind of changes the optimizer can make even when the behavior is less obviously related. #[track_caller] diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index 4008639095bde..2d9c4ac9fcf7c 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -200,7 +200,7 @@ fn logical_merge bool>( // If one or both of the runs are sorted do a physical merge, using // quicksort to sort the unsorted run if present. We also *need* to // physically merge if the combined runs would not fit in the scratch space - // anymore (as this would mean we are no longer able to to quicksort them). + // anymore (as this would mean we are no longer able to quicksort them). let len = v.len(); let can_fit_in_scratch = len <= scratch.len(); if !can_fit_in_scratch || left.sorted() || right.sorted() { From c198c0e6d0556cec74d10aec998f4e229137c701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 10:10:30 +0200 Subject: [PATCH 137/189] Do not consider LLDB version to be valid if it is empty When dry run is enabled, the command for finding LLDB version would succeed, but return an empty string. This was inadvertently enabling a code path that should only be executed when the LLDB is actually present and its version is valid. This commit makes sure that if the version is empty, LLDB will be considered not found. --- src/bootstrap/src/core/build_steps/test.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 998e45848a1c3..dc53bd3cfa785 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1805,14 +1805,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); let lldb_version = builder - .run( - BootstrapCommand::new(&lldb_exe) - .capture() - .allow_failure() - .run_always() - .arg("--version"), - ) - .stdout_if_ok(); + .run(BootstrapCommand::new(&lldb_exe).capture().allow_failure().arg("--version")) + .stdout_if_ok() + .and_then(|v| if v.trim().is_empty() { None } else { Some(v) }); if let Some(ref vers) = lldb_version { cmd.arg("--lldb-version").arg(vers); let lldb_python_dir = builder From 0b4edb2487005d7db85a1261fcc77e26e1955553 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 4 Jul 2024 02:50:56 +0800 Subject: [PATCH 138/189] reject SmartPointer constructions not serving the purpose --- .../src/deriving/smart_ptr.rs | 39 +++++++++- .../ui/deriving/deriving-smart-pointer-neg.rs | 45 +++++++++++ .../deriving-smart-pointer-neg.stderr | 75 +++++++++++++++++++ tests/ui/deriving/deriving-smart-pointer.rs | 1 + .../feature-gate-derive-smart-pointer.rs | 1 + .../feature-gate-derive-smart-pointer.stderr | 2 +- 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 tests/ui/deriving/deriving-smart-pointer-neg.rs create mode 100644 tests/ui/deriving/deriving-smart-pointer-neg.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index ea054a7e35526..bbc7cd3962720 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -3,8 +3,9 @@ use std::mem::swap; use ast::HasAttrs; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, - TraitBoundModifiers, + TraitBoundModifiers, VariantData, }; +use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr( _is_const: bool, ) { let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(_, g) = &aitem.kind + && let ItemKind::Struct(struct_data, g) = &aitem.kind { + let is_transparent = aitem.attrs.iter().any(|attr| { + attr::find_repr_attrs(cx.sess, attr) + .into_iter() + .any(|r| matches!(r, attr::ReprTransparent)) + }); + if !is_transparent { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); + return; + } + if !matches!( + struct_data, + VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) + if !fields.is_empty()) + { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with at least one field", + ) + .emit(); + return; + } (aitem.ident, g) } else { - cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit(); + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); return; }; diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs new file mode 100644 index 0000000000000..bfb4e86b39601 --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs @@ -0,0 +1,45 @@ +#![feature(derive_smart_pointer, arbitrary_self_types)] + +use std::marker::SmartPointer; + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +enum NotStruct<'a, T: ?Sized> { + Variant(&'a T), +} + +#[derive(SmartPointer)] +//~^ ERROR: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits +#[repr(transparent)] +struct NoPointee<'a, T: ?Sized> { + ptr: &'a T, +} + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[repr(transparent)] +struct NoField<'a, #[pointee] T: ?Sized> {} +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: type parameter `T` is never used + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[repr(transparent)] +struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: type parameter `T` is never used + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +struct NotTransparent<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +// However, reordering attributes should work nevertheless. +#[repr(transparent)] +#[derive(SmartPointer)] +struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +fn main() {} diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr new file mode 100644 index 0000000000000..d994a6ee376b0 --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-neg.stderr @@ -0,0 +1,75 @@ +error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-smart-pointer-neg.rs:5:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits + --> $DIR/deriving-smart-pointer-neg.rs:11:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with at least one field + --> $DIR/deriving-smart-pointer-neg.rs:18:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with at least one field + --> $DIR/deriving-smart-pointer-neg.rs:25:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-smart-pointer-neg.rs:32:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-smart-pointer-neg.rs:21:16 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-smart-pointer-neg.rs:21:31 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-smart-pointer-neg.rs:28:20 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-smart-pointer-neg.rs:28:35 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-smart-pointer.rs index cfc3369850bd6..d34a502da684f 100644 --- a/tests/ui/deriving/deriving-smart-pointer.rs +++ b/tests/ui/deriving/deriving-smart-pointer.rs @@ -4,6 +4,7 @@ use std::marker::SmartPointer; #[derive(SmartPointer)] +#[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs index ae8005592cdb6..3257a9ca624ba 100644 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs +++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs @@ -1,6 +1,7 @@ use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer' #[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer' +#[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { //~^ ERROR the `#[pointee]` attribute is an experimental feature ptr: &'a T, diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr index 0ffd82fb9e120..19501939dc5be 100644 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr +++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr @@ -9,7 +9,7 @@ LL | #[derive(SmartPointer)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[pointee]` attribute is an experimental feature - --> $DIR/feature-gate-derive-smart-pointer.rs:4:22 + --> $DIR/feature-gate-derive-smart-pointer.rs:5:22 | LL | struct MyPointer<'a, #[pointee] T: ?Sized> { | ^^^^^^^^^^ From 1471532131984a8819401b02201982b5993ba996 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Jul 2024 11:07:19 +0200 Subject: [PATCH 139/189] Allow to have different types for arguments of `Rustc::remap_path_prefix` --- src/tools/run-make-support/src/rustc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 3f23c1b8f9e76..ffc18a5e48753 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -107,7 +107,11 @@ impl Rustc { } /// Remap source path prefixes in all output. - pub fn remap_path_prefix>(&mut self, from: P, to: P) -> &mut Self { + pub fn remap_path_prefix, P2: AsRef>( + &mut self, + from: P, + to: P2, + ) -> &mut Self { let from = from.as_ref().to_string_lossy(); let to = to.as_ref().to_string_lossy(); From 12f29e991a4eef962d315b45d24c784b4c5b987e Mon Sep 17 00:00:00 2001 From: schvv31n Date: Thu, 4 Jul 2024 10:18:57 +0100 Subject: [PATCH 140/189] added built-in var to jsondocck --- src/tools/jsondocck/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index 50697d46b8c70..5f72bd171a17c 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -23,7 +23,7 @@ impl Cache { Cache { value: serde_json::from_str::(&content).expect("failed to convert from JSON"), - variables: HashMap::new(), + variables: HashMap::from([("FILE".to_owned(), config.template.clone().into())]), } } From 8ef2c6c6afd8f5b4d5c69278cc3dd986e37c574d Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Wed, 3 Jul 2024 22:56:31 +0200 Subject: [PATCH 141/189] TB: Make FnEntry access on protected locations be a write under certain circumstances --- .../tree_borrows/diagnostics.rs | 7 ++-- .../src/borrow_tracker/tree_borrows/mod.rs | 19 ++------- .../src/borrow_tracker/tree_borrows/perms.rs | 4 ++ .../src/borrow_tracker/tree_borrows/tree.rs | 41 +++++++++++-------- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index 8abc8530f7c46..498b7dc3e420a 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -19,7 +19,7 @@ pub enum AccessCause { Explicit(AccessKind), Reborrow, Dealloc, - FnExit, + FnExit(AccessKind), } impl fmt::Display for AccessCause { @@ -28,7 +28,8 @@ impl fmt::Display for AccessCause { Self::Explicit(kind) => write!(f, "{kind}"), Self::Reborrow => write!(f, "reborrow"), Self::Dealloc => write!(f, "deallocation"), - Self::FnExit => write!(f, "protector release"), + Self::FnExit(AccessKind::Read) => write!(f, "protector release read"), + Self::FnExit(AccessKind::Write) => write!(f, "protector release write"), } } } @@ -40,7 +41,7 @@ impl AccessCause { Self::Explicit(kind) => format!("{rel} {kind}"), Self::Reborrow => format!("reborrow (acting as a {rel} read access)"), Self::Dealloc => format!("deallocation (acting as a {rel} write access)"), - Self::FnExit => format!("protector release (acting as a {rel} read access)"), + Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"), } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 77e003ab8a789..86074384084d5 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -68,13 +68,11 @@ impl<'tcx> Tree { let global = machine.borrow_tracker.as_ref().unwrap(); let span = machine.current_span(); self.perform_access( - access_kind, tag, - Some(range), + Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))), global, alloc_id, span, - diagnostics::AccessCause::Explicit(access_kind), ) } @@ -115,15 +113,8 @@ impl<'tcx> Tree { alloc_id: AllocId, // diagnostics ) -> InterpResult<'tcx> { let span = machine.current_span(); - self.perform_access( - AccessKind::Read, - tag, - None, // no specified range because it occurs on the entire allocation - global, - alloc_id, - span, - diagnostics::AccessCause::FnExit, - ) + // `None` makes it the magic on-protector-end operation + self.perform_access(tag, None, global, alloc_id, span) } } @@ -297,13 +288,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // All reborrows incur a (possibly zero-sized) read access to the parent tree_borrows.perform_access( - AccessKind::Read, orig_tag, - Some(range), + Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)), this.machine.borrow_tracker.as_ref().unwrap(), alloc_id, this.machine.current_span(), - diagnostics::AccessCause::Reborrow, )?; // Record the parent-child pair in the tree. tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range, span)?; diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index fb3a4c8dad91c..7aa9c3e862bcc 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -186,6 +186,10 @@ impl Permission { pub fn is_disabled(&self) -> bool { self.inner == Disabled } + /// Check if `self` is the post-child-write state of a pointer (is `Active`). + pub fn is_active(&self) -> bool { + self.inner == Active + } /// Default initial permission of the root of a new tree at inbounds positions. /// Must *only* be used for the root, this is not in general an "initial" permission! diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index ff4589657aff2..90bd11032185c 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -530,13 +530,11 @@ impl<'tcx> Tree { span: Span, // diagnostics ) -> InterpResult<'tcx> { self.perform_access( - AccessKind::Write, tag, - Some(access_range), + Some((access_range, AccessKind::Write, diagnostics::AccessCause::Dealloc)), global, alloc_id, span, - diagnostics::AccessCause::Dealloc, )?; for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) { TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } @@ -570,12 +568,16 @@ impl<'tcx> Tree { } /// Map the per-node and per-location `LocationState::perform_access` - /// to each location of `access_range`, on every tag of the allocation. + /// to each location of the first component of `access_range_and_kind`, + /// on every tag of the allocation. /// - /// If `access_range` is `None`, this is interpreted as the special + /// If `access_range_and_kind` is `None`, this is interpreted as the special /// access that is applied on protector release: /// - the access will be applied only to initialized locations of the allocation, - /// - and it will not be visible to children. + /// - it will not be visible to children, + /// - it will be recorded as a `FnExit` diagnostic access + /// - and it will be a read except if the location is `Active`, i.e. has been written to, + /// in which case it will be a write. /// /// `LocationState::perform_access` will take care of raising transition /// errors and updating the `initialized` status of each location, @@ -585,13 +587,11 @@ impl<'tcx> Tree { /// - recording the history. pub fn perform_access( &mut self, - access_kind: AccessKind, tag: BorTag, - access_range: Option, + access_range_and_kind: Option<(AllocRange, AccessKind, diagnostics::AccessCause)>, global: &GlobalState, - alloc_id: AllocId, // diagnostics - span: Span, // diagnostics - access_cause: diagnostics::AccessCause, // diagnostics + alloc_id: AllocId, // diagnostics + span: Span, // diagnostics ) -> InterpResult<'tcx> { use std::ops::Range; // Performs the per-node work: @@ -605,6 +605,8 @@ impl<'tcx> Tree { // `perms_range` is only for diagnostics (it is the range of // the `RangeMap` on which we are currently working). let node_app = |perms_range: Range, + access_kind: AccessKind, + access_cause: diagnostics::AccessCause, args: NodeAppArgs<'_>| -> Result { let NodeAppArgs { node, mut perm, rel_pos } = args; @@ -618,14 +620,13 @@ impl<'tcx> Tree { let protected = global.borrow().protected_tags.contains_key(&node.tag); let transition = old_state.perform_access(access_kind, rel_pos, protected)?; - // Record the event as part of the history if !transition.is_noop() { node.debug_info.history.push(diagnostics::Event { transition, is_foreign: rel_pos.is_foreign(), access_cause, - access_range, + access_range: access_range_and_kind.map(|x| x.0), transition_range: perms_range, span, }); @@ -636,6 +637,7 @@ impl<'tcx> Tree { // Error handler in case `node_app` goes wrong. // Wraps the faulty transition in more context for diagnostics. let err_handler = |perms_range: Range, + access_cause: diagnostics::AccessCause, args: ErrHandlerArgs<'_, TransitionError>| -> InterpError<'tcx> { let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args; @@ -650,7 +652,7 @@ impl<'tcx> Tree { .build() }; - if let Some(access_range) = access_range { + if let Some((access_range, access_kind, access_cause)) = access_range_and_kind { // Default branch: this is a "normal" access through a known range. // We iterate over affected locations and traverse the tree for each of them. for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) @@ -658,8 +660,8 @@ impl<'tcx> Tree { TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } .traverse_parents_this_children_others( tag, - |args| node_app(perms_range.clone(), args), - |args| err_handler(perms_range.clone(), args), + |args| node_app(perms_range.clone(), access_kind, access_cause, args), + |args| err_handler(perms_range.clone(), access_cause, args), )?; } } else { @@ -678,11 +680,14 @@ impl<'tcx> Tree { if let Some(p) = perms.get(idx) && p.initialized { + let access_kind = + if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read }; + let access_cause = diagnostics::AccessCause::FnExit(access_kind); TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } .traverse_nonchildren( tag, - |args| node_app(perms_range.clone(), args), - |args| err_handler(perms_range.clone(), args), + |args| node_app(perms_range.clone(), access_kind, access_cause, args), + |args| err_handler(perms_range.clone(), access_cause, args), )?; } } From 0a86e7966442e12fa2080727d08047fdd2d3e619 Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Thu, 4 Jul 2024 10:59:30 +0200 Subject: [PATCH 142/189] Add UI test for protector end write semantics --- .../fail/tree_borrows/protector-write-lazy.rs | 35 +++++++++++++++++++ .../tree_borrows/protector-write-lazy.stderr | 27 ++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs new file mode 100644 index 0000000000000..238f6dba9d3f7 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-tree-borrows +// This test tests that TB's protector end semantics correctly ensure +// that protected activated writes can be reordered. +fn the_other_function(ref_to_fst_elem: &mut i32, ptr_to_vec: *mut i32) -> *mut i32 { + // Activate the reference. Afterwards, we should be able to reorder arbitrary writes. + *ref_to_fst_elem = 0; + // Here is such an arbitrary write. + // It could be moved down after the retag, in which case the `funky_ref` would be invalidated. + // We need to ensure that the `funky_ptr` is unusable even if the write to `ref_to_fst_elem` + // happens before the retag. + *ref_to_fst_elem = 42; + // this creates a reference that is Reserved Lazy on the first element (offset 0). + // It does so by doing a proper retag on the second element (offset 1), which is fine + // since nothing else happens at that offset, but the lazy init mechanism means it's + // also reserved at offset 0, but not initialized. + let funky_ptr_lazy_on_fst_elem = + unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1); + // If we write to `ref_to_fst_elem` here, then any further access to `funky_ptr_lazy_on_fst_elem` would + // definitely be UB. Since the compiler ought to be able to reorder the write of `42` above down to + // here, that means we want this program to also be UB. + return funky_ptr_lazy_on_fst_elem; +} + +fn main() { + let mut v = vec![0, 1]; + // get a pointer to the root of the allocation + // note that it's not important it's the actual root, what matters is that it's a parent + // of both references that will be created + let ptr_to_vec = v.as_mut_ptr(); + let ref_to_fst_elem = unsafe { &mut *ptr_to_vec }; + let funky_ptr_lazy_on_fst_elem = the_other_function(ref_to_fst_elem, ptr_to_vec); + // now we try to use the funky lazy pointer. + // It should be UB, since the write-on-protector-end should disable it. + unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } //~ ERROR: /reborrow through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr new file mode 100644 index 0000000000000..955abd144c7c3 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: reborrow through at ALLOC[0x0] is forbidden + --> $DIR/protector-write-lazy.rs:LL:CC + | +LL | unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow through at ALLOC[0x0] is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag has state Disabled which forbids this reborrow (acting as a child read access) +help: the accessed tag was created here, in the initial state Reserved + --> $DIR/protector-write-lazy.rs:LL:CC + | +LL | unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: the accessed tag later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag + --> $DIR/protector-write-lazy.rs:LL:CC + | +LL | } + | ^ + = help: this transition corresponds to a loss of read and write permissions + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/protector-write-lazy.rs:LL:CC + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 87b741549cff667ef59d92a36938f5d55d932bf6 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 4 Jul 2024 10:07:22 +0000 Subject: [PATCH 143/189] trivial update on tidy bless note --- src/tools/tidy/src/run_make_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs index 2d9f8448a35bf..8d1767878378c 100644 --- a/src/tools/tidy/src/run_make_tests.rs +++ b/src/tools/tidy/src/run_make_tests.rs @@ -95,7 +95,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { tidy_error!( bad, "Makefile `{}` no longer exists and should be removed from the exclusions in \ - `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run --bless to update \ + `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run `x test tidy --bless` to update \ the allow list", p.display() ); From 02bec40930d7256d290c6a61b60df8284e460dda Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Thu, 4 Jul 2024 12:01:49 +0200 Subject: [PATCH 144/189] TB: protector end semantics never causes immediate UB --- .../miri/src/borrow_tracker/tree_borrows/diagnostics.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index 498b7dc3e420a..a753de28a041e 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -28,8 +28,11 @@ impl fmt::Display for AccessCause { Self::Explicit(kind) => write!(f, "{kind}"), Self::Reborrow => write!(f, "reborrow"), Self::Dealloc => write!(f, "deallocation"), - Self::FnExit(AccessKind::Read) => write!(f, "protector release read"), - Self::FnExit(AccessKind::Write) => write!(f, "protector release write"), + // This is dead code, since the protector release access itself can never + // cause UB (while the protector is active, if some other access invalidates + // further use of the protected tag, that is immediate UB). + // Describing the cause of UB is the only time this function is called. + Self::FnExit(_) => unreachable!("protector accesses can never be the source of UB"), } } } From 410f760ed530954a3f3da66b41207833207efdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 4 Jul 2024 12:34:07 +0200 Subject: [PATCH 145/189] Make CI more agnostic of the owning GitHub organization This should make it possible to switch running `auto` and `try` builds from `rust-lang-ci` to `rust-lang`. --- src/ci/docker/run.sh | 3 +-- src/ci/github-actions/calculate-job-matrix.py | 14 +++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index a4c59b3067ead..695b8b4c0d9e1 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -93,8 +93,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then docker --version REGISTRY=ghcr.io - # PR CI runs on rust-lang, but we want to use the cache from rust-lang-ci - REGISTRY_USERNAME=rust-lang-ci + REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER} # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum} # Tag used to cache the Docker build diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py index 4f9bc39a628ce..d03bbda100807 100755 --- a/src/ci/github-actions/calculate-job-matrix.py +++ b/src/ci/github-actions/calculate-job-matrix.py @@ -91,21 +91,17 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: if ctx.event_name == "pull_request": return PRRunType() elif ctx.event_name == "push": - old_bors_try_build = ( - ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and - ctx.repository == "rust-lang-ci/rust" + try_build = ctx.ref in ( + "refs/heads/try", + "refs/heads/try-perf", + "refs/heads/automation/bors/try" ) - new_bors_try_build = ( - ctx.ref == "refs/heads/automation/bors/try" and - ctx.repository == "rust-lang/rust" - ) - try_build = old_bors_try_build or new_bors_try_build if try_build: jobs = get_custom_jobs(ctx) return TryRunType(custom_jobs=jobs) - if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust": + if ctx.ref == "refs/heads/auto": return AutoRunType() return None From 273d253ce6855381c9b7c36d3ea92581dd54becb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2024 16:04:37 +0200 Subject: [PATCH 146/189] offset_from: "the difference must fit in an isize" is a corollary also, isize::MIN is an impossible distance --- .../src/interpret/intrinsics.rs | 4 +-- library/core/src/ptr/const_ptr.rs | 27 +++----------- library/core/src/ptr/mut_ptr.rs | 27 +++----------- library/core/src/ptr/non_null.rs | 35 +++++-------------- tests/ui/consts/offset_from_ub.rs | 8 +++++ tests/ui/consts/offset_from_ub.stderr | 16 ++++++--- 6 files changed, 40 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1d54da267eebf..d86f1a7a34f2a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // The signed form of the intrinsic allows this. If we interpret the // difference as isize, we'll get the proper signed difference. If that - // seems *positive*, they were more than isize::MAX apart. + // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart. let dist = val.to_target_isize(self)?; - if dist >= 0 { + if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() { throw_ub_custom!( fluent::const_eval_offset_from_underflow, name = intrinsic_name, diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5537d26669a23..039dc6d7a4981 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -611,8 +611,7 @@ impl *const T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// /// * `self` and `origin` must either /// @@ -623,26 +622,10 @@ impl *const T { /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, **in bytes**, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 30d5b2cfc5a8b..cbd3de1268a18 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -836,8 +836,7 @@ impl *mut T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// /// * `self` and `origin` must either /// @@ -848,26 +847,10 @@ impl *mut T { /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, in bytes, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 0504a0fc32f4f..0b1bd5aeebb9c 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -761,38 +761,21 @@ impl NonNull { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * Both `self` and `origin` must be either in bounds or one - /// byte past the end of the same [allocated object]. + /// * `self` and `origin` must either /// - /// * Both pointers must be *derived from* a pointer to the same object. - /// (See below for an example.) + /// * both be *derived from* a pointer to the same [allocated object], and the memory range between + /// the two pointers must be either empty or in bounds of that object. (See below for an example.) + /// * or both be derived from an integer literal/constant, and point to the same address. /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, in bytes, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 57767e965962b..e71f88b8d5fab 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -92,6 +92,14 @@ pub const TOO_FAR_APART2: isize = { unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed //~| too far before }; +pub const TOO_FAR_APART3: isize = { + let ptr1 = &0u8 as *const u8; + let ptr2 = ptr1.wrapping_offset(isize::MIN); + // The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its + // absolute value does not. (Also anyway there cannot be an allocation of that size.) + unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed + //~| too far before +}; const WRONG_ORDER_UNSIGNED: usize = { let a = ['a', 'b', 'c']; diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 65f75a6e05875..7caf6247b9e9e 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -60,13 +60,19 @@ LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:99:14 + --> $DIR/offset_from_ub.rs:100:14 + | +LL | unsafe { ptr_offset_from(ptr1, ptr2) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:107:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:106:14 + --> $DIR/offset_from_ub.rs:114:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second @@ -79,7 +85,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` - --> $DIR/offset_from_ub.rs:115:14 + --> $DIR/offset_from_ub.rs:123:14 | LL | unsafe { ptr2.offset_from(ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -92,11 +98,11 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` - --> $DIR/offset_from_ub.rs:121:14 + --> $DIR/offset_from_ub.rs:129:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0080`. From 9ba492f2797250b2fcaa38d483ca5c23bf0bd8dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2024 16:42:33 +0200 Subject: [PATCH 147/189] also remove redundant requirements from offset() --- library/core/src/ptr/const_ptr.rs | 101 ++++++++++-------------------- library/core/src/ptr/mut_ptr.rs | 99 ++++++++++------------------- library/core/src/ptr/non_null.rs | 96 ++++++++++------------------ 3 files changed, 100 insertions(+), 196 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 039dc6d7a4981..68cf820343344 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -390,37 +390,26 @@ impl *const T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -622,7 +611,7 @@ impl *const T { /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// As a consequence, the absolute distance between the pointers, **in bytes**, computed on + /// As a consequence, the absolute distance between the pointers, in bytes, computed on /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is /// implied by the in-bounds requirement, and the fact that no allocated object can be larger /// than `isize::MAX` bytes. @@ -862,37 +851,26 @@ impl *const T { } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -946,7 +924,7 @@ impl *const T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -954,30 +932,19 @@ impl *const T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index cbd3de1268a18..0dc910db5b9bd 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -404,37 +404,26 @@ impl *mut T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -1003,37 +992,26 @@ impl *mut T { unsafe { (self as *const T).sub_ptr(origin) } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -1087,7 +1065,7 @@ impl *mut T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -1095,30 +1073,19 @@ impl *mut T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 0b1bd5aeebb9c..75a99e14fdadc 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -476,36 +476,26 @@ impl NonNull { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// @@ -562,36 +552,26 @@ impl NonNull { unsafe { NonNull { pointer: self.pointer.byte_offset(count) } } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. - /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// @@ -649,7 +629,7 @@ impl NonNull { unsafe { NonNull { pointer: self.pointer.byte_add(count) } } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -657,29 +637,19 @@ impl NonNull { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 263 bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// From 34860a56f09baf9bc02cde287f4baff921b9a748 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 4 Jul 2024 12:09:25 +0000 Subject: [PATCH 148/189] Update windows-bindgen to 0.58.0 --- Cargo.lock | 8 +- library/std/src/sys/pal/windows/c.rs | 9 +- .../std/src/sys/pal/windows/c/bindings.txt | 2 +- .../std/src/sys/pal/windows/c/windows_sys.rs | 970 +++--------------- .../src/sys/pal/windows/c/windows_targets.rs | 15 + library/std/src/sys/pal/windows/stdio.rs | 8 +- src/tools/generate-windows-sys/Cargo.toml | 2 +- src/tools/generate-windows-sys/src/main.rs | 1 + 8 files changed, 159 insertions(+), 856 deletions(-) create mode 100644 library/std/src/sys/pal/windows/c/windows_targets.rs diff --git a/Cargo.lock b/Cargo.lock index 96cef9070842e..fbe1abf2a3317 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6356,9 +6356,9 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccb96113d6277ba543c0f77e1c5494af8094bf9daf9b85acdc3f1b620e7c7b4" +checksum = "91cd28d93c692351f3a6e5615567c56756e330bee1c99c6bdd57bfc5ab15f589" dependencies = [ "proc-macro2", "rayon", @@ -6379,9 +6379,9 @@ dependencies = [ [[package]] name = "windows-metadata" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8308d076825b9d9e5abc64f8113e96d02b2aeeba869b20fdd65c7e70cda13dfc" +checksum = "2e837f3c3012cfe9e7086302a93f441a7999439be1ad4c530d55d2f6d2921809" [[package]] name = "windows-sys" diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 6ec82693077dc..27aa35f69f1bf 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -13,6 +13,8 @@ use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_vo use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; +mod windows_targets; + mod windows_sys; pub use windows_sys::*; @@ -504,11 +506,8 @@ if #[cfg(not(target_vendor = "uwp"))] { #[cfg(target_arch = "arm")] pub enum CONTEXT {} }} - -#[link(name = "ws2_32")] -extern "system" { - pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32; -} +// WSAStartup is only redefined here so that we can override WSADATA for Arm32 +windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32); #[cfg(target_arch = "arm")] #[repr(C)] pub struct WSADATA { diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 849e64ac59135..5ad4a3731d822 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -1,5 +1,5 @@ --out windows_sys.rs ---config flatten std +--config flatten sys --filter !Windows.Win32.Foundation.INVALID_HANDLE_VALUE Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 19f013d3347e4..fea00fec9ae59 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,843 +1,136 @@ -// Bindings generated by `windows-bindgen` 0.57.0 +// Bindings generated by `windows-bindgen` 0.58.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] -#[link(name = "advapi32")] -extern "system" { - pub fn OpenProcessToken( - processhandle: HANDLE, - desiredaccess: TOKEN_ACCESS_MASK, - tokenhandle: *mut HANDLE, - ) -> BOOL; -} -#[link(name = "advapi32")] -extern "system" { - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(randombuffer: *mut core::ffi::c_void, randombufferlength: u32) -> BOOLEAN; -} -#[link(name = "kernel32")] -extern "system" { - pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK); -} -#[link(name = "kernel32")] -extern "system" { - pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK); -} -#[link(name = "kernel32")] -extern "system" { - pub fn CancelIo(hfile: HANDLE) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CloseHandle(hobject: HANDLE) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CompareStringOrdinal( - lpstring1: PCWSTR, - cchcount1: i32, - lpstring2: PCWSTR, - cchcount2: i32, - bignorecase: BOOL, - ) -> COMPARESTRING_RESULT; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CopyFileExW( - lpexistingfilename: PCWSTR, - lpnewfilename: PCWSTR, - lpprogressroutine: LPPROGRESS_ROUTINE, - lpdata: *const core::ffi::c_void, - pbcancel: *mut BOOL, - dwcopyflags: u32, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateDirectoryW( - lppathname: PCWSTR, - lpsecurityattributes: *const SECURITY_ATTRIBUTES, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateEventW( - lpeventattributes: *const SECURITY_ATTRIBUTES, - bmanualreset: BOOL, - binitialstate: BOOL, - lpname: PCWSTR, - ) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateFileW( - lpfilename: PCWSTR, - dwdesiredaccess: u32, - dwsharemode: FILE_SHARE_MODE, - lpsecurityattributes: *const SECURITY_ATTRIBUTES, - dwcreationdisposition: FILE_CREATION_DISPOSITION, - dwflagsandattributes: FILE_FLAGS_AND_ATTRIBUTES, - htemplatefile: HANDLE, - ) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateHardLinkW( - lpfilename: PCWSTR, - lpexistingfilename: PCWSTR, - lpsecurityattributes: *const SECURITY_ATTRIBUTES, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateNamedPipeW( - lpname: PCWSTR, - dwopenmode: FILE_FLAGS_AND_ATTRIBUTES, - dwpipemode: NAMED_PIPE_MODE, - nmaxinstances: u32, - noutbuffersize: u32, - ninbuffersize: u32, - ndefaulttimeout: u32, - lpsecurityattributes: *const SECURITY_ATTRIBUTES, - ) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateProcessW( - lpapplicationname: PCWSTR, - lpcommandline: PWSTR, - lpprocessattributes: *const SECURITY_ATTRIBUTES, - lpthreadattributes: *const SECURITY_ATTRIBUTES, - binherithandles: BOOL, - dwcreationflags: PROCESS_CREATION_FLAGS, - lpenvironment: *const core::ffi::c_void, - lpcurrentdirectory: PCWSTR, - lpstartupinfo: *const STARTUPINFOW, - lpprocessinformation: *mut PROCESS_INFORMATION, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateSymbolicLinkW( - lpsymlinkfilename: PCWSTR, - lptargetfilename: PCWSTR, - dwflags: SYMBOLIC_LINK_FLAGS, - ) -> BOOLEAN; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateThread( - lpthreadattributes: *const SECURITY_ATTRIBUTES, - dwstacksize: usize, - lpstartaddress: LPTHREAD_START_ROUTINE, - lpparameter: *const core::ffi::c_void, - dwcreationflags: THREAD_CREATION_FLAGS, - lpthreadid: *mut u32, - ) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn CreateWaitableTimerExW( - lptimerattributes: *const SECURITY_ATTRIBUTES, - lptimername: PCWSTR, - dwflags: u32, - dwdesiredaccess: u32, - ) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST); -} -#[link(name = "kernel32")] -extern "system" { - pub fn DeviceIoControl( - hdevice: HANDLE, - dwiocontrolcode: u32, - lpinbuffer: *const core::ffi::c_void, - ninbuffersize: u32, - lpoutbuffer: *mut core::ffi::c_void, - noutbuffersize: u32, - lpbytesreturned: *mut u32, - lpoverlapped: *mut OVERLAPPED, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn DuplicateHandle( - hsourceprocesshandle: HANDLE, - hsourcehandle: HANDLE, - htargetprocesshandle: HANDLE, - lptargethandle: *mut HANDLE, - dwdesiredaccess: u32, - binherithandle: BOOL, - dwoptions: DUPLICATE_HANDLE_OPTIONS, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn ExitProcess(uexitcode: u32) -> !; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FindClose(hfindfile: HANDLE) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FindFirstFileW(lpfilename: PCWSTR, lpfindfiledata: *mut WIN32_FIND_DATAW) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FindNextFileW(hfindfile: HANDLE, lpfindfiledata: *mut WIN32_FIND_DATAW) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FlushFileBuffers(hfile: HANDLE) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FormatMessageW( - dwflags: FORMAT_MESSAGE_OPTIONS, - lpsource: *const core::ffi::c_void, - dwmessageid: u32, - dwlanguageid: u32, - lpbuffer: PWSTR, - nsize: u32, - arguments: *const *const i8, - ) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn FreeEnvironmentStringsW(penv: PCWSTR) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetActiveProcessorCount(groupnumber: u16) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetCommandLineW() -> PCWSTR; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetConsoleMode(hconsolehandle: HANDLE, lpmode: *mut CONSOLE_MODE) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetCurrentDirectoryW(nbufferlength: u32, lpbuffer: PWSTR) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetCurrentProcess() -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetCurrentProcessId() -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetCurrentThread() -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetEnvironmentStringsW() -> PWSTR; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetEnvironmentVariableW(lpname: PCWSTR, lpbuffer: PWSTR, nsize: u32) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetExitCodeProcess(hprocess: HANDLE, lpexitcode: *mut u32) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFileAttributesW(lpfilename: PCWSTR) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFileInformationByHandle( - hfile: HANDLE, - lpfileinformation: *mut BY_HANDLE_FILE_INFORMATION, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFileInformationByHandleEx( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *mut core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFileType(hfile: HANDLE) -> FILE_TYPE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFinalPathNameByHandleW( - hfile: HANDLE, - lpszfilepath: PWSTR, - cchfilepath: u32, - dwflags: GETFINALPATHNAMEBYHANDLE_FLAGS, - ) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetFullPathNameW( - lpfilename: PCWSTR, - nbufferlength: u32, - lpbuffer: PWSTR, - lpfilepart: *mut PWSTR, - ) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetLastError() -> WIN32_ERROR; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetModuleFileNameW(hmodule: HMODULE, lpfilename: PWSTR, nsize: u32) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetModuleHandleW(lpmodulename: PCWSTR) -> HMODULE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetOverlappedResult( - hfile: HANDLE, - lpoverlapped: *const OVERLAPPED, - lpnumberofbytestransferred: *mut u32, - bwait: BOOL, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetProcessId(process: HANDLE) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetStdHandle(nstdhandle: STD_HANDLE) -> HANDLE; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetSystemDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetSystemInfo(lpsysteminfo: *mut SYSTEM_INFO); -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME); -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME); -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetTempPathW(nbufferlength: u32, lpbuffer: PWSTR) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn GetWindowsDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn InitOnceBeginInitialize( - lpinitonce: *mut INIT_ONCE, - dwflags: u32, - fpending: *mut BOOL, - lpcontext: *mut *mut core::ffi::c_void, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn InitOnceComplete( - lpinitonce: *mut INIT_ONCE, - dwflags: u32, - lpcontext: *const core::ffi::c_void, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn InitializeProcThreadAttributeList( - lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, - dwattributecount: u32, - dwflags: u32, - lpsize: *mut usize, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn LocalFree(hmem: HLOCAL) -> HLOCAL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn MoveFileExW( - lpexistingfilename: PCWSTR, - lpnewfilename: PCWSTR, - dwflags: MOVE_FILE_FLAGS, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn MultiByteToWideChar( - codepage: u32, - dwflags: MULTI_BYTE_TO_WIDE_CHAR_FLAGS, - lpmultibytestr: PCSTR, - cbmultibyte: i32, - lpwidecharstr: PWSTR, - cchwidechar: i32, - ) -> i32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn QueryPerformanceFrequency(lpfrequency: *mut i64) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn ReadConsoleW( - hconsoleinput: HANDLE, - lpbuffer: *mut core::ffi::c_void, - nnumberofcharstoread: u32, - lpnumberofcharsread: *mut u32, - pinputcontrol: *const CONSOLE_READCONSOLE_CONTROL, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn ReadFile( - hfile: HANDLE, - lpbuffer: *mut u8, - nnumberofbytestoread: u32, - lpnumberofbytesread: *mut u32, - lpoverlapped: *mut OVERLAPPED, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn ReadFileEx( - hfile: HANDLE, - lpbuffer: *mut u8, - nnumberofbytestoread: u32, - lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK); -} -#[link(name = "kernel32")] -extern "system" { - pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK); -} -#[link(name = "kernel32")] -extern "system" { - pub fn RemoveDirectoryW(lppathname: PCWSTR) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetCurrentDirectoryW(lppathname: PCWSTR) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetEnvironmentVariableW(lpname: PCWSTR, lpvalue: PCWSTR) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetFileAttributesW( - lpfilename: PCWSTR, - dwfileattributes: FILE_FLAGS_AND_ATTRIBUTES, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetFileInformationByHandle( - hfile: HANDLE, - fileinformationclass: FILE_INFO_BY_HANDLE_CLASS, - lpfileinformation: *const core::ffi::c_void, - dwbuffersize: u32, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetFilePointerEx( - hfile: HANDLE, - lidistancetomove: i64, - lpnewfilepointer: *mut i64, - dwmovemethod: SET_FILE_POINTER_MOVE_METHOD, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetFileTime( - hfile: HANDLE, - lpcreationtime: *const FILETIME, - lplastaccesstime: *const FILETIME, - lplastwritetime: *const FILETIME, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetHandleInformation(hobject: HANDLE, dwmask: u32, dwflags: HANDLE_FLAGS) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetLastError(dwerrcode: WIN32_ERROR); -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SetWaitableTimer( - htimer: HANDLE, - lpduetime: *const i64, - lperiod: i32, - pfncompletionroutine: PTIMERAPCROUTINE, - lpargtocompletionroutine: *const core::ffi::c_void, - fresume: BOOL, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn Sleep(dwmilliseconds: u32); -} -#[link(name = "kernel32")] -extern "system" { - pub fn SleepConditionVariableSRW( - conditionvariable: *mut CONDITION_VARIABLE, - srwlock: *mut SRWLOCK, - dwmilliseconds: u32, - flags: u32, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SleepEx(dwmilliseconds: u32, balertable: BOOL) -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn SwitchToThread() -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TerminateProcess(hprocess: HANDLE, uexitcode: u32) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TlsAlloc() -> u32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TlsFree(dwtlsindex: u32) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TlsGetValue(dwtlsindex: u32) -> *mut core::ffi::c_void; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TlsSetValue(dwtlsindex: u32, lptlsvalue: *const core::ffi::c_void) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> BOOLEAN; -} -#[link(name = "kernel32")] -extern "system" { - pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> BOOLEAN; -} -#[link(name = "kernel32")] -extern "system" { - pub fn UpdateProcThreadAttribute( - lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, - dwflags: u32, - attribute: usize, - lpvalue: *const core::ffi::c_void, - cbsize: usize, - lppreviousvalue: *mut core::ffi::c_void, - lpreturnsize: *const usize, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn WaitForMultipleObjects( - ncount: u32, - lphandles: *const HANDLE, - bwaitall: BOOL, - dwmilliseconds: u32, - ) -> WAIT_EVENT; -} -#[link(name = "kernel32")] -extern "system" { - pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT; -} -#[link(name = "kernel32")] -extern "system" { - pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE); -} -#[link(name = "kernel32")] -extern "system" { - pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE); -} -#[link(name = "kernel32")] -extern "system" { - pub fn WideCharToMultiByte( - codepage: u32, - dwflags: u32, - lpwidecharstr: PCWSTR, - cchwidechar: i32, - lpmultibytestr: PSTR, - cbmultibyte: i32, - lpdefaultchar: PCSTR, - lpuseddefaultchar: *mut BOOL, - ) -> i32; -} -#[link(name = "kernel32")] -extern "system" { - pub fn WriteConsoleW( - hconsoleoutput: HANDLE, - lpbuffer: *const core::ffi::c_void, - nnumberofcharstowrite: u32, - lpnumberofcharswritten: *mut u32, - lpreserved: *const core::ffi::c_void, - ) -> BOOL; -} -#[link(name = "kernel32")] -extern "system" { - pub fn WriteFileEx( - hfile: HANDLE, - lpbuffer: *const u8, - nnumberofbytestowrite: u32, - lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE, - ) -> BOOL; -} -#[link(name = "ntdll")] -extern "system" { - pub fn NtCreateFile( - filehandle: *mut HANDLE, - desiredaccess: FILE_ACCESS_RIGHTS, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - allocationsize: *const i64, - fileattributes: FILE_FLAGS_AND_ATTRIBUTES, - shareaccess: FILE_SHARE_MODE, - createdisposition: NTCREATEFILE_CREATE_DISPOSITION, - createoptions: NTCREATEFILE_CREATE_OPTIONS, - eabuffer: *const core::ffi::c_void, - ealength: u32, - ) -> NTSTATUS; -} -#[link(name = "ntdll")] -extern "system" { - pub fn NtReadFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const core::ffi::c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *mut core::ffi::c_void, - length: u32, - byteoffset: *const i64, - key: *const u32, - ) -> NTSTATUS; -} -#[link(name = "ntdll")] -extern "system" { - pub fn NtWriteFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const core::ffi::c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *const core::ffi::c_void, - length: u32, - byteoffset: *const i64, - key: *const u32, - ) -> NTSTATUS; -} -#[link(name = "ntdll")] -extern "system" { - pub fn RtlNtStatusToDosError(status: NTSTATUS) -> u32; -} -#[link(name = "userenv")] -extern "system" { - pub fn GetUserProfileDirectoryW( - htoken: HANDLE, - lpprofiledir: PWSTR, - lpcchsize: *mut u32, - ) -> BOOL; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSACleanup() -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSADuplicateSocketW( - s: SOCKET, - dwprocessid: u32, - lpprotocolinfo: *mut WSAPROTOCOL_INFOW, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSAGetLastError() -> WSA_ERROR; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSARecv( - s: SOCKET, - lpbuffers: *const WSABUF, - dwbuffercount: u32, - lpnumberofbytesrecvd: *mut u32, - lpflags: *mut u32, - lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSASend( - s: SOCKET, - lpbuffers: *const WSABUF, - dwbuffercount: u32, - lpnumberofbytessent: *mut u32, - dwflags: u32, - lpoverlapped: *mut OVERLAPPED, - lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn WSASocketW( - af: i32, - r#type: i32, - protocol: i32, - lpprotocolinfo: *const WSAPROTOCOL_INFOW, - g: u32, - dwflags: u32, - ) -> SOCKET; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn bind(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn closesocket(s: SOCKET) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn connect(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA); -} -#[link(name = "ws2_32")] -extern "system" { - pub fn getaddrinfo( - pnodename: PCSTR, - pservicename: PCSTR, - phints: *const ADDRINFOA, - ppresult: *mut *mut ADDRINFOA, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn getpeername(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn getsockname(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn getsockopt(s: SOCKET, level: i32, optname: i32, optval: PSTR, optlen: *mut i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn ioctlsocket(s: SOCKET, cmd: i32, argp: *mut u32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn listen(s: SOCKET, backlog: i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn recv(s: SOCKET, buf: PSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn recvfrom( - s: SOCKET, - buf: PSTR, - len: i32, - flags: i32, - from: *mut SOCKADDR, - fromlen: *mut i32, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn select( - nfds: i32, - readfds: *mut FD_SET, - writefds: *mut FD_SET, - exceptfds: *mut FD_SET, - timeout: *const TIMEVAL, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn send(s: SOCKET, buf: PCSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn sendto( - s: SOCKET, - buf: PCSTR, - len: i32, - flags: i32, - to: *const SOCKADDR, - tolen: i32, - ) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn setsockopt(s: SOCKET, level: i32, optname: i32, optval: PCSTR, optlen: i32) -> i32; -} -#[link(name = "ws2_32")] -extern "system" { - pub fn shutdown(s: SOCKET, how: WINSOCK_SHUTDOWN_HOW) -> i32; -} +windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL); +windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK)); +windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK)); +windows_targets::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT); +windows_targets::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST)); +windows_targets::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !); +windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn FindFirstFileW(lpfilename : PCWSTR, lpfindfiledata : *mut WIN32_FIND_DATAW) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32); +windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR); +windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR); +windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); +windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); +windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE); +windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleW(lpmodulename : PCWSTR) -> HMODULE); +windows_targets::link!("kernel32.dll" "system" fn GetOverlappedResult(hfile : HANDLE, lpoverlapped : *const OVERLAPPED, lpnumberofbytestransferred : *mut u32, bwait : BOOL) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC); +windows_targets::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO)); +windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); +windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); +windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); +windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); +windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); +windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); +windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK)); +windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK)); +windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR)); +windows_targets::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); +windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32); +windows_targets::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn TlsAlloc() -> u32); +windows_targets::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) -> *mut core::ffi::c_void); +windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN); +windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT); +windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); +windows_targets::link!("kernel32.dll" "system" fn WakeAllConditionVariable(conditionvariable : *mut CONDITION_VARIABLE)); +windows_targets::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE)); +windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32); +windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL); +windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); +windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); +windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL); +windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR); +windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET); +windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET); +windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA)); +windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn send(s : SOCKET, buf : PCSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn sendto(s : SOCKET, buf : PCSTR, len : i32, flags : i32, to : *const SOCKADDR, tolen : i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i32, optname : i32, optval : PCSTR, optlen : i32) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32); pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; pub type ADDRESS_FAMILY = u16; #[repr(C)] @@ -3991,3 +3284,4 @@ pub struct XSAVE_FORMAT { pub Reserved4: [u8; 224], } // ignore-tidy-filelength +use super::windows_targets; diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs new file mode 100644 index 0000000000000..cc3cc6e861194 --- /dev/null +++ b/library/std/src/sys/pal/windows/c/windows_targets.rs @@ -0,0 +1,15 @@ +pub macro link { + ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + #[link(name = "kernel32")] + extern $abi { + $(#[link_name=$link_name])? + pub fn $($function)*; + } + ) +} + +#[link(name = "advapi32")] +#[link(name = "ntdll")] +#[link(name = "userenv")] +#[link(name = "ws2_32")] +extern "C" {} diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 690b60d1decca..10aeeac07ea2e 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -232,13 +232,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result { debug_assert!(data.len() < u32::MAX as usize); let mut written = 0; cvt(unsafe { - c::WriteConsoleW( - handle, - data.as_ptr() as c::LPCVOID, - data.len() as u32, - &mut written, - ptr::null_mut(), - ) + c::WriteConsoleW(handle, data.as_ptr(), data.len() as u32, &mut written, ptr::null_mut()) })?; Ok(written as usize) } diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml index ebf3082fb4f24..882d3d6352526 100644 --- a/src/tools/generate-windows-sys/Cargo.toml +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies.windows-bindgen] -version = "0.57.0" +version = "0.58.0" diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs index c8913910bd6e7..fd21e7a86b002 100644 --- a/src/tools/generate-windows-sys/src/main.rs +++ b/src/tools/generate-windows-sys/src/main.rs @@ -17,6 +17,7 @@ fn main() -> Result<(), Box> { let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?; writeln!(&mut f, "// ignore-tidy-filelength")?; + writeln!(&mut f, "use super::windows_targets;")?; Ok(()) } From 0d54fe0d02f24923cc82bbdae786471bfa79d70c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 4 Jul 2024 12:20:51 +0000 Subject: [PATCH 149/189] Remove a use of `StructuredDiag`, which is incompatible with automatic error tainting and error translations --- compiler/rustc_hir_analysis/messages.ftl | 2 - compiler/rustc_hir_analysis/src/errors.rs | 9 --- .../src/structured_errors.rs | 5 +- .../structured_errors/sized_unsized_cast.rs | 56 ------------------- compiler/rustc_hir_typeck/messages.ftl | 15 +++++ compiler/rustc_hir_typeck/src/cast.rs | 10 +--- compiler/rustc_hir_typeck/src/errors.rs | 11 ++++ ...slice_elem_ty_mismatch_in_unsizing_cast.rs | 4 ++ ...e_elem_ty_mismatch_in_unsizing_cast.stderr | 9 +++ 9 files changed, 43 insertions(+), 78 deletions(-) delete mode 100644 compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs create mode 100644 tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs create mode 100644 tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 064d9c077b0a6..91b1506d1e4e5 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -55,8 +55,6 @@ hir_analysis_cannot_capture_late_bound_ty = cannot capture late-bound type parameter in {$what} .label = parameter defined here -hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` - hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present .label = `for<...>` is here diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 3ffb51fa9926a..79e948ae7d9e9 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -707,15 +707,6 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> { pub help: Option<()>, } -#[derive(Diagnostic)] -#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)] -pub(crate) struct CastThinPointerToFatPointer<'tcx> { - #[primary_span] - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, -} - #[derive(Diagnostic)] #[diag(hir_analysis_invalid_union_field, code = E0740)] pub(crate) struct InvalidUnionField { diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs index 5abfd25dd95df..61a2400f9e434 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors.rs @@ -1,10 +1,7 @@ mod missing_cast_for_variadic_arg; -mod sized_unsized_cast; mod wrong_number_of_generic_args; -pub use self::{ - missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, -}; +pub use self::{missing_cast_for_variadic_arg::*, wrong_number_of_generic_args::*}; use rustc_errors::{Diag, ErrCode}; use rustc_session::Session; diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs deleted file mode 100644 index 9e871ff9af01b..0000000000000 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{errors, structured_errors::StructuredDiag}; -use rustc_errors::{codes::*, Diag}; -use rustc_middle::ty::{Ty, TypeVisitableExt}; -use rustc_session::Session; -use rustc_span::Span; - -pub struct SizedUnsizedCast<'tcx> { - pub sess: &'tcx Session, - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, -} - -impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> { - fn session(&self) -> &Session { - self.sess - } - - fn code(&self) -> ErrCode { - E0607 - } - - fn diagnostic_common(&self) -> Diag<'tcx> { - let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer { - span: self.span, - expr_ty: self.expr_ty, - cast_ty: self.cast_ty.to_owned(), - }); - - if self.expr_ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> { - err.help( - "Thin pointers are \"simple\" pointers: they are purely a reference to a -memory address. - -Fat pointers are pointers referencing \"Dynamically Sized Types\" (also -called DST). DST don't have a statically known size, therefore they can -only exist behind some kind of pointers that contain additional -information. Slices and trait objects are DSTs. In the case of slices, -the additional information the fat pointer holds is their size. - -To fix this error, don't try to cast directly between thin and fat -pointers. - -For more information about casts, take a look at The Book: -https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions", - ); - err - } -} diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index d6f3f4d640bd5..3c5070bd00628 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -23,6 +23,21 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` +hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` + .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a + memory address. + + Fat pointers are pointers referencing "Dynamically Sized Types" (also + called DST). DST don't have a statically known size, therefore they can + only exist behind some kind of pointers that contain additional + information. Slices and trait objects are DSTs. In the case of slices, + the additional information the fat pointer holds is their size. + + To fix this error, don't try to cast directly between thin and fat + pointers. + + For more information about casts, take a look at The Book: + https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions", hir_typeck_cast_unknown_pointer = cannot cast {$to -> [true] to *[false] from diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index cb1a412d17eef..53e44d6bcaee8 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -500,16 +500,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - use rustc_hir_analysis::structured_errors::{SizedUnsizedCast, StructuredDiag}; - - SizedUnsizedCast { - sess: fcx.tcx.sess, + fcx.dcx().emit_err(errors::CastThinPointerToFatPointer { span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), - } - .diagnostic() - .emit(); + teach: fcx.tcx.sess.teach(E0607).then_some(()), + }); } CastError::IntToFatCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 98add86252c52..e49b921e63cac 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -689,3 +689,14 @@ pub struct ReplaceWithName { pub span: Span, pub name: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)] +pub(crate) struct CastThinPointerToFatPointer<'tcx> { + #[primary_span] + pub span: Span, + pub expr_ty: Ty<'tcx>, + pub cast_ty: String, + #[note(hir_typeck_teach_help)] + pub(crate) teach: Option<()>, +} diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs new file mode 100644 index 0000000000000..d821b6a0117e6 --- /dev/null +++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs @@ -0,0 +1,4 @@ +const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) }; +//~^ ERROR: cannot cast + +fn main() {} diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr new file mode 100644 index 0000000000000..3b861d784d8b8 --- /dev/null +++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr @@ -0,0 +1,9 @@ +error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]` + --> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31 + | +LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0607`. From 14f4ed2ba3a86bbb2bca77690d036316c3d21fc8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 4 Jul 2024 13:27:24 +0000 Subject: [PATCH 150/189] Add comments to windows_targets.rs --- library/std/src/sys/pal/windows/c/windows_targets.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs index cc3cc6e861194..56c563462d366 100644 --- a/library/std/src/sys/pal/windows/c/windows_targets.rs +++ b/library/std/src/sys/pal/windows/c/windows_targets.rs @@ -1,5 +1,14 @@ +//! Provides the `link!` macro used by the generated windows bindings. +//! +//! This is a simple wrapper around an `extern` block with a `#[link]` attribute. +//! It's very roughly equivalent to the windows-targets crate. + pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't + // have in this repo. So instead we always link kernel32.lib and add the rest of the import + // libraries below by using an empty extern block. This works because extern blocks are not + // connected to the library given in the #[link] attribute. #[link(name = "kernel32")] extern $abi { $(#[link_name=$link_name])? From 0adb82528fa00467a3f14a282f4581bb30f91aba Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 4 Jul 2024 22:05:00 +0800 Subject: [PATCH 151/189] Improve dead code analysis --- compiler/rustc_passes/src/dead.rs | 40 ++++++------------- library/core/src/default.rs | 1 - .../salsa-macros/src/database_storage.rs | 8 ---- tests/ui-fulldeps/deriving-global.rs | 3 ++ tests/ui-fulldeps/deriving-hygiene.rs | 1 + .../ui/const-generics/issues/issue-86535-2.rs | 1 + tests/ui/const-generics/issues/issue-86535.rs | 1 + .../impl-trait/extra-impl-in-trait-impl.fixed | 2 + .../ui/impl-trait/extra-impl-in-trait-impl.rs | 2 + .../extra-impl-in-trait-impl.stderr | 8 ++-- tests/ui/lint/dead-code/issue-59003.rs | 2 +- .../lint-unused-adt-appeared-in-pattern.rs | 37 +++++++++++++++++ ...lint-unused-adt-appeared-in-pattern.stderr | 20 ++++++++++ .../not-lint-used-adt-appeared-in-pattern.rs | 32 +++++++++++++++ ...sed-adt-impl-pub-trait-with-assoc-const.rs | 36 +++++++++++------ ...adt-impl-pub-trait-with-assoc-const.stderr | 24 +++++++++-- .../dead-code/unused-struct-derive-default.rs | 1 + .../unused-struct-derive-default.stderr | 1 - tests/ui/parser/issues/issue-105366.fixed | 1 + tests/ui/parser/issues/issue-105366.rs | 1 + tests/ui/parser/issues/issue-105366.stderr | 2 +- 21 files changed, 164 insertions(+), 60 deletions(-) create mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs create mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr create mode 100644 tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bbd586386dd27..0d55a6777647d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -277,7 +277,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { pats: &[hir::PatField<'_>], ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; for pat in pats { @@ -297,7 +300,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { dotdot: hir::DotDotPos, ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => { self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); return; @@ -402,31 +408,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return false; } - // don't ignore impls for Enums and pub Structs whose methods don't have self receiver, - // cause external crate may call such methods to construct values of these types - if let Some(local_impl_of) = impl_of.as_local() - && let Some(local_def_id) = def_id.as_local() - && let Some(fn_sig) = - self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) - && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) - && let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind - && let Res::Def(def_kind, did) = path.res - { - match def_kind { - // for example, #[derive(Default)] pub struct T(i32); - // external crate can call T::default() to construct T, - // so that don't ignore impl Default for pub Enum and Structs - DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => { - return false; - } - // don't ignore impl Default for Enums, - // cause we don't know which variant is constructed - DefKind::Enum => return false, - _ => (), - }; - } - if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { @@ -690,6 +671,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.handle_field_pattern_match(pat, res, fields); } PatKind::Path(ref qpath) => { + if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() { + self.check_def_id(adt.did()); + } let res = self.typeck_results().qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -845,7 +829,7 @@ fn check_item<'tcx>( // mark the method live if the self_ty is public, // or the method is public and may construct self if tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self)) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 5cacedcb241a5..4524b352ec817 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar; /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Default")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Default: Sized { /// Returns the "default value" for a type. /// diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs index 14238e2fed55d..f16d814b9f038 100644 --- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs +++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs @@ -241,11 +241,3 @@ impl Parse for QueryGroup { Ok(QueryGroup { group_path }) } } - -struct Nothing; - -impl Parse for Nothing { - fn parse(_input: ParseStream<'_>) -> syn::Result { - Ok(Nothing) - } -} diff --git a/tests/ui-fulldeps/deriving-global.rs b/tests/ui-fulldeps/deriving-global.rs index 7783010be441d..0ba149c9ad654 100644 --- a/tests/ui-fulldeps/deriving-global.rs +++ b/tests/ui-fulldeps/deriving-global.rs @@ -17,18 +17,21 @@ mod submod { // if any of these are implemented without global calls for any // function calls, then being in a submodule will (correctly) // cause errors about unrecognised module `std` (or `extra`) + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] enum A { A1(usize), A2(isize), } + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct B { x: usize, y: isize, } + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct C(usize, isize); } diff --git a/tests/ui-fulldeps/deriving-hygiene.rs b/tests/ui-fulldeps/deriving-hygiene.rs index a3a6f9e022ebb..f948d6ac544e5 100644 --- a/tests/ui-fulldeps/deriving-hygiene.rs +++ b/tests/ui-fulldeps/deriving-hygiene.rs @@ -20,6 +20,7 @@ pub const s: u8 = 1; pub const state: u8 = 1; pub const cmp: u8 = 1; +#[allow(dead_code)] #[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)] struct Foo {} diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs index 1ba3b6d5347c0..bd9431dbc85b5 100644 --- a/tests/ui/const-generics/issues/issue-86535-2.rs +++ b/tests/ui/const-generics/issues/issue-86535-2.rs @@ -7,6 +7,7 @@ pub trait Foo { fn foo() where [(); Self::ASSOC_C]:; } +#[allow(dead_code)] struct Bar; impl Foo for Bar { const ASSOC_C: usize = 3; diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs index dd6bc88ad198f..cd9934a4a9971 100644 --- a/tests/ui/const-generics/issues/issue-86535.rs +++ b/tests/ui/const-generics/issues/issue-86535.rs @@ -2,6 +2,7 @@ #![feature(adt_const_params, generic_const_exprs)] #![allow(incomplete_features, unused_variables)] +#[allow(dead_code)] struct F; impl X for F<{ S }> { const W: usize = 3; diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed index 886fc1d005802..3c4499f017337 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed @@ -1,6 +1,8 @@ //@ run-rustfix +#[allow(dead_code)] struct S(T); +#[allow(dead_code)] struct S2; impl Default for S { diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs index f3271993867cb..ac0783295242e 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs @@ -1,6 +1,8 @@ //@ run-rustfix +#[allow(dead_code)] struct S(T); +#[allow(dead_code)] struct S2; impl impl Default for S { diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr index 5aafc8b64d4ff..91c7da5a04fb4 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -1,23 +1,23 @@ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:6:18 + --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:6:18 + --> $DIR/extra-impl-in-trait-impl.rs:8:18 | LL | impl impl Default for S { | ^^^^^^^^^^^^ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:12:6 + --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:12:6 + --> $DIR/extra-impl-in-trait-impl.rs:14:6 | LL | impl impl Default for S2 { | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs index e3dcaca577889..319cf2db1495f 100644 --- a/tests/ui/lint/dead-code/issue-59003.rs +++ b/tests/ui/lint/dead-code/issue-59003.rs @@ -4,8 +4,8 @@ #![deny(dead_code)] +#[allow(dead_code)] struct Foo { - #[allow(dead_code)] inner: u32, } diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs new file mode 100644 index 0000000000000..25777438456b6 --- /dev/null +++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs @@ -0,0 +1,37 @@ +#![deny(dead_code)] + +struct Foo(u8); //~ ERROR struct `Foo` is never constructed + +enum Bar { //~ ERROR enum `Bar` is never used + Var1(u8), + Var2(u8), +} + +pub trait Tr1 { + fn f1() -> Self; +} + +impl Tr1 for Foo { + fn f1() -> Foo { + let f = Foo(0); + let Foo(tag) = f; + Foo(tag) + } +} + +impl Tr1 for Bar { + fn f1() -> Bar { + let b = Bar::Var1(0); + let b = if let Bar::Var1(_) = b { + Bar::Var1(0) + } else { + Bar::Var2(0) + }; + match b { + Bar::Var1(_) => Bar::Var2(0), + Bar::Var2(_) => Bar::Var1(0), + } + } +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr new file mode 100644 index 0000000000000..7c1a4b4597755 --- /dev/null +++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr @@ -0,0 +1,20 @@ +error: struct `Foo` is never constructed + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8 + | +LL | struct Foo(u8); + | ^^^ + | +note: the lint level is defined here + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: enum `Bar` is never used + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6 + | +LL | enum Bar { + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs new file mode 100644 index 0000000000000..43a2e43190433 --- /dev/null +++ b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![deny(dead_code)] + +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum RecordField { + Target = 1, + Level, + Module, + File, + Line, + NumArgs, +} + +unsafe trait Pod {} + +#[repr(transparent)] +struct RecordFieldWrapper(RecordField); + +unsafe impl Pod for RecordFieldWrapper {} + +fn try_read(buf: &[u8]) -> T { + unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) } +} + +pub fn foo(buf: &[u8]) -> RecordField { + let RecordFieldWrapper(tag) = try_read(buf); + tag +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs index bf2fc243e8194..658cc3d6c613a 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs @@ -1,8 +1,9 @@ #![deny(dead_code)] struct T1; //~ ERROR struct `T1` is never constructed -pub struct T2(i32); //~ ERROR struct `T2` is never constructed -struct T3; +struct T2; //~ ERROR struct `T2` is never constructed +pub struct T3(i32); //~ ERROR struct `T3` is never constructed +pub struct T4(i32); //~ ERROR field `0` is never read trait Trait1 { //~ ERROR trait `Trait1` is never used const UNUSED: i32; @@ -11,13 +12,13 @@ trait Trait1 { //~ ERROR trait `Trait1` is never used } pub trait Trait2 { - const USED: i32; - fn used(&self) {} + const MAY_USED: i32; + fn may_used(&self) {} } pub trait Trait3 { - const USED: i32; - fn construct_self() -> Self; + const MAY_USED: i32; + fn may_used() -> Self; } impl Trait1 for T1 { @@ -30,23 +31,34 @@ impl Trait1 for T1 { impl Trait1 for T2 { const UNUSED: i32 = 0; fn construct_self() -> Self { - T2(0) + Self } } impl Trait2 for T1 { - const USED: i32 = 0; + const MAY_USED: i32 = 0; } impl Trait2 for T2 { - const USED: i32 = 0; + const MAY_USED: i32 = 0; } -impl Trait3 for T3 { - const USED: i32 = 0; - fn construct_self() -> Self { +impl Trait2 for T3 { + const MAY_USED: i32 = 0; +} + +impl Trait3 for T2 { + const MAY_USED: i32 = 0; + fn may_used() -> Self { Self } } +impl Trait3 for T4 { + const MAY_USED: i32 = 0; + fn may_used() -> Self { + T4(0) + } +} + fn main() {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr index 174096d939883..08c7a5cb4b062 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr @@ -11,16 +11,32 @@ LL | #![deny(dead_code)] | ^^^^^^^^^ error: struct `T2` is never constructed - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:12 + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8 | -LL | pub struct T2(i32); +LL | struct T2; + | ^^ + +error: struct `T3` is never constructed + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:12 + | +LL | pub struct T3(i32); | ^^ +error: field `0` is never read + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15 + | +LL | pub struct T4(i32); + | -- ^^^ + | | + | field in this struct + | + = help: consider removing this field + error: trait `Trait1` is never used - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7 + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:8:7 | LL | trait Trait1 { | ^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs index 330ad32dd5709..f20b7cb66ee51 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.rs +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs @@ -22,4 +22,5 @@ pub struct T2 { fn main() { let _x: Used = Default::default(); + let _e: E = Default::default(); } diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr index bbb0bd7be7064..7422f9a39f312 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr @@ -4,7 +4,6 @@ error: struct `T` is never constructed LL | struct T; | ^ | - = note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/unused-struct-derive-default.rs:1:9 | diff --git a/tests/ui/parser/issues/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed index 7157b647524dd..95419dc07f2cc 100644 --- a/tests/ui/parser/issues/issue-105366.fixed +++ b/tests/ui/parser/issues/issue-105366.fixed @@ -1,5 +1,6 @@ //@ run-rustfix +#[allow(dead_code)] struct Foo; impl From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs index dc3cb8b343d32..3278b73799125 100644 --- a/tests/ui/parser/issues/issue-105366.rs +++ b/tests/ui/parser/issues/issue-105366.rs @@ -1,5 +1,6 @@ //@ run-rustfix +#[allow(dead_code)] struct Foo; fn From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr index 18c04dfaf2088..195305a2ec889 100644 --- a/tests/ui/parser/issues/issue-105366.stderr +++ b/tests/ui/parser/issues/issue-105366.stderr @@ -1,5 +1,5 @@ error: you might have meant to write `impl` instead of `fn` - --> $DIR/issue-105366.rs:5:1 + --> $DIR/issue-105366.rs:6:1 | LL | fn From for Foo { | ^^ From 40cad01f2f9d830aeb798057a0aeb761316ebf28 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 19 Jun 2024 13:25:29 -0400 Subject: [PATCH 152/189] rewrite and rename include_bytes_deps to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - .../input.bin | 0 .../input.md | 0 .../input.txt | 0 .../main.rs | 0 tests/run-make/include-bytes-deps/rmake.rs | 15 +++++++++++++++ tests/run-make/include_bytes_deps/Makefile | 7 ------- 7 files changed, 15 insertions(+), 8 deletions(-) rename tests/run-make/{include_bytes_deps => include-bytes-deps}/input.bin (100%) rename tests/run-make/{include_bytes_deps => include-bytes-deps}/input.md (100%) rename tests/run-make/{include_bytes_deps => include-bytes-deps}/input.txt (100%) rename tests/run-make/{include_bytes_deps => include-bytes-deps}/main.rs (100%) create mode 100644 tests/run-make/include-bytes-deps/rmake.rs delete mode 100644 tests/run-make/include_bytes_deps/Makefile diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2da4e476e9016..6d13559818669 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -46,7 +46,6 @@ run-make/fmt-write-bloat/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile -run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile run-make/interdependent-c-libraries/Makefile diff --git a/tests/run-make/include_bytes_deps/input.bin b/tests/run-make/include-bytes-deps/input.bin similarity index 100% rename from tests/run-make/include_bytes_deps/input.bin rename to tests/run-make/include-bytes-deps/input.bin diff --git a/tests/run-make/include_bytes_deps/input.md b/tests/run-make/include-bytes-deps/input.md similarity index 100% rename from tests/run-make/include_bytes_deps/input.md rename to tests/run-make/include-bytes-deps/input.md diff --git a/tests/run-make/include_bytes_deps/input.txt b/tests/run-make/include-bytes-deps/input.txt similarity index 100% rename from tests/run-make/include_bytes_deps/input.txt rename to tests/run-make/include-bytes-deps/input.txt diff --git a/tests/run-make/include_bytes_deps/main.rs b/tests/run-make/include-bytes-deps/main.rs similarity index 100% rename from tests/run-make/include_bytes_deps/main.rs rename to tests/run-make/include-bytes-deps/main.rs diff --git a/tests/run-make/include-bytes-deps/rmake.rs b/tests/run-make/include-bytes-deps/rmake.rs new file mode 100644 index 0000000000000..6ca29fa664c98 --- /dev/null +++ b/tests/run-make/include-bytes-deps/rmake.rs @@ -0,0 +1,15 @@ +// include_bytes! and include_str! in `main.rs` +// should register the included file as of #24423, +// and this test checks that this is still the case. +// See https://github.com/rust-lang/rust/pull/24423 + +//FIXME(Oneirical): check if works without ignore freebsd + +use run_make_support::{invalid_utf8_contains, rustc}; + +fn main() { + rustc().emit("dep-info").input("main.rs").run(); + invalid_utf8_contains("main.d", "input.txt"); + invalid_utf8_contains("main.d", "input.bin"); + invalid_utf8_contains("main.d", "input.md"); +} diff --git a/tests/run-make/include_bytes_deps/Makefile b/tests/run-make/include_bytes_deps/Makefile deleted file mode 100644 index 696dfd207bbff..0000000000000 --- a/tests/run-make/include_bytes_deps/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# ignore-freebsd - -all: - $(RUSTC) --emit dep-info main.rs - $(CGREP) "input.txt" "input.bin" "input.md" < $(TMPDIR)/main.d From 73d7dc7f220c8e451defc1f3817b99ed70079a4e Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 19 Jun 2024 14:06:17 -0400 Subject: [PATCH 153/189] rewrite optimization-remarks-dir-pgo to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../optimization-remarks-dir-pgo/Makefile | 17 ----------------- .../optimization-remarks-dir-pgo/rmake.rs | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 18 deletions(-) delete mode 100644 tests/run-make/optimization-remarks-dir-pgo/Makefile create mode 100644 tests/run-make/optimization-remarks-dir-pgo/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6d13559818669..e26a1326f443a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -101,7 +101,6 @@ run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile run-make/obey-crate-type-flag/Makefile -run-make/optimization-remarks-dir-pgo/Makefile run-make/optimization-remarks-dir/Makefile run-make/output-type-permutations/Makefile run-make/panic-abort-eh_frame/Makefile diff --git a/tests/run-make/optimization-remarks-dir-pgo/Makefile b/tests/run-make/optimization-remarks-dir-pgo/Makefile deleted file mode 100644 index 57ffd6e70f00b..0000000000000 --- a/tests/run-make/optimization-remarks-dir-pgo/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# needs-profiler-support -# ignore-cross-compile - -include ../tools.mk - -PROFILE_DIR=$(TMPDIR)/profiles - -check_hotness: - $(RUSTC) -Cprofile-generate="$(TMPDIR)"/profdata -O foo.rs -o$(TMPDIR)/foo - $(TMPDIR)/foo - "$(LLVM_BIN_DIR)"/llvm-profdata merge \ - -o "$(TMPDIR)"/merged.profdata \ - "$(TMPDIR)"/profdata/*.profraw - $(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata -O foo.rs -Cremark=all -Zremark-dir=$(PROFILE_DIR) - - # Check that PGO hotness is included in the remark files - cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e "Hotness" diff --git a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs new file mode 100644 index 0000000000000..678d9c2de8b40 --- /dev/null +++ b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs @@ -0,0 +1,19 @@ +// This test checks the -Zremark-dir flag, which writes LLVM +// optimization remarks to the YAML format. When using PGO (Profile +// Guided Optimization), the Hotness attribute should be included in +// the output remark files. +// See https://github.com/rust-lang/rust/pull/114439 + +//@ needs-profiler-support +//@ ignore-cross-compile + +use run_make_support::{run, llvm_profdata, rustc, invalid_utf8_contains}; + +fn main() { + rustc().profile_generate("profdata").opt().input("foo.rs").output("foo").run(); + run("foo"); + llvm_profdata().merge().output("merged.profdata").input("profdata/default_15907418011457399462_0.profraw").run(); + rustc().profile_use("merged.profdata").opt().input("foo.rs").arg("-Cremark=all").arg("-Zremark-dir=profiles").run(); + // Check that PGO hotness is included in the remark files + invalid_utf8_contains("profiles/foo.cba44757bc0621b9-cgu.0.opt.opt.yaml", "Hotness"); +} From 651f02363d96ce75ae297d70104153a8b3b0981f Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 19 Jun 2024 14:30:47 -0400 Subject: [PATCH 154/189] rewrite optimization-remarks-dir to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../optimization-remarks-dir-pgo/rmake.rs | 16 +++++++++--- .../optimization-remarks-dir/Makefile | 12 --------- .../optimization-remarks-dir/rmake.rs | 26 +++++++++++++++++++ 4 files changed, 39 insertions(+), 16 deletions(-) delete mode 100644 tests/run-make/optimization-remarks-dir/Makefile create mode 100644 tests/run-make/optimization-remarks-dir/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index e26a1326f443a..4516bf86e2b35 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -101,7 +101,6 @@ run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile run-make/obey-crate-type-flag/Makefile -run-make/optimization-remarks-dir/Makefile run-make/output-type-permutations/Makefile run-make/panic-abort-eh_frame/Makefile run-make/pass-linker-flags-flavor/Makefile diff --git a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs index 678d9c2de8b40..e527dcb0befa5 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs +++ b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs @@ -7,13 +7,23 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{run, llvm_profdata, rustc, invalid_utf8_contains}; +use run_make_support::{invalid_utf8_contains, llvm_profdata, run, rustc}; fn main() { rustc().profile_generate("profdata").opt().input("foo.rs").output("foo").run(); run("foo"); - llvm_profdata().merge().output("merged.profdata").input("profdata/default_15907418011457399462_0.profraw").run(); - rustc().profile_use("merged.profdata").opt().input("foo.rs").arg("-Cremark=all").arg("-Zremark-dir=profiles").run(); + llvm_profdata() + .merge() + .output("merged.profdata") + .input("profdata/default_15907418011457399462_0.profraw") + .run(); + rustc() + .profile_use("merged.profdata") + .opt() + .input("foo.rs") + .arg("-Cremark=all") + .arg("-Zremark-dir=profiles") + .run(); // Check that PGO hotness is included in the remark files invalid_utf8_contains("profiles/foo.cba44757bc0621b9-cgu.0.opt.opt.yaml", "Hotness"); } diff --git a/tests/run-make/optimization-remarks-dir/Makefile b/tests/run-make/optimization-remarks-dir/Makefile deleted file mode 100644 index a8342c8ad14d5..0000000000000 --- a/tests/run-make/optimization-remarks-dir/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -PROFILE_DIR=$(TMPDIR)/profiles - -all: check_inline check_filter - -check_inline: - $(RUSTC) -O foo.rs --crate-type=lib -Cremark=all -Zremark-dir=$(PROFILE_DIR) - cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e "inline" -check_filter: - $(RUSTC) -O foo.rs --crate-type=lib -Cremark=foo -Zremark-dir=$(PROFILE_DIR) - cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e -v "inline" diff --git a/tests/run-make/optimization-remarks-dir/rmake.rs b/tests/run-make/optimization-remarks-dir/rmake.rs new file mode 100644 index 0000000000000..d0c4ccd72d13a --- /dev/null +++ b/tests/run-make/optimization-remarks-dir/rmake.rs @@ -0,0 +1,26 @@ +// In this test, the function `bar` has #[inline(never)] and the function `foo` +// does not. This test outputs LLVM optimization remarks twice - first for all +// functions (including `bar`, and the `inline` mention), and then for only `foo` +// (should not have the `inline` mention). +// See https://github.com/rust-lang/rust/pull/113040 + +use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rustc}; + +fn main() { + rustc() + .opt() + .input("foo.rs") + .crate_type("lib") + .arg("-Cremark=all") + .arg("-Zremark-dir=profiles_all") + .run(); + invalid_utf8_contains("profiles_all/foo.5be5606e1f6aa79b-cgu.0.opt.opt.yaml", "inline"); + rustc() + .opt() + .input("foo.rs") + .crate_type("lib") + .arg("-Cremark=foo") + .arg("-Zremark-dir=profiles_foo") + .run(); + invalid_utf8_not_contains("profiles_foo/foo.5be5606e1f6aa79b-cgu.0.opt.opt.yaml", "inline"); +} From 5e23dfea9dee65b8a5b7ed54354b4c46d38f12ca Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 19 Jun 2024 14:55:22 -0400 Subject: [PATCH 155/189] rewrite and rename issue-40535 to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-40535/Makefile | 13 ------------- .../bar.rs | 0 .../baz.rs | 0 .../foo.rs | 0 tests/run-make/metadata-only-crate-no-ice/rmake.rs | 14 ++++++++++++++ 6 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/issue-40535/Makefile rename tests/run-make/{issue-40535 => metadata-only-crate-no-ice}/bar.rs (100%) rename tests/run-make/{issue-40535 => metadata-only-crate-no-ice}/baz.rs (100%) rename tests/run-make/{issue-40535 => metadata-only-crate-no-ice}/foo.rs (100%) create mode 100644 tests/run-make/metadata-only-crate-no-ice/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4516bf86e2b35..4fbfa442fcc54 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -63,7 +63,6 @@ run-make/issue-33329/Makefile run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-37839/Makefile -run-make/issue-40535/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile diff --git a/tests/run-make/issue-40535/Makefile b/tests/run-make/issue-40535/Makefile deleted file mode 100644 index 155c88252144d..0000000000000 --- a/tests/run-make/issue-40535/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -include ../tools.mk - -# The ICE occurred in the following situation: -# * `foo` declares `extern crate bar, baz`, depends only on `bar` (forgetting `baz` in `Cargo.toml`) -# * `bar` declares and depends on `extern crate baz` -# * All crates built in metadata-only mode (`cargo check`) -all: - # cc https://github.com/rust-lang/rust/issues/40623 - $(RUSTC) baz.rs --emit=metadata - $(RUSTC) bar.rs --emit=metadata --extern baz=$(TMPDIR)/libbaz.rmeta - $(RUSTC) foo.rs --emit=metadata --extern bar=$(TMPDIR)/libbar.rmeta 2>&1 | \ - $(CGREP) -v "unexpectedly panicked" - # ^ Succeeds if it doesn't find the ICE message diff --git a/tests/run-make/issue-40535/bar.rs b/tests/run-make/metadata-only-crate-no-ice/bar.rs similarity index 100% rename from tests/run-make/issue-40535/bar.rs rename to tests/run-make/metadata-only-crate-no-ice/bar.rs diff --git a/tests/run-make/issue-40535/baz.rs b/tests/run-make/metadata-only-crate-no-ice/baz.rs similarity index 100% rename from tests/run-make/issue-40535/baz.rs rename to tests/run-make/metadata-only-crate-no-ice/baz.rs diff --git a/tests/run-make/issue-40535/foo.rs b/tests/run-make/metadata-only-crate-no-ice/foo.rs similarity index 100% rename from tests/run-make/issue-40535/foo.rs rename to tests/run-make/metadata-only-crate-no-ice/foo.rs diff --git a/tests/run-make/metadata-only-crate-no-ice/rmake.rs b/tests/run-make/metadata-only-crate-no-ice/rmake.rs new file mode 100644 index 0000000000000..825da12cfd1bc --- /dev/null +++ b/tests/run-make/metadata-only-crate-no-ice/rmake.rs @@ -0,0 +1,14 @@ +// In a dependency hierarchy, metadata-only crates could cause an Internal +// Compiler Error (ICE) due to a compiler bug - not correctly fetching sources for +// metadata-only crates. This test is a minimal reproduction of a program that triggered +// this bug, and checks that no ICE occurs. +// See https://github.com/rust-lang/rust/issues/40535 + +use run_make_support::rustc; + +fn main() { + rustc().input("baz.rs").emit("metadata").run(); + rustc().input("bar.rs").emit("metadata").extern_("baz", "libbaz.rmeta").run(); + // There should be no internal compiler error message. + rustc().input("foo.rs").emit("metadata").extern_("bar", "libbaz.rmeta").run().assert_stderr_not_contains("unexpectedly panicked"); +} From b167a15d64c0777afa6b90d7883368c629049a16 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 19 Jun 2024 15:46:27 -0400 Subject: [PATCH 156/189] rewrite rmeta-preferred to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/include-bytes-deps/rmake.rs | 2 -- .../metadata-only-crate-no-ice/rmake.rs | 4 ++-- tests/run-make/rmeta-preferred/Makefile | 16 ---------------- tests/run-make/rmeta-preferred/rmake.rs | 18 ++++++++++++++++++ 5 files changed, 20 insertions(+), 21 deletions(-) delete mode 100644 tests/run-make/rmeta-preferred/Makefile create mode 100644 tests/run-make/rmeta-preferred/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4fbfa442fcc54..70c1b055c6e40 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -132,7 +132,6 @@ run-make/return-non-c-like-enum-from-c/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile -run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile diff --git a/tests/run-make/include-bytes-deps/rmake.rs b/tests/run-make/include-bytes-deps/rmake.rs index 6ca29fa664c98..ea371ddae5675 100644 --- a/tests/run-make/include-bytes-deps/rmake.rs +++ b/tests/run-make/include-bytes-deps/rmake.rs @@ -3,8 +3,6 @@ // and this test checks that this is still the case. // See https://github.com/rust-lang/rust/pull/24423 -//FIXME(Oneirical): check if works without ignore freebsd - use run_make_support::{invalid_utf8_contains, rustc}; fn main() { diff --git a/tests/run-make/metadata-only-crate-no-ice/rmake.rs b/tests/run-make/metadata-only-crate-no-ice/rmake.rs index 825da12cfd1bc..e6f852fca413a 100644 --- a/tests/run-make/metadata-only-crate-no-ice/rmake.rs +++ b/tests/run-make/metadata-only-crate-no-ice/rmake.rs @@ -9,6 +9,6 @@ use run_make_support::rustc; fn main() { rustc().input("baz.rs").emit("metadata").run(); rustc().input("bar.rs").emit("metadata").extern_("baz", "libbaz.rmeta").run(); - // There should be no internal compiler error message. - rustc().input("foo.rs").emit("metadata").extern_("bar", "libbaz.rmeta").run().assert_stderr_not_contains("unexpectedly panicked"); + // There should be no internal compiler error. + rustc().input("foo.rs").emit("metadata").extern_("bar", "libbaz.rmeta").run(); } diff --git a/tests/run-make/rmeta-preferred/Makefile b/tests/run-make/rmeta-preferred/Makefile deleted file mode 100644 index 3bf12cced29ab..0000000000000 --- a/tests/run-make/rmeta-preferred/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that using rlibs and rmeta dep crates work together. Specifically, that -# there can be both an rmeta and an rlib file and rustc will prefer the rmeta -# file. -# -# This behavior is simply making sure this doesn't accidentally change; in this -# case we want to make sure that the rlib isn't being used as that would cause -# bugs in -Zbinary-dep-depinfo (see #68298). - -all: - $(RUSTC) rmeta_aux.rs --crate-type=rlib --emit link,metadata - $(RUSTC) lib.rs --crate-type=rlib --emit dep-info -Zbinary-dep-depinfo - $(CGREP) "librmeta_aux.rmeta" < $(TMPDIR)/lib.d - $(CGREP) -v "librmeta_aux.rlib" < $(TMPDIR)/lib.d diff --git a/tests/run-make/rmeta-preferred/rmake.rs b/tests/run-make/rmeta-preferred/rmake.rs new file mode 100644 index 0000000000000..09cba06e2f509 --- /dev/null +++ b/tests/run-make/rmeta-preferred/rmake.rs @@ -0,0 +1,18 @@ +// This test compiles `lib.rs`'s dependency, `rmeta_aux.rs`, as both an rlib +// and an rmeta crate. By default, rustc should give the metadata crate (rmeta) +// precedence over the rust-lib (rlib). This test inspects the contents of the binary +// and that the correct (rmeta) crate was used. +// rlibs being preferred could indicate a resurgence of the -Zbinary-dep-depinfo bug +// seen in #68298. +// See https://github.com/rust-lang/rust/pull/37681 + +//@ ignore-cross-compile + +use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rustc}; + +fn main() { + rustc().input("rmeta_aux.rs").crate_type("rlib").emit("link,metadata").run(); + rustc().input("lib.rs").crate_type("rlib").emit("dep-info").arg("-Zbinary-dep-depinfo").run(); + invalid_utf8_contains("lib.d", "librmeta_aux.rmeta"); + invalid_utf8_not_contains("lib.d", "librmeta_aux.rlib"); +} From 3ea36f5bb6845bc0c0737d174e49fd3ff9380708 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 20 Jun 2024 16:02:22 -0400 Subject: [PATCH 157/189] add shallow_find_files helper function to run-make-support --- src/tools/run-make-support/src/lib.rs | 34 +++++++++++++++++++ .../optimization-remarks-dir-pgo/rmake.rs | 26 ++++++++++---- .../optimization-remarks-dir/rmake.rs | 19 +++++++++-- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 9a180fe4ad19a..af5ae6a8e608c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -261,6 +261,40 @@ pub fn test_while_readonly, F: FnOnce() + std::panic::UnwindSafe> success.unwrap(); } +/// Browse the directory `path` non-recursively and return all files which respect the parameters +/// outlined by `closure`. +#[track_caller] +pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( + path: P, + closure: F, +) -> Vec { + let mut matching_files = Vec::new(); + for entry in fs_wrapper::read_dir(path) { + let entry = entry.expect("failed to read directory entry."); + let path = entry.path(); + + if path.is_file() && closure(&path) { + matching_files.push(path); + } + } + matching_files +} + +/// Returns true if the filename at `path` starts with `prefix`. +pub fn has_prefix>(path: P, prefix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) +} + +/// Returns true if the filename at `path` has the extension `extension`. +pub fn has_extension>(path: P, extension: &str) -> bool { + path.as_ref().extension().is_some_and(|ext| ext == extension) +} + +/// Returns true if the filename at `path` does not contain `expected`. +pub fn not_contains>(path: P, expected: &str) -> bool { + !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) +} + /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] diff --git a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs index e527dcb0befa5..228c43cc5f18a 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs +++ b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs @@ -7,16 +7,20 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{invalid_utf8_contains, llvm_profdata, run, rustc}; +use run_make_support::{ + has_extension, has_prefix, invalid_utf8_contains, llvm_profdata, run, rustc, shallow_find_files, +}; fn main() { rustc().profile_generate("profdata").opt().input("foo.rs").output("foo").run(); run("foo"); - llvm_profdata() - .merge() - .output("merged.profdata") - .input("profdata/default_15907418011457399462_0.profraw") - .run(); + // The profdata filename is a long sequence of numbers, fetch it by prefix and extension + // to keep the test working even if the filename changes. + let profdata_files = shallow_find_files("profdata", |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profdata_file = profdata_files.get(0).unwrap(); + llvm_profdata().merge().output("merged.profdata").input(profdata_file).run(); rustc() .profile_use("merged.profdata") .opt() @@ -25,5 +29,13 @@ fn main() { .arg("-Zremark-dir=profiles") .run(); // Check that PGO hotness is included in the remark files - invalid_utf8_contains("profiles/foo.cba44757bc0621b9-cgu.0.opt.opt.yaml", "Hotness"); + let remark_files = shallow_find_files("profiles", |path| { + has_prefix(path, "foo") && has_extension(path, "yaml") + }); + assert!(!remark_files.is_empty()); + for file in remark_files { + if !file.to_str().unwrap().contains("codegen") { + invalid_utf8_contains(file, "Hotness") + }; + } } diff --git a/tests/run-make/optimization-remarks-dir/rmake.rs b/tests/run-make/optimization-remarks-dir/rmake.rs index d0c4ccd72d13a..afcb8c3e3ebdb 100644 --- a/tests/run-make/optimization-remarks-dir/rmake.rs +++ b/tests/run-make/optimization-remarks-dir/rmake.rs @@ -4,7 +4,10 @@ // (should not have the `inline` mention). // See https://github.com/rust-lang/rust/pull/113040 -use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use run_make_support::{ + has_extension, has_prefix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains, + rustc, shallow_find_files, +}; fn main() { rustc() @@ -14,7 +17,12 @@ fn main() { .arg("-Cremark=all") .arg("-Zremark-dir=profiles_all") .run(); - invalid_utf8_contains("profiles_all/foo.5be5606e1f6aa79b-cgu.0.opt.opt.yaml", "inline"); + let all_remark_files = shallow_find_files("profiles_all", |path| { + has_prefix(path, "foo") && has_extension(path, "yaml") && not_contains(path, "codegen") + }); + for file in all_remark_files { + invalid_utf8_contains(file, "inline") + } rustc() .opt() .input("foo.rs") @@ -22,5 +30,10 @@ fn main() { .arg("-Cremark=foo") .arg("-Zremark-dir=profiles_foo") .run(); - invalid_utf8_not_contains("profiles_foo/foo.5be5606e1f6aa79b-cgu.0.opt.opt.yaml", "inline"); + let foo_remark_files = shallow_find_files("profiles_foo", |path| { + has_prefix(path, "foo") && has_extension(path, "yaml") + }); + for file in foo_remark_files { + invalid_utf8_not_contains(file, "inline") + } } From eb19e8106b5828085a46aa0b86206459c293fa70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 4 Jul 2024 23:44:10 +0200 Subject: [PATCH 158/189] crashes: add latest --- tests/crashes/126896.rs | 17 +++++++++++++++++ tests/crashes/126939.rs | 21 +++++++++++++++++++++ tests/crashes/126942.rs | 11 +++++++++++ tests/crashes/126944.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/crashes/126966.rs | 29 +++++++++++++++++++++++++++++ tests/crashes/126969.rs | 9 +++++++++ tests/crashes/126982.rs | 18 ++++++++++++++++++ tests/crashes/127222.rs | 3 +++ tests/crashes/127266.rs | 17 +++++++++++++++++ tests/crashes/127299.rs | 12 ++++++++++++ tests/crashes/127304.rs | 20 ++++++++++++++++++++ tests/crashes/127332.rs | 9 +++++++++ 12 files changed, 204 insertions(+) create mode 100644 tests/crashes/126896.rs create mode 100644 tests/crashes/126939.rs create mode 100644 tests/crashes/126942.rs create mode 100644 tests/crashes/126944.rs create mode 100644 tests/crashes/126966.rs create mode 100644 tests/crashes/126969.rs create mode 100644 tests/crashes/126982.rs create mode 100644 tests/crashes/127222.rs create mode 100644 tests/crashes/127266.rs create mode 100644 tests/crashes/127299.rs create mode 100644 tests/crashes/127304.rs create mode 100644 tests/crashes/127332.rs diff --git a/tests/crashes/126896.rs b/tests/crashes/126896.rs new file mode 100644 index 0000000000000..35bf9d5207ac1 --- /dev/null +++ b/tests/crashes/126896.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#126896 +//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes + +#![feature(type_alias_impl_trait)] +type Two<'a, 'b> = impl std::fmt::Debug; + +fn set(x: &mut isize) -> isize { + *x +} + +fn d(x: Two) { + let c1 = || set(x); + c1; +} + +fn main() { +} diff --git a/tests/crashes/126939.rs b/tests/crashes/126939.rs new file mode 100644 index 0000000000000..1edf748460604 --- /dev/null +++ b/tests/crashes/126939.rs @@ -0,0 +1,21 @@ +//@ known-bug: rust-lang/rust#126939 + +struct MySlice(bool, T); +type MySliceBool = MySlice<[bool]>; + +use std::mem; + +struct P2 { + a: T, + b: MySliceBool, +} + +macro_rules! check { + ($t:ty, $align:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + }); +} + +pub fn main() { + check!(P2, 1); +} diff --git a/tests/crashes/126942.rs b/tests/crashes/126942.rs new file mode 100644 index 0000000000000..e4adc8fab287e --- /dev/null +++ b/tests/crashes/126942.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126942 +struct Thing; + +pub trait Every { + type Assoc; +} +impl Every for Thing { + type Assoc = T; +} + +static I: ::Assoc = 3; diff --git a/tests/crashes/126944.rs b/tests/crashes/126944.rs new file mode 100644 index 0000000000000..c0c5622e26020 --- /dev/null +++ b/tests/crashes/126944.rs @@ -0,0 +1,38 @@ +//@ known-bug: rust-lang/rust#126944 +// Step 1: Create two names for a single type: `Thing` and `AlsoThing` + +struct Thing; +struct Dummy; +pub trait DummyTrait { + type DummyType; +} +impl DummyTrait for Dummy { + type DummyType = Thing; +} +type AlsoThing = ::DummyType; + +// Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject` + +pub trait SomeTrait { + type Item; +} +type TraitObject = dyn SomeTrait; +type AlsoTraitObject = dyn SomeTrait; + +// Step 3: Force the compiler to check whether the two names are the same type + +pub trait Supertrait { + type Foo; +} +pub trait Subtrait: Supertrait {} + +pub trait HasOutput { + type Output; +} + +fn foo() -> F::Output +where + F: HasOutput>, +{ + todo!() +} diff --git a/tests/crashes/126966.rs b/tests/crashes/126966.rs new file mode 100644 index 0000000000000..edeedc68c40d7 --- /dev/null +++ b/tests/crashes/126966.rs @@ -0,0 +1,29 @@ +//@ known-bug: rust-lang/rust#126966 +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom, + { + } +} + +#[repr(u32)] +enum Ox00 { + V = 0x00, +} + +#[repr(C, packed(2))] +enum OxFF { + V = 0xFF, +} + +fn test() { + union Superset { + a: Ox00, + b: OxFF, + } + + assert::is_transmutable::(); +} diff --git a/tests/crashes/126969.rs b/tests/crashes/126969.rs new file mode 100644 index 0000000000000..676563d059caf --- /dev/null +++ b/tests/crashes/126969.rs @@ -0,0 +1,9 @@ +//@ known-bug: rust-lang/rust#126969 + +struct S { + _: union { t: T }, +} + +fn f(S::<&i8> { .. }: S<&i8>) {} + +fn main() {} diff --git a/tests/crashes/126982.rs b/tests/crashes/126982.rs new file mode 100644 index 0000000000000..8522d9415eb88 --- /dev/null +++ b/tests/crashes/126982.rs @@ -0,0 +1,18 @@ +//@ known-bug: rust-lang/rust#126982 + +#![feature(coerce_unsized)] +use std::ops::CoerceUnsized; + +struct Foo { + a: T, +} + +impl CoerceUnsized for Foo {} + +union U { + a: usize, +} + +const C: U = Foo { a: 10 }; + +fn main() {} diff --git a/tests/crashes/127222.rs b/tests/crashes/127222.rs new file mode 100644 index 0000000000000..eda0ea3d9b729 --- /dev/null +++ b/tests/crashes/127222.rs @@ -0,0 +1,3 @@ +//@ known-bug: rust-lang/rust#127222 +#[marker] +trait Foo = PartialEq + Send; diff --git a/tests/crashes/127266.rs b/tests/crashes/127266.rs new file mode 100644 index 0000000000000..2bdbe03e373a9 --- /dev/null +++ b/tests/crashes/127266.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#127266 +#![feature(const_mut_refs)] +#![feature(const_refs_to_static)] + +struct Meh { + x: &'static dyn UnsafeCell, +} + +const MUH: Meh = Meh { + x: &mut *(READONLY as *mut _), +}; + +static READONLY: i32 = 0; + +trait UnsafeCell<'a> {} + +pub fn main() {} diff --git a/tests/crashes/127299.rs b/tests/crashes/127299.rs new file mode 100644 index 0000000000000..7eb78387997ab --- /dev/null +++ b/tests/crashes/127299.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#127299 +trait Qux { + fn bar() -> i32; +} + +pub struct Lint { + pub desc: &'static Qux, +} + +static FOO: &Lint = &Lint { desc: "desc" }; + +fn main() {} diff --git a/tests/crashes/127304.rs b/tests/crashes/127304.rs new file mode 100644 index 0000000000000..2975fc27f6766 --- /dev/null +++ b/tests/crashes/127304.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust #127304 +#![feature(adt_const_params)] + +trait Trait {} +impl Trait for () {} + +struct MyStr(str); +impl std::marker::ConstParamTy for MyStr {} + +fn function_with_my_str() -> &'static MyStr { + S +} + +impl MyStr { + const fn new(s: &Trait str) -> &'static MyStr {} +} + +pub fn main() { + let f = function_with_my_str::<{ MyStr::new("hello") }>(); +} diff --git a/tests/crashes/127332.rs b/tests/crashes/127332.rs new file mode 100644 index 0000000000000..5c14af01cece8 --- /dev/null +++ b/tests/crashes/127332.rs @@ -0,0 +1,9 @@ +//@ known-bug: rust-lang/rust #127332 + +async fn fun() { + enum Foo { + A { x: u32 }, + } + let orig = Foo::A { x: 5 }; + Foo::A { x: 6, ..orig }; +} From 86a19467c1da6eb9353ad878979a8f74a8b5b230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 5 Jul 2024 00:52:01 +0000 Subject: [PATCH 159/189] Tweak `-1 as usize` suggestion When writing a negative unsigned integer literal, use a verbose suggestion and account for `as` casting. --- compiler/rustc_hir_typeck/src/op.rs | 13 +++++++-- .../feature-gate-negate-unsigned.stderr | 9 ++++--- tests/ui/unsigned-literal-negation.stderr | 27 ++++++++++--------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 5a11cb7096f33..7264bc5a78d82 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -838,8 +838,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) = ex.kind { - err.span_suggestion( - ex.span, + let span = if let hir::Node::Expr(parent) = + self.tcx.parent_hir_node(ex.hir_id) + && let hir::ExprKind::Cast(..) = parent.kind + { + // `-1 as usize` -> `usize::MAX` + parent.span + } else { + ex.span + }; + err.span_suggestion_verbose( + span, format!( "you may have meant the maximum value of `{actual}`", ), diff --git a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr index d1f4ed5cb04b8..696326157ce29 100644 --- a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr +++ b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr @@ -2,12 +2,13 @@ error[E0600]: cannot apply unary operator `-` to type `usize` --> $DIR/feature-gate-negate-unsigned.rs:10:23 | LL | let _max: usize = -1; - | ^^ - | | - | cannot apply unary operator `-` - | help: you may have meant the maximum value of `usize`: `usize::MAX` + | ^^ cannot apply unary operator `-` | = note: unsigned values cannot be negated +help: you may have meant the maximum value of `usize` + | +LL | let _max: usize = usize::MAX; + | ~~~~~~~~~~ error[E0600]: cannot apply unary operator `-` to type `u8` --> $DIR/feature-gate-negate-unsigned.rs:14:14 diff --git a/tests/ui/unsigned-literal-negation.stderr b/tests/ui/unsigned-literal-negation.stderr index 0aaa8c3b72f9d..b0a730477a1b0 100644 --- a/tests/ui/unsigned-literal-negation.stderr +++ b/tests/ui/unsigned-literal-negation.stderr @@ -2,34 +2,37 @@ error[E0600]: cannot apply unary operator `-` to type `usize` --> $DIR/unsigned-literal-negation.rs:2:13 | LL | let x = -1 as usize; - | ^^ - | | - | cannot apply unary operator `-` - | help: you may have meant the maximum value of `usize`: `usize::MAX` + | ^^ cannot apply unary operator `-` | = note: unsigned values cannot be negated +help: you may have meant the maximum value of `usize` + | +LL | let x = usize::MAX; + | ~~~~~~~~~~ error[E0600]: cannot apply unary operator `-` to type `usize` --> $DIR/unsigned-literal-negation.rs:3:13 | LL | let x = (-1) as usize; - | ^^^^ - | | - | cannot apply unary operator `-` - | help: you may have meant the maximum value of `usize`: `usize::MAX` + | ^^^^ cannot apply unary operator `-` | = note: unsigned values cannot be negated +help: you may have meant the maximum value of `usize` + | +LL | let x = usize::MAX; + | ~~~~~~~~~~ error[E0600]: cannot apply unary operator `-` to type `u32` --> $DIR/unsigned-literal-negation.rs:4:18 | LL | let x: u32 = -1; - | ^^ - | | - | cannot apply unary operator `-` - | help: you may have meant the maximum value of `u32`: `u32::MAX` + | ^^ cannot apply unary operator `-` | = note: unsigned values cannot be negated +help: you may have meant the maximum value of `u32` + | +LL | let x: u32 = u32::MAX; + | ~~~~~~~~ error: aborting due to 3 previous errors From f095de4bf105e92b035a7cd64c34bcce56b7cb78 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 4 Jul 2024 23:52:49 +1000 Subject: [PATCH 160/189] coverage: Rename `mir::coverage::BranchInfo` to `CoverageInfoHi` This opens the door to collecting and storing coverage information that is unrelated to branch coverage or MC/DC. --- compiler/rustc_middle/src/mir/coverage.rs | 11 +- compiler/rustc_middle/src/mir/mod.rs | 13 ++- compiler/rustc_middle/src/mir/pretty.rs | 16 ++- .../rustc_mir_build/src/build/coverageinfo.rs | 107 ++++++++++-------- .../src/build/coverageinfo/mcdc.rs | 12 +- .../rustc_mir_build/src/build/custom/mod.rs | 2 +- .../rustc_mir_build/src/build/matches/mod.rs | 4 +- compiler/rustc_mir_build/src/build/mod.rs | 8 +- .../src/coverage/mappings.rs | 22 ++-- 9 files changed, 110 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index da25fbb0a82b3..beaaadd497d3a 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -103,7 +103,7 @@ pub enum CoverageKind { SpanMarker, /// Marks its enclosing basic block with an ID that can be referred to by - /// side data in [`BranchInfo`]. + /// side data in [`CoverageInfoHi`]. /// /// Should be erased before codegen (at some point after `InstrumentCoverage`). BlockMarker { id: BlockMarkerId }, @@ -274,10 +274,15 @@ pub struct FunctionCoverageInfo { pub mcdc_num_condition_bitmaps: usize, } -/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR. +/// Coverage information for a function, recorded during MIR building and +/// attached to the corresponding `mir::Body`. Used by the `InstrumentCoverage` +/// MIR pass. +/// +/// ("Hi" indicates that this is "high-level" information collected at the +/// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.) #[derive(Clone, Debug)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct BranchInfo { +pub struct CoverageInfoHi { /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was /// injected into the MIR body. This makes it possible to allocate per-ID /// data structures without having to scan the entire body first. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ef88b253864bd..83e3898cebfa4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -430,11 +430,12 @@ pub struct Body<'tcx> { pub tainted_by_errors: Option, - /// Branch coverage information collected during MIR building, to be used by - /// the `InstrumentCoverage` pass. + /// Coverage information collected from THIR/MIR during MIR building, + /// to be used by the `InstrumentCoverage` pass. /// - /// Only present if branch coverage is enabled and this function is eligible. - pub coverage_branch_info: Option>, + /// Only present if coverage is enabled and this function is eligible. + /// Boxed to limit space overhead in non-coverage builds. + pub coverage_info_hi: Option>, /// Per-function coverage information added by the `InstrumentCoverage` /// pass, to be used in conjunction with the coverage statements injected @@ -484,7 +485,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); @@ -515,7 +516,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors: None, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4453ce44b0371..5b2c603ce25ac 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -473,8 +473,8 @@ pub fn write_mir_intro<'tcx>( // Add an empty line before the first block is printed. writeln!(w)?; - if let Some(branch_info) = &body.coverage_branch_info { - write_coverage_branch_info(branch_info, w)?; + if let Some(coverage_info_hi) = &body.coverage_info_hi { + write_coverage_info_hi(coverage_info_hi, w)?; } if let Some(function_coverage_info) = &body.function_coverage_info { write_function_coverage_info(function_coverage_info, w)?; @@ -483,12 +483,16 @@ pub fn write_mir_intro<'tcx>( Ok(()) } -fn write_coverage_branch_info( - branch_info: &coverage::BranchInfo, +fn write_coverage_info_hi( + coverage_info_hi: &coverage::CoverageInfoHi, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::BranchInfo { branch_spans, mcdc_branch_spans, mcdc_decision_spans, .. } = - branch_info; + let coverage::CoverageInfoHi { + num_block_markers: _, + branch_spans, + mcdc_branch_spans, + mcdc_decision_spans, + } = coverage_info_hi; for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans { writeln!( diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 876faca5172ac..204ee45bfa2d7 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -2,7 +2,7 @@ use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir}; use rustc_middle::ty::TyCtxt; @@ -13,16 +13,25 @@ use crate::build::{Builder, CFG}; mod mcdc; -pub(crate) struct BranchInfoBuilder { +/// Collects coverage-related information during MIR building, to eventually be +/// turned into a function's [`CoverageInfoHi`] when MIR building is complete. +pub(crate) struct CoverageInfoBuilder { /// Maps condition expressions to their enclosing `!`, for better instrumentation. nots: FxHashMap, markers: BlockMarkerGen, - branch_spans: Vec, + /// Present if branch coverage is enabled. + branch_info: Option, + /// Present if MC/DC coverage is enabled. mcdc_info: Option, } +#[derive(Default)] +struct BranchInfo { + branch_spans: Vec, +} + #[derive(Clone, Copy)] struct NotInfo { /// When visiting the associated expression as a branch condition, treat this @@ -62,20 +71,20 @@ impl BlockMarkerGen { } } -impl BranchInfoBuilder { - /// Creates a new branch info builder, but only if branch coverage instrumentation +impl CoverageInfoBuilder { + /// Creates a new coverage info builder, but only if coverage instrumentation /// is enabled and `def_id` represents a function that is eligible for coverage. pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) { - Some(Self { - nots: FxHashMap::default(), - markers: BlockMarkerGen::default(), - branch_spans: vec![], - mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), - }) - } else { - None + if !tcx.sess.instrument_coverage() || !tcx.is_eligible_for_coverage(def_id) { + return None; } + + Some(Self { + nots: FxHashMap::default(), + markers: BlockMarkerGen::default(), + branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default), + mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), + }) } /// Unary `!` expressions inside an `if` condition are lowered by lowering @@ -88,6 +97,12 @@ impl BranchInfoBuilder { pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) { assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. }); + // The information collected by this visitor is only needed when branch + // coverage or higher is enabled. + if self.branch_info.is_none() { + return; + } + self.visit_with_not_info( thir, unary_not, @@ -137,40 +152,40 @@ impl BranchInfoBuilder { false_block, inject_block_marker, ); - } else { - let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); - let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); - - self.branch_spans.push(BranchSpan { - span: source_info.span, - true_marker, - false_marker, - }); + return; } + + // Bail out if branch coverage is not enabled. + let Some(branch_info) = self.branch_info.as_mut() else { return }; + + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); + let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); + + branch_info.branch_spans.push(BranchSpan { + span: source_info.span, + true_marker, + false_marker, + }); } - pub(crate) fn into_done(self) -> Option> { - let Self { - nots: _, - markers: BlockMarkerGen { num_block_markers }, - branch_spans, - mcdc_info, - } = self; + pub(crate) fn into_done(self) -> Box { + let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } = + self; - if num_block_markers == 0 { - assert!(branch_spans.is_empty()); - return None; - } + let branch_spans = + branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); let (mcdc_decision_spans, mcdc_branch_spans) = mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); - Some(Box::new(mir::coverage::BranchInfo { + // For simplicity, always return an info struct (without Option), even + // if there's nothing interesting in it. + Box::new(CoverageInfoHi { num_block_markers, branch_spans, mcdc_branch_spans, mcdc_decision_spans, - })) + }) } } @@ -184,7 +199,7 @@ impl<'tcx> Builder<'_, 'tcx> { block: &mut BasicBlock, ) { // Bail out if condition coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; if !self.tcx.sess.instrument_coverage_condition() { return; }; @@ -224,7 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> { ); // Separate path for handling branches when MC/DC is enabled. - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, @@ -247,12 +262,12 @@ impl<'tcx> Builder<'_, 'tcx> { mut then_block: BasicBlock, mut else_block: BasicBlock, ) { - // Bail out if branch coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + // Bail out if coverage is not enabled for this function. + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; // If this condition expression is nested within one or more `!` expressions, // replace it with the enclosing `!` collected by `visit_unary_not`. - if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) { + if let Some(&NotInfo { enclosing_not, is_flipped }) = coverage_info.nots.get(&expr_id) { expr_id = enclosing_not; if is_flipped { std::mem::swap(&mut then_block, &mut else_block); @@ -261,7 +276,7 @@ impl<'tcx> Builder<'_, 'tcx> { let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, @@ -280,13 +295,11 @@ impl<'tcx> Builder<'_, 'tcx> { true_block: BasicBlock, false_block: BasicBlock, ) { - // Bail out if branch coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; - - // FIXME(#124144) This may need special handling when MC/DC is enabled. + // Bail out if coverage is not enabled for this function. + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; let source_info = SourceInfo { span: pattern.span, scope: self.source_scope }; - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index f97e9ef60a297..3aa6e708476d5 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -250,24 +250,24 @@ impl MCDCInfoBuilder { impl Builder<'_, '_> { pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { mcdc_info.state.record_conditions(logical_op, span); } } pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default()); }; } pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { if mcdc_info.state.decision_ctx_stack.pop().is_none() { bug!("Unexpected empty decision stack"); diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index a0a512a2effcf..f6ebcbcbdc949 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -62,7 +62,7 @@ pub(super) fn build_custom_mir<'tcx>( tainted_by_errors: None, injection_phase: None, pass_count: 0, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index efed52231e3fa..e435e2f92883c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -160,8 +160,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Improve branch coverage instrumentation by noting conditions // nested within one or more `!` expressions. // (Skipped if branch coverage is not enabled.) - if let Some(branch_info) = this.coverage_branch_info.as_mut() { - branch_info.visit_unary_not(this.thir, expr_id); + if let Some(coverage_info) = this.coverage_info.as_mut() { + coverage_info.visit_unary_not(this.thir, expr_id); } let local_scope = this.local_scope(); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 601e5d4d3dc79..0f9746cb719ca 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -218,8 +218,8 @@ struct Builder<'a, 'tcx> { lint_level_roots_cache: GrowableBitSet, /// Collects additional coverage information during MIR building. - /// Only present if branch coverage is enabled and this function is eligible. - coverage_branch_info: Option, + /// Only present if coverage is enabled and this function is eligible. + coverage_info: Option, } type CaptureMap<'tcx> = SortedIndexMultiMap>; @@ -773,7 +773,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unit_temp: None, var_debug_info: vec![], lint_level_roots_cache: GrowableBitSet::new_empty(), - coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def), + coverage_info: coverageinfo::CoverageInfoBuilder::new_if_enabled(tcx, def), }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); @@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.coroutine, None, ); - body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done()); + body.coverage_info_hi = self.coverage_info.map(|b| b.into_done()); body } diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 235992ac5470d..25297245172ac 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -3,7 +3,9 @@ use std::collections::BTreeSet; use rustc_data_structures::graph::DirectedGraph; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind}; +use rustc_middle::mir::coverage::{ + BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, +}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -157,12 +159,12 @@ impl ExtractedMappings { } fn resolve_block_markers( - branch_info: &mir::coverage::BranchInfo, + coverage_info_hi: &CoverageInfoHi, mir_body: &mir::Body<'_>, ) -> IndexVec> { let mut block_markers = IndexVec::>::from_elem_n( None, - branch_info.num_block_markers, + coverage_info_hi.num_block_markers, ); // Fill out the mapping from block marker IDs to their enclosing blocks. @@ -188,11 +190,11 @@ pub(super) fn extract_branch_pairs( hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Vec { - let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] }; + let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] }; - let block_markers = resolve_block_markers(branch_info, mir_body); + let block_markers = resolve_block_markers(coverage_info_hi, mir_body); - branch_info + coverage_info_hi .branch_spans .iter() .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { @@ -222,9 +224,9 @@ pub(super) fn extract_mcdc_mappings( mcdc_branches: &mut impl Extend, mcdc_decisions: &mut impl Extend, ) { - let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return }; + let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; - let block_markers = resolve_block_markers(branch_info, mir_body); + let block_markers = resolve_block_markers(coverage_info_hi, mir_body); let bcb_from_marker = |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); @@ -243,7 +245,7 @@ pub(super) fn extract_mcdc_mappings( Some((span, true_bcb, false_bcb)) }; - mcdc_branches.extend(branch_info.mcdc_branch_spans.iter().filter_map( + mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map( |&mir::coverage::MCDCBranchSpan { span: raw_span, condition_info, @@ -257,7 +259,7 @@ pub(super) fn extract_mcdc_mappings( }, )); - mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( + mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { let span = unexpand_into_body_span(decision.span, body_span)?; From f96f4436310d889da0ace73659f73500cc6c93c3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 5 Jul 2024 13:07:30 +1000 Subject: [PATCH 161/189] Tweak how the extra newline is printed after coverage info --- compiler/rustc_middle/src/mir/pretty.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5b2c603ce25ac..af19ed95193a7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -494,11 +494,15 @@ fn write_coverage_info_hi( mcdc_decision_spans, } = coverage_info_hi; + // Only add an extra trailing newline if we printed at least one thing. + let mut did_print = false; + for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans { writeln!( w, "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", )?; + did_print = true; } for coverage::MCDCBranchSpan { @@ -514,6 +518,7 @@ fn write_coverage_info_hi( "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}", condition_info.map(|info| info.condition_id) )?; + did_print = true; } for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in @@ -523,10 +528,10 @@ fn write_coverage_info_hi( w, "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" )?; + did_print = true; } - if !branch_spans.is_empty() || !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty() - { + if did_print { writeln!(w)?; } From 3e4368053ffa72183f32c2c7c790cd6b29713f95 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Jul 2024 12:04:32 +0200 Subject: [PATCH 162/189] Improve `Command::args` API in `run-make-support` --- src/tools/run-make-support/src/command.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index ee651704c6fd0..c506c3d6b61a2 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -75,11 +75,12 @@ impl Command { /// Generic command arguments provider. Prefer specific helper methods if possible. /// Note that for some executables, arguments might be platform specific. For C/C++ /// compilers, arguments might be platform *and* compiler specific. - pub fn args(&mut self, args: &[S]) -> &mut Self + pub fn args(&mut self, args: V) -> &mut Self where S: AsRef, + V: AsRef<[S]>, { - self.cmd.args(args); + self.cmd.args(args.as_ref()); self } From 415e202c48d349dae9ad138c3adb78dc51d5ad9c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Jul 2024 11:19:52 +0200 Subject: [PATCH 163/189] Improve code of `run-make/llvm-ident` test --- tests/run-make/llvm-ident/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/llvm-ident/rmake.rs b/tests/run-make/llvm-ident/rmake.rs index f460829288e8c..6934a4b36d013 100644 --- a/tests/run-make/llvm-ident/rmake.rs +++ b/tests/run-make/llvm-ident/rmake.rs @@ -28,7 +28,7 @@ fn main() { files.push(path.to_path_buf()); } }); - cmd(llvm_bin_dir().join("llvm-dis")).args(&files).run(); + cmd(llvm_bin_dir().join("llvm-dis")).args(files).run(); // Check LLVM IR files (including temporary outputs) have `!llvm.ident` // named metadata, reusing the related codegen test. From 4abc51a2196657adb20f1a83fb7c04063c7c7586 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 5 Jul 2024 14:05:29 +0200 Subject: [PATCH 164/189] Improve readability of some fmt code examples --- library/core/src/fmt/mod.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index d0e188dfcd1d8..25ab5b2db9641 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -517,7 +517,10 @@ impl Display for Arguments<'_> { /// /// let origin = Point { x: 0, y: 0 }; /// -/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }"); +/// assert_eq!( +/// format!("The origin is: {origin:?}"), +/// "The origin is: Point { x: 0, y: 0 }", +/// ); /// ``` /// /// Manually implementing: @@ -541,7 +544,10 @@ impl Display for Arguments<'_> { /// /// let origin = Point { x: 0, y: 0 }; /// -/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }"); +/// assert_eq!( +/// format!("The origin is: {origin:?}"), +/// "The origin is: Point { x: 0, y: 0 }", +/// ); /// ``` /// /// There are a number of helper methods on the [`Formatter`] struct to help you with manual @@ -582,11 +588,11 @@ impl Display for Arguments<'_> { /// /// let origin = Point { x: 0, y: 0 }; /// -/// assert_eq!(format!("The origin is: {origin:#?}"), -/// "The origin is: Point { +/// let expected = "The origin is: Point { /// x: 0, /// y: 0, -/// }"); +/// }"; +/// assert_eq!(format!("The origin is: {origin:#?}"), expected); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -738,8 +744,10 @@ pub trait Display { /// } /// } /// - /// assert_eq!("(1.987, 2.983)", - /// format!("{}", Position { longitude: 1.987, latitude: 2.983, })); + /// assert_eq!( + /// "(1.987, 2.983)", + /// format!("{}", Position { longitude: 1.987, latitude: 2.983, }), + /// ); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; From 3d699a4fa1eee76a8d8951e449d5df37061af658 Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 5 Jul 2024 22:06:57 +0800 Subject: [PATCH 165/189] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index e6a6470d1eb4c..c54cff0e6e4d1 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit e6a6470d1eb4c88fee4b1ea98cd8e0ac4a181c16 +Subproject commit c54cff0e6e4d1a0d0a2df7c1ce3d96cdd554763e From f763d621494d2f6358c3e774596468275e6ad046 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 5 Jul 2024 14:14:35 +0000 Subject: [PATCH 166/189] Fix a few doc comment for compiler-interal API docs. They only used `//` instead of `///` so weren't picked up by rustdoc. --- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 2 +- .../src/elaborate_drops.rs | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index b6e9000ef9506..c99e8a7fe8ecf 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -18,7 +18,7 @@ use rustc_trait_selection::traits::{ use std::cell::RefCell; use std::ops::Deref; -// Data shared between a "typeck root" and its nested bodies, +/// Data shared between a "typeck root" and its nested bodies, /// e.g. closures defined within the function. For example: /// ```ignore (illustrative) /// fn foo() { diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index fbbb8c5e47245..25bebb0539a4f 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -33,16 +33,16 @@ use std::fmt; /// as it would allow running a destructor on a place behind a reference: /// /// ```text -// fn drop_term(t: &mut T) { -// mir! { -// { -// Drop(*t, exit) -// } -// exit = { -// Return() -// } -// } -// } +/// fn drop_term(t: &mut T) { +/// mir! { +/// { +/// Drop(*t, exit) +/// } +/// exit = { +/// Return() +/// } +/// } +/// } /// ``` pub struct ElaborateDrops; From 1e4d821136033fb08ac5140127f37f35ff687273 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 13:22:02 -0400 Subject: [PATCH 167/189] rewrite pgo-gen to rmake --- src/tools/run-make-support/src/lib.rs | 1 - .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/pgo-gen/Makefile | 11 ----------- tests/run-make/pgo-gen/rmake.rs | 18 ++++++++++++++++++ 4 files changed, 18 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/pgo-gen/Makefile create mode 100644 tests/run-make/pgo-gen/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index af5ae6a8e608c..6c1bcc6d7cd90 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -272,7 +272,6 @@ pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( for entry in fs_wrapper::read_dir(path) { let entry = entry.expect("failed to read directory entry."); let path = entry.path(); - if path.is_file() && closure(&path) { matching_files.push(path); } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 70c1b055c6e40..97990e5923561 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -109,7 +109,6 @@ run-make/pass-non-c-like-enum-to-c/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-gen-no-imp-symbols/Makefile -run-make/pgo-gen/Makefile run-make/pgo-indirect-call-promotion/Makefile run-make/pgo-use/Makefile run-make/pointer-auth-link-with-c/Makefile diff --git a/tests/run-make/pgo-gen/Makefile b/tests/run-make/pgo-gen/Makefile deleted file mode 100644 index c1d456986fb28..0000000000000 --- a/tests/run-make/pgo-gen/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# needs-profiler-support -# ignore-cross-compile - -include ../tools.mk - -COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)" - -all: - $(RUSTC) $(COMPILE_FLAGS) test.rs - $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) diff --git a/tests/run-make/pgo-gen/rmake.rs b/tests/run-make/pgo-gen/rmake.rs new file mode 100644 index 0000000000000..d35b29302648e --- /dev/null +++ b/tests/run-make/pgo-gen/rmake.rs @@ -0,0 +1,18 @@ +// -C profile-generate, when used with rustc, is supposed to output +// profile files (.profraw) after running a binary to analyze how the compiler +// optimizes code. This test checks that these files are generated. +// See https://github.com/rust-lang/rust/pull/48346 + +//@ needs-profiler-support +//@ ignore-cross-compile + +use run_make_support::{cwd, find_files_by_prefix_and_extension, run, rustc}; + +fn main() { + rustc().arg("-g").profile_generate(cwd()).run(); + run("test"); + assert!( + find_files_by_prefix_and_extension(cwd(), "default", "profraw").len() > 0, + "no .profraw file generated" + ); +} From a1555eb0d618eb1abae39d07e6428e2688788b7b Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 13:46:20 -0400 Subject: [PATCH 168/189] rewrite pgo-use to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/pgo-use/Makefile | 43 --------------- tests/run-make/pgo-use/rmake.rs | 54 +++++++++++++++++++ 3 files changed, 54 insertions(+), 44 deletions(-) delete mode 100644 tests/run-make/pgo-use/Makefile create mode 100644 tests/run-make/pgo-use/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 97990e5923561..2050189cead96 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -110,7 +110,6 @@ run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-gen-no-imp-symbols/Makefile run-make/pgo-indirect-call-promotion/Makefile -run-make/pgo-use/Makefile run-make/pointer-auth-link-with-c/Makefile run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile diff --git a/tests/run-make/pgo-use/Makefile b/tests/run-make/pgo-use/Makefile deleted file mode 100644 index 92098a4019c47..0000000000000 --- a/tests/run-make/pgo-use/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# needs-profiler-support -# ignore-cross-compile - -include ../tools.mk - -# This test makes sure that PGO profiling data leads to cold functions being -# marked as `cold` and hot functions with `inlinehint`. -# The test program contains an `if` were actual execution only ever takes the -# `else` branch. Accordingly, we expect the function that is never called to -# be marked as cold. -# -# Disable the pre-inlining pass (i.e. a pass that does some inlining before -# it adds the profiling instrumentation). Disabling this pass leads to -# rather predictable IR which we need for this test to be stable. - -COMMON_FLAGS=-Copt-level=2 -Ccodegen-units=1 -Cllvm-args=-disable-preinline - -ifeq ($(UNAME),Darwin) -# macOS does not have the `tac` command, but `tail -r` does the same thing -TAC := tail -r -else -# some other platforms don't support the `-r` flag for `tail`, so use `tac` -TAC := tac -endif - -all: - # Compile the test program with instrumentation - $(RUSTC) $(COMMON_FLAGS) -Cprofile-generate="$(TMPDIR)" main.rs - # Run it in order to generate some profiling data - $(call RUN,main some-argument) || exit 1 - # Postprocess the profiling data so it can be used by the compiler - "$(LLVM_BIN_DIR)"/llvm-profdata merge \ - -o "$(TMPDIR)"/merged.profdata \ - "$(TMPDIR)"/default_*.profraw - # Compile the test program again, making use of the profiling data - $(RUSTC) $(COMMON_FLAGS) -Cprofile-use="$(TMPDIR)"/merged.profdata --emit=llvm-ir main.rs - # Check that the generate IR contains some things that we expect - # - # We feed the file into LLVM FileCheck tool *in reverse* so that we see the - # line with the function name before the line with the function attributes. - # FileCheck only supports checking that something matches on the next line, - # but not if something matches on the previous line. - $(TAC) "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs new file mode 100644 index 0000000000000..04777821b51b0 --- /dev/null +++ b/tests/run-make/pgo-use/rmake.rs @@ -0,0 +1,54 @@ +// This test makes sure that PGO profiling data leads to cold functions being +// marked as `cold` and hot functions with `inlinehint`. +// The test program contains an `if` where actual execution only ever takes the +// `else` branch. Accordingly, we expect the function that is never called to +// be marked as cold. +// See https://github.com/rust-lang/rust/pull/60262 + +//@ needs-profiler-support +//@ ignore-cross-compile + +use run_make_support::{ + cwd, find_files_by_prefix_and_extension, fs_wrapper, llvm_filecheck, llvm_profdata, + run_with_args, rustc, +}; + +fn main() { + // Compile the test program with instrumentation + // Disable the pre-inlining pass (i.e. a pass that does some inlining before + // it adds the profiling instrumentation). Disabling this pass leads to + // rather predictable IR which we need for this test to be stable. + rustc() + .opt_level("2") + .codegen_units(1) + .arg("-Cllvm-args=-disable-preinline") + .profile_generate(cwd()) + .input("main.rs") + .run(); + // Run it in order to generate some profiling data + run_with_args("main", &["some-argument"]); + // Postprocess the profiling data so it can be used by the compiler + llvm_profdata() + .merge() + .output("merged.profdata") + .input(find_files_by_prefix_and_extension(cwd(), "default", "profraw").get(0).unwrap()) + .run(); + // Compile the test program again, making use of the profiling data + rustc() + .opt_level("2") + .codegen_units(1) + .arg("-Cllvm-args=-disable-preinline") + .profile_use("merged.profdata") + .emit("llvm-ir") + .input("main.rs") + .run(); + // Check that the generate IR contains some things that we expect + // + // We feed the file into LLVM FileCheck tool *in reverse* so that we see the + // line with the function name before the line with the function attributes. + // FileCheck only supports checking that something matches on the next line, + // but not if something matches on the previous line. + let mut bytes = fs_wrapper::read("interesting.ll"); + bytes.reverse(); + llvm_filecheck().patterns("filecheck-patterns.txt").stdin(bytes).run(); +} From b15e72a9ed8f34b98d32eba2eb5d3a3d9befea77 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 13:58:48 -0400 Subject: [PATCH 169/189] rewrite profile to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/profile/Makefile | 13 ----------- tests/run-make/profile/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/profile/Makefile create mode 100644 tests/run-make/profile/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2050189cead96..0cb3275d7e934 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -113,7 +113,6 @@ run-make/pgo-indirect-call-promotion/Makefile run-make/pointer-auth-link-with-c/Makefile run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile -run-make/profile/Makefile run-make/prune-link-args/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile diff --git a/tests/run-make/profile/Makefile b/tests/run-make/profile/Makefile deleted file mode 100644 index 7919b18ba74a5..0000000000000 --- a/tests/run-make/profile/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# needs-profiler-support -# ignore-cross-compile - -include ../tools.mk - -all: - $(RUSTC) -g -Z profile test.rs - $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) - [ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) - $(RUSTC) -g -Z profile -Z profile-emit=$(TMPDIR)/abc/abc.gcda test.rs - $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/abc/abc.gcda" ] || (echo "gcda file not emitted to defined path"; exit 1) diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs new file mode 100644 index 0000000000000..8d41978baecdd --- /dev/null +++ b/tests/run-make/profile/rmake.rs @@ -0,0 +1,22 @@ +// This test revolves around the rustc flag -Z profile, which should +// generate a .gcno file (initial profiling information) as well +// as a .gcda file (branch counters). The path where these are emitted +// should also be configurable with -Z profile-emit. This test checks +// that the files are produced, and then that the latter flag is respected. +// See https://github.com/rust-lang/rust/pull/42433 + +//@ ignore-cross-compile +//@ needs-profiler-support + +use run_make_support::{run, rustc}; +use std::path::Path; + +fn main() { + rustc().arg("-g").arg("-Zprofile").input("test.rs").run(); + run("test"); + assert!(Path::new("test.gcno").exists(), "no .gcno file"); + assert!(Path::new("test.gcda").exists(), "no .gcda file"); + rustc().arg("-g").arg("-Zprofile").arg("-Zprofile-emit=abc/abc.gcda").input("test.rs").run(); + run("test"); + assert!(Path::new("abc/abc.gcda").exists(), "gcda file not emitted to defined path"); +} From 3cdce7ee1050930b696683906430c0641e55b3fc Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 28 Jun 2024 16:25:12 -0400 Subject: [PATCH 170/189] rewrite output-type-permutations to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../output-type-permutations/Makefile | 147 --------------- .../output-type-permutations/rmake.rs | 178 ++++++++++++++++++ 3 files changed, 178 insertions(+), 148 deletions(-) delete mode 100644 tests/run-make/output-type-permutations/Makefile create mode 100644 tests/run-make/output-type-permutations/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 70c1b055c6e40..3a9755e5658c0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -100,7 +100,6 @@ run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile run-make/obey-crate-type-flag/Makefile -run-make/output-type-permutations/Makefile run-make/panic-abort-eh_frame/Makefile run-make/pass-linker-flags-flavor/Makefile run-make/pass-linker-flags-from-dep/Makefile diff --git a/tests/run-make/output-type-permutations/Makefile b/tests/run-make/output-type-permutations/Makefile deleted file mode 100644 index 035033b9fddd3..0000000000000 --- a/tests/run-make/output-type-permutations/Makefile +++ /dev/null @@ -1,147 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib - $(call REMOVE_RLIBS,bar) - $(call REMOVE_DYLIBS,bar) - rm $(call STATICLIB,bar) - rm -f $(TMPDIR)/{lib,}bar.{dll.exp,dll.lib,pdb,dll.a} - # Check that $(TMPDIR) is empty. - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --crate-type=bin - rm $(TMPDIR)/$(call BIN,bar) - rm -f $(TMPDIR)/bar.pdb - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link - rm $(TMPDIR)/bar.ll - rm $(TMPDIR)/bar.bc - rm $(TMPDIR)/bar.s - rm $(TMPDIR)/bar.o - rm $(TMPDIR)/$(call BIN,bar) - rm -f $(TMPDIR)/bar.pdb - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit=asm=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit=llvm-bc=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit=llvm-ir=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --emit=obj=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --emit=link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - rm -f $(TMPDIR)/foo.pdb - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --crate-type=rlib --emit=link=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --crate-type=dylib --emit=link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - rm -f $(TMPDIR)/{lib,}foo.{dll.exp,dll.lib,pdb,dll.a,exe.a} - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] || (ls -1 $(TMPDIR) && exit 1) - - $(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo - rm $(TMPDIR)/foo - $(RUSTC) foo.rs --crate-type=staticlib --emit=link=$(TMPDIR)/foo - rm $(TMPDIR)/foo - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo.rs --crate-type=bin --emit=link=$(TMPDIR)/$(call BIN,foo) - rm $(TMPDIR)/$(call BIN,foo) - rm -f $(TMPDIR)/foo.pdb - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \ - --emit link \ - --crate-type=rlib - rm $(TMPDIR)/ir - rm $(TMPDIR)/libbar.rlib - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \ - --emit llvm-ir=$(TMPDIR)/ir \ - --emit llvm-bc=$(TMPDIR)/bc \ - --emit obj=$(TMPDIR)/obj \ - --emit link=$(TMPDIR)/link \ - --crate-type=staticlib - rm $(TMPDIR)/asm - rm $(TMPDIR)/ir - rm $(TMPDIR)/bc - rm $(TMPDIR)/obj - rm $(TMPDIR)/link - $(RUSTC) foo.rs --emit=asm=$(TMPDIR)/asm \ - --emit llvm-ir=$(TMPDIR)/ir \ - --emit=llvm-bc=$(TMPDIR)/bc \ - --emit obj=$(TMPDIR)/obj \ - --emit=link=$(TMPDIR)/link \ - --crate-type=staticlib - rm $(TMPDIR)/asm - rm $(TMPDIR)/ir - rm $(TMPDIR)/bc - rm $(TMPDIR)/obj - rm $(TMPDIR)/link - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - - $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib - rm $(TMPDIR)/bar.ll - rm $(TMPDIR)/bar.s - rm $(TMPDIR)/bar.o - rm $(call STATICLIB,bar) - mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc - # Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later - # comparison. - - $(RUSTC) foo.rs --emit=llvm-bc,link --crate-type=rlib - cmp $(TMPDIR)/foo.bc $(TMPDIR)/bar.bc - rm $(TMPDIR)/bar.bc - rm $(TMPDIR)/foo.bc - $(call REMOVE_RLIBS,bar) - [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs new file mode 100644 index 0000000000000..69af1274c68a1 --- /dev/null +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -0,0 +1,178 @@ +// In 2014, rustc's output flags were reworked to be a lot more modular. +// This test uses these output flags in an expansive variety of combinations +// and syntax styles, checking that compilation is successful and that no unexpected +// files are created. +// The assert_eq! checks that "1 file remains" at the end of each part of the test, +// because foo.rs counts as a file, and should be the only remaining one. +// See https://github.com/rust-lang/rust/pull/12020 + +use run_make_support::{ + bin_name, cwd, dynamic_lib_name, fs_wrapper, rust_lib_name, rustc, static_lib_name, +}; + +fn remove_artifacts() { + std::fs::remove_file("libbar.ddl.exp").unwrap_or_default(); + std::fs::remove_file("libbar.dll.lib").unwrap_or_default(); + std::fs::remove_file("libbar.pdb").unwrap_or_default(); + std::fs::remove_file("libbar.dll.a").unwrap_or_default(); + std::fs::remove_file("libbar.exe.a").unwrap_or_default(); + std::fs::remove_file("bar.ddl.exp").unwrap_or_default(); + std::fs::remove_file("bar.dll.lib").unwrap_or_default(); + std::fs::remove_file("bar.pdb").unwrap_or_default(); + std::fs::remove_file("bar.dll.a").unwrap_or_default(); + std::fs::remove_file("bar.exe.a").unwrap_or_default(); +} + +fn main() { + rustc().input("foo.rs").crate_type("rlib,dylib,staticlib").run(); + fs_wrapper::remove_file(rust_lib_name("bar")); + fs_wrapper::remove_file(dynamic_lib_name("bar")); + fs_wrapper::remove_file(static_lib_name("bar")); + remove_artifacts(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").crate_type("bin").run(); + fs_wrapper::remove_file(bin_name("bar")); + std::fs::remove_file("bar.pdb").unwrap_or_default(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").run(); + fs_wrapper::remove_file("bar.ll"); + fs_wrapper::remove_file("bar.bc"); + fs_wrapper::remove_file("bar.s"); + fs_wrapper::remove_file("bar.o"); + fs_wrapper::remove_file(bin_name("bar")); + std::fs::remove_file("bar.pdb").unwrap_or_default(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("asm").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").emit("asm=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").arg("--emit=asm=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("llvm-bc").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").emit("llvm-bc=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").arg("--emit=llvm-bc=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("llvm-ir").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").emit("llvm-ir=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").arg("--emit=llvm-ir=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("obj").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").emit("obj=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").arg("--emit=obj=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + let bin_foo = bin_name("foo"); + rustc().input("foo.rs").emit("link").output(&bin_foo).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").emit(&format!("link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").arg(&format!("--emit=link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + std::fs::remove_file("foo.pdb").unwrap_or_default(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").crate_type("rlib").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").crate_type("rlib").emit("link=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").crate_type("rlib").arg("--emit=link=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").crate_type("dylib").output(&bin_foo).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").crate_type("dylib").emit(&format!("link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").crate_type("dylib").arg(&format!("--emit=link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + remove_artifacts(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").crate_type("staticlib").emit("link").output("foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").crate_type("staticlib").emit("link=foo").run(); + fs_wrapper::remove_file("foo"); + rustc().input("foo.rs").crate_type("staticlib").arg("--emit=link=foo").run(); + fs_wrapper::remove_file("foo"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").crate_type("bin").output(&bin_foo).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").crate_type("bin").emit(&format!("link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + rustc().input("foo.rs").crate_type("bin").arg(&format!("--emit=link={bin_foo}")).run(); + fs_wrapper::remove_file(&bin_foo); + std::fs::remove_file("foo.pdb").unwrap_or_default(); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("llvm-ir=ir").emit("link").crate_type("rlib").run(); + fs_wrapper::remove_file("ir"); + fs_wrapper::remove_file(rust_lib_name("bar")); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc() + .input("foo.rs") + .emit("asm=asm") + .emit("llvm-ir=ir") + .emit("llvm-bc=bc") + .emit("obj=obj") + .emit("link=link") + .crate_type("staticlib") + .run(); + fs_wrapper::remove_file("asm"); + fs_wrapper::remove_file("ir"); + fs_wrapper::remove_file("bc"); + fs_wrapper::remove_file("obj"); + fs_wrapper::remove_file("link"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc() + .input("foo.rs") + .arg("--emit=asm=asm") + .arg("--emit") + .arg("llvm-ir=ir") + .arg("--emit=llvm-bc=bc") + .arg("--emit") + .arg("obj=obj") + .arg("--emit=link=link") + .crate_type("staticlib") + .run(); + fs_wrapper::remove_file("asm"); + fs_wrapper::remove_file("ir"); + fs_wrapper::remove_file("bc"); + fs_wrapper::remove_file("obj"); + fs_wrapper::remove_file("link"); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + + rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").crate_type("staticlib").run(); + fs_wrapper::remove_file("bar.ll"); + fs_wrapper::remove_file("bar.s"); + fs_wrapper::remove_file("bar.o"); + fs_wrapper::remove_file(static_lib_name("bar")); + fs_wrapper::rename("bar.bc", "foo.bc"); + // Don't check that no files except foo.rs remain - we left `foo.bc` for later + // comparison. + + rustc().input("foo.rs").emit("llvm-bc,link").crate_type("rlib").run(); + assert_eq!(fs_wrapper::read("foo.bc"), fs_wrapper::read("bar.bc")); + fs_wrapper::remove_file("bar.bc"); + fs_wrapper::remove_file("foo.bc"); + fs_wrapper::remove_file(rust_lib_name("bar")); + assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); +} From 73994719b466350c1faf88d0bfbf20b44c29a8aa Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 2 Jul 2024 15:25:26 -0400 Subject: [PATCH 171/189] add shallow_find_files helper to run_make_support --- src/tools/run-make-support/src/lib.rs | 5 + .../output-type-permutations/rmake.rs | 447 +++++++++++------- 2 files changed, 285 insertions(+), 167 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index af5ae6a8e608c..20ceb03defef9 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -295,6 +295,11 @@ pub fn not_contains>(path: P, expected: &str) -> bool { !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) } +/// Returns true if the filename at `path` is not in `expected`. +pub fn name_not_among>(path: P, expected: &[&'static str]) -> bool { + path.as_ref().file_name().is_some_and(|name| !expected.contains(&name.to_str().unwrap())) +} + /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index 69af1274c68a1..eb166307f6800 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -1,178 +1,291 @@ // In 2014, rustc's output flags were reworked to be a lot more modular. // This test uses these output flags in an expansive variety of combinations -// and syntax styles, checking that compilation is successful and that no unexpected -// files are created. -// The assert_eq! checks that "1 file remains" at the end of each part of the test, -// because foo.rs counts as a file, and should be the only remaining one. +// and syntax styles, checking that compilation is successful and that output +// files are exactly what is expected, no more, no less. // See https://github.com/rust-lang/rust/pull/12020 use run_make_support::{ - bin_name, cwd, dynamic_lib_name, fs_wrapper, rust_lib_name, rustc, static_lib_name, + bin_name, cwd, dynamic_lib_name, fs_wrapper, name_not_among, rust_lib_name, rustc, + shallow_find_files, static_lib_name, }; -fn remove_artifacts() { - std::fs::remove_file("libbar.ddl.exp").unwrap_or_default(); - std::fs::remove_file("libbar.dll.lib").unwrap_or_default(); - std::fs::remove_file("libbar.pdb").unwrap_or_default(); - std::fs::remove_file("libbar.dll.a").unwrap_or_default(); - std::fs::remove_file("libbar.exe.a").unwrap_or_default(); - std::fs::remove_file("bar.ddl.exp").unwrap_or_default(); - std::fs::remove_file("bar.dll.lib").unwrap_or_default(); - std::fs::remove_file("bar.pdb").unwrap_or_default(); - std::fs::remove_file("bar.dll.a").unwrap_or_default(); - std::fs::remove_file("bar.exe.a").unwrap_or_default(); +// Each test takes 4 arguments: +// `must_exist`: output files which must be found - if any are absent, the test fails +// `can_exist`: optional output files which will not trigger a failure +// `dir`: the name of the directory where the test happens +// `rustc_invocation`: the rustc command being tested +// Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure. +fn assert_expected_output_files( + must_exist: &[&'static str], + can_exist: &[&'static str], + dir: &str, + rustc_invocation: impl Fn(), +) { + fs_wrapper::create_dir(dir); + rustc_invocation(); + for file in must_exist { + fs_wrapper::remove_file(dir.to_owned() + "/" + file); + } + let actual_output_files = shallow_find_files(dir, |path| name_not_among(path, can_exist)); + if !&actual_output_files.is_empty() { + dbg!(&actual_output_files); + panic!("unexpected output artifacts detected"); + } } fn main() { - rustc().input("foo.rs").crate_type("rlib,dylib,staticlib").run(); - fs_wrapper::remove_file(rust_lib_name("bar")); - fs_wrapper::remove_file(dynamic_lib_name("bar")); - fs_wrapper::remove_file(static_lib_name("bar")); - remove_artifacts(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").crate_type("bin").run(); - fs_wrapper::remove_file(bin_name("bar")); - std::fs::remove_file("bar.pdb").unwrap_or_default(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").run(); - fs_wrapper::remove_file("bar.ll"); - fs_wrapper::remove_file("bar.bc"); - fs_wrapper::remove_file("bar.s"); - fs_wrapper::remove_file("bar.o"); - fs_wrapper::remove_file(bin_name("bar")); - std::fs::remove_file("bar.pdb").unwrap_or_default(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("asm").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").emit("asm=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").arg("--emit=asm=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("llvm-bc").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").emit("llvm-bc=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").arg("--emit=llvm-bc=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("llvm-ir").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").emit("llvm-ir=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").arg("--emit=llvm-ir=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("obj").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").emit("obj=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").arg("--emit=obj=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - let bin_foo = bin_name("foo"); - rustc().input("foo.rs").emit("link").output(&bin_foo).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").emit(&format!("link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").arg(&format!("--emit=link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - std::fs::remove_file("foo.pdb").unwrap_or_default(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").crate_type("rlib").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").crate_type("rlib").emit("link=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").crate_type("rlib").arg("--emit=link=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").crate_type("dylib").output(&bin_foo).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").crate_type("dylib").emit(&format!("link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").crate_type("dylib").arg(&format!("--emit=link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - remove_artifacts(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").crate_type("staticlib").emit("link").output("foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").crate_type("staticlib").emit("link=foo").run(); - fs_wrapper::remove_file("foo"); - rustc().input("foo.rs").crate_type("staticlib").arg("--emit=link=foo").run(); - fs_wrapper::remove_file("foo"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").crate_type("bin").output(&bin_foo).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").crate_type("bin").emit(&format!("link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - rustc().input("foo.rs").crate_type("bin").arg(&format!("--emit=link={bin_foo}")).run(); - fs_wrapper::remove_file(&bin_foo); - std::fs::remove_file("foo.pdb").unwrap_or_default(); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("llvm-ir=ir").emit("link").crate_type("rlib").run(); - fs_wrapper::remove_file("ir"); - fs_wrapper::remove_file(rust_lib_name("bar")); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc() - .input("foo.rs") - .emit("asm=asm") - .emit("llvm-ir=ir") - .emit("llvm-bc=bc") - .emit("obj=obj") - .emit("link=link") - .crate_type("staticlib") - .run(); - fs_wrapper::remove_file("asm"); - fs_wrapper::remove_file("ir"); - fs_wrapper::remove_file("bc"); - fs_wrapper::remove_file("obj"); - fs_wrapper::remove_file("link"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc() - .input("foo.rs") - .arg("--emit=asm=asm") - .arg("--emit") - .arg("llvm-ir=ir") - .arg("--emit=llvm-bc=bc") - .arg("--emit") - .arg("obj=obj") - .arg("--emit=link=link") - .crate_type("staticlib") - .run(); - fs_wrapper::remove_file("asm"); - fs_wrapper::remove_file("ir"); - fs_wrapper::remove_file("bc"); - fs_wrapper::remove_file("obj"); - fs_wrapper::remove_file("link"); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); - - rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").crate_type("staticlib").run(); - fs_wrapper::remove_file("bar.ll"); - fs_wrapper::remove_file("bar.s"); - fs_wrapper::remove_file("bar.o"); - fs_wrapper::remove_file(static_lib_name("bar")); - fs_wrapper::rename("bar.bc", "foo.bc"); - // Don't check that no files except foo.rs remain - we left `foo.bc` for later - // comparison. - - rustc().input("foo.rs").emit("llvm-bc,link").crate_type("rlib").run(); - assert_eq!(fs_wrapper::read("foo.bc"), fs_wrapper::read("bar.bc")); - fs_wrapper::remove_file("bar.bc"); - fs_wrapper::remove_file("foo.bc"); - fs_wrapper::remove_file(rust_lib_name("bar")); - assert_eq!(fs_wrapper::read_dir(cwd()).count(), 1); + let bin_foo = Box::leak(Box::new(bin_name("foo"))); + let bin_bar = Box::leak(Box::new(bin_name("bar"))); + let static_bar = Box::leak(Box::new(static_lib_name("bar"))); + let dynamic_bar = Box::leak(Box::new(dynamic_lib_name("bar"))); + let rust_bar = Box::leak(Box::new(rust_lib_name("bar"))); + + assert_expected_output_files( + &[static_bar, dynamic_bar, rust_bar], + &[ + "libbar.ddl.exp", + "libbar.dll.lib", + "libbar.pdb", + "libbar.dll.a", + "libbar.exe.a", + "bar.ddl.exp", + "bar.dll.lib", + "bar.pdb", + "bar.dll.a", + "bar.exe.a", + ], + "three-crates", + || { + rustc() + .input("foo.rs") + .out_dir("three-crates") + .crate_type("rlib,dylib,staticlib") + .run(); + }, + ); + + assert_expected_output_files(&[bin_bar], &["bar.pdb"], "bin-crate", || { + rustc().input("foo.rs").crate_type("bin").out_dir("bin-crate").run(); + }); + + assert_expected_output_files( + &["bar.ll", "bar.bc", "bar.s", "bar.o", bin_bar], + &["bar.pdb"], + "all-emit", + || { + rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").out_dir("all-emit").run(); + }, + ); + + assert_expected_output_files(&["foo"], &[], "asm-emit", || { + rustc().input("foo.rs").emit("asm").output("asm-emit/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "asm-emit2", || { + rustc().input("foo.rs").emit("asm=asm-emit2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "asm-emit3", || { + rustc().input("foo.rs").arg("--emit=asm=asm-emit3/foo").run(); + }); + + assert_expected_output_files(&["foo"], &[], "llvm-ir-emit", || { + rustc().input("foo.rs").emit("llvm-ir").output("llvm-ir-emit/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "llvm-ir-emit2", || { + rustc().input("foo.rs").emit("llvm-ir=llvm-ir-emit2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "llvm-ir-emit3", || { + rustc().input("foo.rs").arg("--emit=llvm-ir=llvm-ir-emit3/foo").run(); + }); + + assert_expected_output_files(&["foo"], &[], "llvm-bc-emit", || { + rustc().input("foo.rs").emit("llvm-bc").output("llvm-bc-emit/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "llvm-bc-emit2", || { + rustc().input("foo.rs").emit("llvm-bc=llvm-bc-emit2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "llvm-bc-emit3", || { + rustc().input("foo.rs").arg("--emit=llvm-bc=llvm-bc-emit3/foo").run(); + }); + + assert_expected_output_files(&["foo"], &[], "obj-emit", || { + rustc().input("foo.rs").emit("obj").output("obj-emit/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "obj-emit2", || { + rustc().input("foo.rs").emit("obj=obj-emit2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "obj-emit3", || { + rustc().input("foo.rs").arg("--emit=obj=obj-emit3/foo").run(); + }); + + assert_expected_output_files(&[bin_foo], &[], "link-emit", || { + rustc().input("foo.rs").emit("link").output("link-emit/".to_owned() + bin_foo).run(); + }); + assert_expected_output_files(&[bin_foo], &[], "link-emit2", || { + rustc().input("foo.rs").emit(&format!("link=link-emit2/{bin_foo}")).run(); + }); + assert_expected_output_files(&[bin_foo], &[], "link-emit3", || { + rustc().input("foo.rs").arg(&format!("--emit=link=link-emit3/{bin_foo}")).run(); + }); + + assert_expected_output_files(&["foo"], &[], "rlib", || { + rustc().crate_type("rlib").input("foo.rs").output("rlib/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "rlib2", || { + rustc().crate_type("rlib").input("foo.rs").emit("link=rlib2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "rlib3", || { + rustc().crate_type("rlib").input("foo.rs").arg("--emit=link=rlib3/foo").run(); + }); + + assert_expected_output_files( + &[bin_foo], + &[ + "libbar.ddl.exp", + "libbar.dll.lib", + "libbar.pdb", + "libbar.dll.a", + "libbar.exe.a", + "bar.ddl.exp", + "bar.dll.lib", + "bar.pdb", + "bar.dll.a", + "bar.exe.a", + ], + "dylib", + || { + rustc().crate_type("dylib").input("foo.rs").output("dylib/".to_owned() + bin_foo).run(); + }, + ); + assert_expected_output_files( + &[bin_foo], + &[ + "libbar.ddl.exp", + "libbar.dll.lib", + "libbar.pdb", + "libbar.dll.a", + "libbar.exe.a", + "bar.ddl.exp", + "bar.dll.lib", + "bar.pdb", + "bar.dll.a", + "bar.exe.a", + ], + "dylib2", + || { + rustc() + .crate_type("dylib") + .input("foo.rs") + .emit(&format!("link=dylib2/{bin_foo}")) + .run(); + }, + ); + assert_expected_output_files( + &[bin_foo], + &[ + "libbar.ddl.exp", + "libbar.dll.lib", + "libbar.pdb", + "libbar.dll.a", + "libbar.exe.a", + "bar.ddl.exp", + "bar.dll.lib", + "bar.pdb", + "bar.dll.a", + "bar.exe.a", + ], + "dylib3", + || { + rustc() + .crate_type("dylib") + .input("foo.rs") + .arg(&format!("--emit=link=dylib3/{bin_foo}")) + .run(); + }, + ); + + assert_expected_output_files(&["foo"], &[], "staticlib", || { + rustc().crate_type("staticlib").input("foo.rs").output("staticlib/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "staticlib2", || { + rustc().crate_type("staticlib").input("foo.rs").emit("link=staticlib2/foo").run(); + }); + assert_expected_output_files(&["foo"], &[], "staticlib3", || { + rustc().crate_type("staticlib").input("foo.rs").arg("--emit=link=staticlib3/foo").run(); + }); + + assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate", || { + rustc().crate_type("bin").input("foo.rs").output("bincrate/".to_owned() + bin_foo).run(); + }); + assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate2", || { + rustc().crate_type("bin").input("foo.rs").emit(&format!("link=bincrate2/{bin_foo}")).run(); + }); + assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate3", || { + rustc() + .crate_type("bin") + .input("foo.rs") + .arg(&format!("--emit=link=bincrate3/{bin_foo}")) + .run(); + }); + + assert_expected_output_files(&["ir", rust_bar], &[], "rlib-ir", || { + rustc() + .input("foo.rs") + .emit("llvm-ir=rlib-ir/ir") + .emit("link") + .crate_type("rlib") + .out_dir("rlib-ir") + .run(); + }); + + assert_expected_output_files(&["ir", "asm", "bc", "obj", "link"], &[], "staticlib-all", || { + rustc() + .input("foo.rs") + .emit("asm=staticlib-all/asm") + .emit("llvm-ir=staticlib-all/ir") + .emit("llvm-bc=staticlib-all/bc") + .emit("obj=staticlib-all/obj") + .emit("link=staticlib-all/link") + .crate_type("staticlib") + .run(); + }); + assert_expected_output_files( + &["ir", "asm", "bc", "obj", "link"], + &[], + "staticlib-all2", + || { + rustc() + .input("foo.rs") + .arg("--emit=asm=staticlib-all2/asm") + .arg("--emit") + .arg("llvm-ir=staticlib-all2/ir") + .arg("--emit=llvm-bc=staticlib-all2/bc") + .arg("--emit") + .arg("obj=staticlib-all2/obj") + .arg("--emit=link=staticlib-all2/link") + .crate_type("staticlib") + .run(); + }, + ); + + assert_expected_output_files( + &["bar.ll", "bar.s", "bar.o", static_bar], + &["bar.bc"], // keep this one for the next test + "staticlib-all3", + || { + rustc() + .input("foo.rs") + .emit("asm,llvm-ir,llvm-bc,obj,link") + .crate_type("staticlib") + .out_dir("staticlib-all3") + .run(); + }, + ); + + // the .bc file from the previous test should be equivalent to this one, despite the difference + // in crate type + assert_expected_output_files(&["bar.bc", rust_bar, "foo.bc"], &[], "rlib-emits", || { + fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); + rustc().input("foo.rs").emit("llvm-bc,link").crate_type("rlib").out_dir("rlib-emits").run(); + assert_eq!(fs_wrapper::read("rlib-emits/foo.bc"), fs_wrapper::read("rlib-emits/bar.bc")); + }); } From 811532be6e999c42f8101c6cba62a300da2855cc Mon Sep 17 00:00:00 2001 From: Oneirical Date: Wed, 3 Jul 2024 11:48:19 -0400 Subject: [PATCH 172/189] Expectations struct for output-type-permutations --- src/tools/run-make-support/src/lib.rs | 10 +- .../output-type-permutations/rmake.rs | 632 ++++++++++++------ 2 files changed, 448 insertions(+), 194 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 20ceb03defef9..7bb89106de1b9 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -266,14 +266,14 @@ pub fn test_while_readonly, F: FnOnce() + std::panic::UnwindSafe> #[track_caller] pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( path: P, - closure: F, + filter: F, ) -> Vec { let mut matching_files = Vec::new(); for entry in fs_wrapper::read_dir(path) { let entry = entry.expect("failed to read directory entry."); let path = entry.path(); - if path.is_file() && closure(&path) { + if path.is_file() && filter(&path) { matching_files.push(path); } } @@ -296,8 +296,10 @@ pub fn not_contains>(path: P, expected: &str) -> bool { } /// Returns true if the filename at `path` is not in `expected`. -pub fn name_not_among>(path: P, expected: &[&'static str]) -> bool { - path.as_ref().file_name().is_some_and(|name| !expected.contains(&name.to_str().unwrap())) +pub fn filename_not_in_denylist>(path: P, expected: &[String]) -> bool { + path.as_ref() + .file_name() + .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) } /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index eb166307f6800..30036dc7eeacd 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -5,9 +5,10 @@ // See https://github.com/rust-lang/rust/pull/12020 use run_make_support::{ - bin_name, cwd, dynamic_lib_name, fs_wrapper, name_not_among, rust_lib_name, rustc, + bin_name, dynamic_lib_name, filename_not_in_denylist, fs_wrapper, rust_lib_name, rustc, shallow_find_files, static_lib_name, }; +use std::path::PathBuf; // Each test takes 4 arguments: // `must_exist`: output files which must be found - if any are absent, the test fails @@ -15,46 +16,69 @@ use run_make_support::{ // `dir`: the name of the directory where the test happens // `rustc_invocation`: the rustc command being tested // Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure. -fn assert_expected_output_files( - must_exist: &[&'static str], - can_exist: &[&'static str], - dir: &str, - rustc_invocation: impl Fn(), -) { - fs_wrapper::create_dir(dir); +fn assert_expected_output_files(expectations: Expectations, rustc_invocation: impl Fn()) { + let must_exist = expectations.expected_files; + let can_exist = expectations.allowed_files; + let dir = expectations.test_dir; + + fs_wrapper::create_dir(&dir); rustc_invocation(); for file in must_exist { - fs_wrapper::remove_file(dir.to_owned() + "/" + file); + fs_wrapper::remove_file(PathBuf::from(&dir).join(&file)); } - let actual_output_files = shallow_find_files(dir, |path| name_not_among(path, can_exist)); + let actual_output_files = + shallow_find_files(dir, |path| filename_not_in_denylist(path, &can_exist)); if !&actual_output_files.is_empty() { dbg!(&actual_output_files); panic!("unexpected output artifacts detected"); } } +struct Expectations { + /// Output files which must be found. The test fails if any are absent. + expected_files: Vec, + /// Allowed output files which will not trigger a failure. + allowed_files: Vec, + /// Name of the directory where the test happens. + test_dir: String, +} + +macro_rules! s { + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x.to_string()); + )* + temp_vec + } + }; +} + fn main() { - let bin_foo = Box::leak(Box::new(bin_name("foo"))); - let bin_bar = Box::leak(Box::new(bin_name("bar"))); - let static_bar = Box::leak(Box::new(static_lib_name("bar"))); - let dynamic_bar = Box::leak(Box::new(dynamic_lib_name("bar"))); - let rust_bar = Box::leak(Box::new(rust_lib_name("bar"))); + let bin_foo = bin_name("foo"); assert_expected_output_files( - &[static_bar, dynamic_bar, rust_bar], - &[ - "libbar.ddl.exp", - "libbar.dll.lib", - "libbar.pdb", - "libbar.dll.a", - "libbar.exe.a", - "bar.ddl.exp", - "bar.dll.lib", - "bar.pdb", - "bar.dll.a", - "bar.exe.a", - ], - "three-crates", + Expectations { + expected_files: s![ + static_lib_name("bar"), + dynamic_lib_name("bar"), + rust_lib_name("bar") + ], + allowed_files: s![ + "libbar.dll.exp", + "libbar.dll.lib", + "libbar.pdb", + "libbar.dll.a", + "libbar.exe.a", + "bar.dll.exp", + "bar.dll.lib", + "bar.pdb", + "bar.dll.a", + "bar.exe.a" + ], + test_dir: "three-crates".to_string(), + }, || { rustc() .input("foo.rs") @@ -64,113 +88,256 @@ fn main() { }, ); - assert_expected_output_files(&[bin_bar], &["bar.pdb"], "bin-crate", || { - rustc().input("foo.rs").crate_type("bin").out_dir("bin-crate").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s![bin_name("bar")], + allowed_files: s!["bar.pdb"], + test_dir: "bin-crate".to_string(), + }, + || { + rustc().input("foo.rs").crate_type("bin").out_dir("bin-crate").run(); + }, + ); assert_expected_output_files( - &["bar.ll", "bar.bc", "bar.s", "bar.o", bin_bar], - &["bar.pdb"], - "all-emit", + Expectations { + expected_files: s!["bar.ll", "bar.bc", "bar.s", "bar.o", bin_name("bar")], + allowed_files: s!["bar.pdb"], + test_dir: "all-emit".to_string(), + }, || { rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").out_dir("all-emit").run(); }, ); - assert_expected_output_files(&["foo"], &[], "asm-emit", || { - rustc().input("foo.rs").emit("asm").output("asm-emit/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "asm-emit2", || { - rustc().input("foo.rs").emit("asm=asm-emit2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "asm-emit3", || { - rustc().input("foo.rs").arg("--emit=asm=asm-emit3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "asm-emit".to_string(), + }, + || { + rustc().input("foo.rs").emit("asm").output("asm-emit/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "asm-emit2".to_string(), + }, + || { + rustc().input("foo.rs").emit("asm=asm-emit2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "asm-emit3".to_string(), + }, + || { + rustc().input("foo.rs").arg("--emit=asm=asm-emit3/foo").run(); + }, + ); - assert_expected_output_files(&["foo"], &[], "llvm-ir-emit", || { - rustc().input("foo.rs").emit("llvm-ir").output("llvm-ir-emit/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "llvm-ir-emit2", || { - rustc().input("foo.rs").emit("llvm-ir=llvm-ir-emit2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "llvm-ir-emit3", || { - rustc().input("foo.rs").arg("--emit=llvm-ir=llvm-ir-emit3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-ir-emit".to_string(), + }, + || { + rustc().input("foo.rs").emit("llvm-ir").output("llvm-ir-emit/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-ir-emit2".to_string(), + }, + || { + rustc().input("foo.rs").emit("llvm-ir=llvm-ir-emit2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-ir-emit3".to_string(), + }, + || { + rustc().input("foo.rs").arg("--emit=llvm-ir=llvm-ir-emit3/foo").run(); + }, + ); - assert_expected_output_files(&["foo"], &[], "llvm-bc-emit", || { - rustc().input("foo.rs").emit("llvm-bc").output("llvm-bc-emit/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "llvm-bc-emit2", || { - rustc().input("foo.rs").emit("llvm-bc=llvm-bc-emit2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "llvm-bc-emit3", || { - rustc().input("foo.rs").arg("--emit=llvm-bc=llvm-bc-emit3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-bc-emit".to_string(), + }, + || { + rustc().input("foo.rs").emit("llvm-bc").output("llvm-bc-emit/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-bc-emit2".to_string(), + }, + || { + rustc().input("foo.rs").emit("llvm-bc=llvm-bc-emit2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "llvm-bc-emit3".to_string(), + }, + || { + rustc().input("foo.rs").arg("--emit=llvm-bc=llvm-bc-emit3/foo").run(); + }, + ); - assert_expected_output_files(&["foo"], &[], "obj-emit", || { - rustc().input("foo.rs").emit("obj").output("obj-emit/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "obj-emit2", || { - rustc().input("foo.rs").emit("obj=obj-emit2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "obj-emit3", || { - rustc().input("foo.rs").arg("--emit=obj=obj-emit3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "obj-emit".to_string(), + }, + || { + rustc().input("foo.rs").emit("obj").output("obj-emit/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "obj-emit2".to_string(), + }, + || { + rustc().input("foo.rs").emit("obj=obj-emit2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "obj-emit3".to_string(), + }, + || { + rustc().input("foo.rs").arg("--emit=obj=obj-emit3/foo").run(); + }, + ); - assert_expected_output_files(&[bin_foo], &[], "link-emit", || { - rustc().input("foo.rs").emit("link").output("link-emit/".to_owned() + bin_foo).run(); - }); - assert_expected_output_files(&[bin_foo], &[], "link-emit2", || { - rustc().input("foo.rs").emit(&format!("link=link-emit2/{bin_foo}")).run(); - }); - assert_expected_output_files(&[bin_foo], &[], "link-emit3", || { - rustc().input("foo.rs").arg(&format!("--emit=link=link-emit3/{bin_foo}")).run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s![&bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "link-emit".to_string(), + }, + || { + rustc().input("foo.rs").emit("link").output("link-emit/".to_owned() + &bin_foo).run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s![&bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "link-emit2".to_string(), + }, + || { + rustc().input("foo.rs").emit(&format!("link=link-emit2/{bin_foo}")).run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s![&bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "link-emit3".to_string(), + }, + || { + rustc().input("foo.rs").arg(&format!("--emit=link=link-emit3/{bin_foo}")).run(); + }, + ); - assert_expected_output_files(&["foo"], &[], "rlib", || { - rustc().crate_type("rlib").input("foo.rs").output("rlib/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "rlib2", || { - rustc().crate_type("rlib").input("foo.rs").emit("link=rlib2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "rlib3", || { - rustc().crate_type("rlib").input("foo.rs").arg("--emit=link=rlib3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "rlib".to_string(), + }, + || { + rustc().crate_type("rlib").input("foo.rs").output("rlib/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "rlib2".to_string(), + }, + || { + rustc().crate_type("rlib").input("foo.rs").emit("link=rlib2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "rlib3".to_string(), + }, + || { + rustc().crate_type("rlib").input("foo.rs").arg("--emit=link=rlib3/foo").run(); + }, + ); assert_expected_output_files( - &[bin_foo], - &[ - "libbar.ddl.exp", - "libbar.dll.lib", - "libbar.pdb", - "libbar.dll.a", - "libbar.exe.a", - "bar.ddl.exp", - "bar.dll.lib", - "bar.pdb", - "bar.dll.a", - "bar.exe.a", - ], - "dylib", - || { - rustc().crate_type("dylib").input("foo.rs").output("dylib/".to_owned() + bin_foo).run(); - }, - ); - assert_expected_output_files( - &[bin_foo], - &[ - "libbar.ddl.exp", - "libbar.dll.lib", - "libbar.pdb", - "libbar.dll.a", - "libbar.exe.a", - "bar.ddl.exp", - "bar.dll.lib", - "bar.pdb", - "bar.dll.a", - "bar.exe.a", - ], - "dylib2", + Expectations { + expected_files: s![bin_foo], + allowed_files: s![ + "libfoo.dll.exp", + "libfoo.dll.lib", + "libfoo.pdb", + "libfoo.dll.a", + "libfoo.exe.a", + "foo.dll.exp", + "foo.dll.lib", + "foo.pdb", + "foo.dll.a", + "foo.exe.a" + ], + test_dir: "dylib".to_string(), + }, + || { + rustc() + .crate_type("dylib") + .input("foo.rs") + .output("dylib/".to_owned() + &bin_foo) + .run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s![bin_foo], + allowed_files: s![ + "libfoo.dll.exp", + "libfoo.dll.lib", + "libfoo.pdb", + "libfoo.dll.a", + "libfoo.exe.a", + "foo.dll.exp", + "foo.dll.lib", + "foo.pdb", + "foo.dll.a", + "foo.exe.a" + ], + test_dir: "dylib2".to_string(), + }, || { rustc() .crate_type("dylib") @@ -180,20 +347,22 @@ fn main() { }, ); assert_expected_output_files( - &[bin_foo], - &[ - "libbar.ddl.exp", - "libbar.dll.lib", - "libbar.pdb", - "libbar.dll.a", - "libbar.exe.a", - "bar.ddl.exp", - "bar.dll.lib", - "bar.pdb", - "bar.dll.a", - "bar.exe.a", - ], - "dylib3", + Expectations { + expected_files: s![bin_foo], + allowed_files: s![ + "libfoo.dll.exp", + "libfoo.dll.lib", + "libfoo.pdb", + "libfoo.dll.a", + "libfoo.exe.a", + "foo.dll.exp", + "foo.dll.lib", + "foo.pdb", + "foo.dll.a", + "foo.exe.a" + ], + test_dir: "dylib3".to_string(), + }, || { rustc() .crate_type("dylib") @@ -203,55 +372,121 @@ fn main() { }, ); - assert_expected_output_files(&["foo"], &[], "staticlib", || { - rustc().crate_type("staticlib").input("foo.rs").output("staticlib/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "staticlib2", || { - rustc().crate_type("staticlib").input("foo.rs").emit("link=staticlib2/foo").run(); - }); - assert_expected_output_files(&["foo"], &[], "staticlib3", || { - rustc().crate_type("staticlib").input("foo.rs").arg("--emit=link=staticlib3/foo").run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "staticlib".to_string(), + }, + || { + rustc().crate_type("staticlib").input("foo.rs").output("staticlib/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "staticlib2".to_string(), + }, + || { + rustc().crate_type("staticlib").input("foo.rs").emit("link=staticlib2/foo").run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["foo"], + allowed_files: s![], + test_dir: "staticlib3".to_string(), + }, + || { + rustc().crate_type("staticlib").input("foo.rs").arg("--emit=link=staticlib3/foo").run(); + }, + ); - assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate", || { - rustc().crate_type("bin").input("foo.rs").output("bincrate/".to_owned() + bin_foo).run(); - }); - assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate2", || { - rustc().crate_type("bin").input("foo.rs").emit(&format!("link=bincrate2/{bin_foo}")).run(); - }); - assert_expected_output_files(&["foo"], &["foo.pdb"], "bincrate3", || { - rustc() - .crate_type("bin") - .input("foo.rs") - .arg(&format!("--emit=link=bincrate3/{bin_foo}")) - .run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s![bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "bincrate".to_string(), + }, + || { + rustc() + .crate_type("bin") + .input("foo.rs") + .output("bincrate/".to_owned() + &bin_foo) + .run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s![bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "bincrate2".to_string(), + }, + || { + rustc() + .crate_type("bin") + .input("foo.rs") + .emit(&format!("link=bincrate2/{bin_foo}")) + .run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s![bin_foo], + allowed_files: s!["foo.pdb"], + test_dir: "bincrate3".to_string(), + }, + || { + rustc() + .crate_type("bin") + .input("foo.rs") + .arg(&format!("--emit=link=bincrate3/{bin_foo}")) + .run(); + }, + ); - assert_expected_output_files(&["ir", rust_bar], &[], "rlib-ir", || { - rustc() - .input("foo.rs") - .emit("llvm-ir=rlib-ir/ir") - .emit("link") - .crate_type("rlib") - .out_dir("rlib-ir") - .run(); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["ir", rust_lib_name("bar")], + allowed_files: s![], + test_dir: "rlib-ir".to_string(), + }, + || { + rustc() + .input("foo.rs") + .emit("llvm-ir=rlib-ir/ir") + .emit("link") + .crate_type("rlib") + .out_dir("rlib-ir") + .run(); + }, + ); - assert_expected_output_files(&["ir", "asm", "bc", "obj", "link"], &[], "staticlib-all", || { - rustc() - .input("foo.rs") - .emit("asm=staticlib-all/asm") - .emit("llvm-ir=staticlib-all/ir") - .emit("llvm-bc=staticlib-all/bc") - .emit("obj=staticlib-all/obj") - .emit("link=staticlib-all/link") - .crate_type("staticlib") - .run(); - }); - assert_expected_output_files( - &["ir", "asm", "bc", "obj", "link"], - &[], - "staticlib-all2", + assert_expected_output_files( + Expectations { + expected_files: s!["ir", "asm", "bc", "obj", "link"], + allowed_files: s![], + test_dir: "staticlib-all".to_string(), + }, + || { + rustc() + .input("foo.rs") + .emit("asm=staticlib-all/asm") + .emit("llvm-ir=staticlib-all/ir") + .emit("llvm-bc=staticlib-all/bc") + .emit("obj=staticlib-all/obj") + .emit("link=staticlib-all/link") + .crate_type("staticlib") + .run(); + }, + ); + assert_expected_output_files( + Expectations { + expected_files: s!["ir", "asm", "bc", "obj", "link"], + allowed_files: s![], + test_dir: "staticlib-all2".to_string(), + }, || { rustc() .input("foo.rs") @@ -268,9 +503,11 @@ fn main() { ); assert_expected_output_files( - &["bar.ll", "bar.s", "bar.o", static_bar], - &["bar.bc"], // keep this one for the next test - "staticlib-all3", + Expectations { + expected_files: s!["bar.ll", "bar.s", "bar.o", static_lib_name("bar")], + allowed_files: s!["bar.bc"], // keep this one for the next test + test_dir: "staticlib-all3".to_string(), + }, || { rustc() .input("foo.rs") @@ -283,9 +520,24 @@ fn main() { // the .bc file from the previous test should be equivalent to this one, despite the difference // in crate type - assert_expected_output_files(&["bar.bc", rust_bar, "foo.bc"], &[], "rlib-emits", || { - fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); - rustc().input("foo.rs").emit("llvm-bc,link").crate_type("rlib").out_dir("rlib-emits").run(); - assert_eq!(fs_wrapper::read("rlib-emits/foo.bc"), fs_wrapper::read("rlib-emits/bar.bc")); - }); + assert_expected_output_files( + Expectations { + expected_files: s!["bar.bc", rust_lib_name("bar"), "foo.bc"], + allowed_files: s![], + test_dir: "rlib-emits".to_string(), + }, + || { + fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); + rustc() + .input("foo.rs") + .emit("llvm-bc,link") + .crate_type("rlib") + .out_dir("rlib-emits") + .run(); + assert_eq!( + fs_wrapper::read("rlib-emits/foo.bc"), + fs_wrapper::read("rlib-emits/bar.bc") + ); + }, + ); } From c9be69fd0a6214902749338074c7617cb9f40366 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 13:51:53 -0400 Subject: [PATCH 173/189] Add shallow_find_files helper function to run-make-support --- src/tools/run-make-support/src/lib.rs | 1 + tests/run-make/pgo-gen/rmake.rs | 12 ++++++------ tests/run-make/pgo-use/rmake.rs | 27 ++++++++++++++------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 6c1bcc6d7cd90..af5ae6a8e608c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -272,6 +272,7 @@ pub fn shallow_find_files, F: Fn(&PathBuf) -> bool>( for entry in fs_wrapper::read_dir(path) { let entry = entry.expect("failed to read directory entry."); let path = entry.path(); + if path.is_file() && closure(&path) { matching_files.push(path); } diff --git a/tests/run-make/pgo-gen/rmake.rs b/tests/run-make/pgo-gen/rmake.rs index d35b29302648e..ad2f6388e8fff 100644 --- a/tests/run-make/pgo-gen/rmake.rs +++ b/tests/run-make/pgo-gen/rmake.rs @@ -6,13 +6,13 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{cwd, find_files_by_prefix_and_extension, run, rustc}; +use run_make_support::{cwd, has_extension, has_prefix, run, rustc, shallow_find_files}; fn main() { - rustc().arg("-g").profile_generate(cwd()).run(); + rustc().arg("-g").profile_generate(cwd()).input("test.rs").run(); run("test"); - assert!( - find_files_by_prefix_and_extension(cwd(), "default", "profraw").len() > 0, - "no .profraw file generated" - ); + let profraw_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + assert!(!profraw_files.is_empty(), "no .profraw file generated"); } diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index 04777821b51b0..0f76aff80d0ca 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -9,8 +9,8 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, find_files_by_prefix_and_extension, fs_wrapper, llvm_filecheck, llvm_profdata, - run_with_args, rustc, + cwd, fs_wrapper, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args, + rustc, shallow_find_files, }; fn main() { @@ -28,11 +28,11 @@ fn main() { // Run it in order to generate some profiling data run_with_args("main", &["some-argument"]); // Postprocess the profiling data so it can be used by the compiler - llvm_profdata() - .merge() - .output("merged.profdata") - .input(find_files_by_prefix_and_extension(cwd(), "default", "profraw").get(0).unwrap()) - .run(); + let profraw_files = shallow_find_files(cwd(), |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profraw_file = profraw_files.get(0).unwrap(); + llvm_profdata().merge().output("merged.profdata").input(profraw_file).run(); // Compile the test program again, making use of the profiling data rustc() .opt_level("2") @@ -42,13 +42,14 @@ fn main() { .emit("llvm-ir") .input("main.rs") .run(); - // Check that the generate IR contains some things that we expect - // - // We feed the file into LLVM FileCheck tool *in reverse* so that we see the + // Check that the generate IR contains some things that we expect. + // We feed the file into LLVM FileCheck tool *with its lines reversed* so that we see the // line with the function name before the line with the function attributes. // FileCheck only supports checking that something matches on the next line, // but not if something matches on the previous line. - let mut bytes = fs_wrapper::read("interesting.ll"); - bytes.reverse(); - llvm_filecheck().patterns("filecheck-patterns.txt").stdin(bytes).run(); + let ir = fs_wrapper::read_to_string("main.ll"); + let lines: Vec<_> = ir.lines().rev().collect(); + let mut reversed_ir = lines.join("\n"); + reversed_ir.push('\n'); + llvm_filecheck().patterns("filecheck-patterns.txt").stdin(reversed_ir.as_bytes()).run(); } From 7dca61b68b50b7e38bf3cec027eec2002755b2a4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 5 Jul 2024 15:00:40 +0000 Subject: [PATCH 174/189] Use `ControlFlow` results for visitors that are only looking for a single value --- .../src/diagnostics/conflict_errors.rs | 61 ++++++--------- .../src/deriving/default.rs | 2 +- .../src/collect/generics_of.rs | 74 ++++++++----------- .../src/fn_ctxt/inspect_obligations.rs | 2 - .../src/traits/object_safety.rs | 5 +- .../rustc_trait_selection/src/traits/wf.rs | 2 - 6 files changed, 59 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e291ebd9bb832..c2c3f5bc79ed1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -39,6 +39,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use std::iter; +use std::ops::ControlFlow; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -784,20 +785,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// binding declaration within every scope we inspect. struct Finder { hir_id: hir::HirId, - found: bool, } impl<'hir> Visitor<'hir> for Finder { - fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) { + type Result = ControlFlow<()>; + fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result { if pat.hir_id == self.hir_id { - self.found = true; + return ControlFlow::Break(()); } - hir::intravisit::walk_pat(self, pat); + hir::intravisit::walk_pat(self, pat) } - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { + fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result { if ex.hir_id == self.hir_id { - self.found = true; + return ControlFlow::Break(()); } - hir::intravisit::walk_expr(self, ex); + hir::intravisit::walk_expr(self, ex) } } // The immediate HIR parent of the moved expression. We'll look for it to be a call. @@ -822,9 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { _ => continue, }; if let Some(&hir_id) = local_hir_id { - let mut finder = Finder { hir_id, found: false }; - finder.visit_expr(e); - if finder.found { + if (Finder { hir_id }).visit_expr(e).is_break() { // The current scope includes the declaration of the binding we're accessing, we // can't look up any further for loops. break; @@ -839,9 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(cond, ..), .. }) => { - let mut finder = Finder { hir_id: expr.hir_id, found: false }; - finder.visit_expr(cond); - if finder.found { + if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() { // The expression where the move error happened is in a `while let` // condition Don't suggest clone as it will likely end in an // infinite loop. @@ -1837,7 +1834,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pub struct Holds<'tcx> { ty: Ty<'tcx>, - holds: bool, } impl<'tcx> TypeVisitor> for Holds<'tcx> { @@ -1845,7 +1841,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { if t == self.ty { - self.holds = true; + return ControlFlow::Break(()); } t.super_visit_with(self) } @@ -1863,9 +1859,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { && rcvr_ty == ty && let ty::Ref(_, inner, _) = rcvr_ty.kind() && let inner = inner.peel_refs() - && let mut v = (Holds { ty: inner, holds: false }) - && let _ = v.visit_ty(local_ty) - && v.holds + && (Holds { ty: inner }).visit_ty(local_ty).is_break() && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) { err.span_label( @@ -4325,15 +4319,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { } /// Detect whether one of the provided spans is a statement nested within the top-most visited expr -struct ReferencedStatementsVisitor<'a>(&'a [Span], bool); +struct ReferencedStatementsVisitor<'a>(&'a [Span]); -impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { +impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> { + type Result = ControlFlow<()>; + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result { match s.kind { - hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => { - self.1 = true; - } - _ => {} + hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } } } @@ -4375,9 +4368,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, None) => { // `if` expressions with no `else` that initialize the binding might be missing an // `else` arm. - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_expr(body); - if v.1 { + if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() { self.errors.push(( cond.span, format!( @@ -4394,11 +4385,9 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, Some(other)) => { // `if` expressions where the binding is only initialized in one of the two arms // might be missing a binding initialization. - let mut a = ReferencedStatementsVisitor(self.spans, false); - a.visit_expr(body); - let mut b = ReferencedStatementsVisitor(self.spans, false); - b.visit_expr(other); - match (a.1, b.1) { + let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break(); + let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break(); + match (a, b) { (true, true) | (false, false) => {} (true, false) => { if other.span.is_desugaring(DesugaringKind::WhileLoop) { @@ -4437,11 +4426,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { // arms might be missing an initialization. let results: Vec = arms .iter() - .map(|arm| { - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_arm(arm); - v.1 - }) + .map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break()) .collect(); if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { for (arm, seen) in arms.iter().zip(results) { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 577523a1d5a32..7a65ed97f00c2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -240,7 +240,7 @@ fn has_a_default_variant(item: &Annotatable) -> bool { if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) { ControlFlow::Break(()) } else { - // no need to subrecurse. + // no need to walk the variant, we are only looking for top level variants ControlFlow::Continue(()) } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9b02c1a61fa97..22d465c8e62be 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use crate::middle::resolve_bound_vars as rbv; use hir::{ intravisit::{self, Visitor}, @@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let mut in_param_ty = false; for (_parent, node) in tcx.hir().parent_iter(hir_id) { if let Some(generics) = node.generics() { - let mut visitor = AnonConstInParamTyDetector { - in_param_ty: false, - found_anon_const_in_param_ty: false, - ct: hir_id, - }; + let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id }; - visitor.visit_generics(generics); - in_param_ty = visitor.found_anon_const_in_param_ty; + in_param_ty = visitor.visit_generics(generics).is_break(); break; } } @@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { tcx: TyCtxt<'tcx>, outer_index: ty::DebruijnIndex, - has_late_bound_regions: Option, } impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + type Result = ControlFlow; + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { match ty.kind { hir::TyKind::BareFn(..) => { self.outer_index.shift_in(1); - intravisit::walk_ty(self, ty); + let res = intravisit::walk_ty(self, ty); self.outer_index.shift_out(1); + res } _ => intravisit::walk_ty(self, ty), } } - fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow { self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, tr); + let res = intravisit::walk_poly_trait_ref(self, tr); self.outer_index.shift_out(1); + res } - fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - if self.has_late_bound_regions.is_some() { - return; - } - + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow { match self.tcx.named_bound_var(lt.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} + Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => { + ControlFlow::Continue(()) + } Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) - if debruijn < self.outer_index => {} + if debruijn < self.outer_index => + { + ControlFlow::Continue(()) + } Some( rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..) | rbv::ResolvedArg::Error(_), ) - | None => { - self.has_late_bound_regions = Some(lt.ident.span); - } + | None => ControlFlow::Break(lt.ident.span), } } } @@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option, decl: &'tcx hir::FnDecl<'tcx>, ) -> Option { - let mut visitor = LateBoundRegionsDetector { - tcx, - outer_index: ty::INNERMOST, - has_late_bound_regions: None, - }; + let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST }; for param in generics.params { if let GenericParamKind::Lifetime { .. } = param.kind { if tcx.is_late_bound(param.hir_id) { @@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option Visitor<'v> for AnonConstInParamTyDetector { - fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + type Result = ControlFlow<()>; + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; - self.visit_ty(ty); + let res = self.visit_ty(ty); self.in_param_ty = prev; + res + } else { + ControlFlow::Continue(()) } } - fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result { if self.in_param_ty && self.ct == c.hir_id { - self.found_anon_const_in_param_ty = true; - } else { - intravisit::walk_anon_const(self, c) + return ControlFlow::Break(()); } + intravisit::walk_anon_const(self, c) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index fab7eb7495c5f..90dd5f73586b3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> { } impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { - type Result = (); - fn span(&self) -> Span { self.root_cause.span } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index f1611bd049de9..5b2c8fb1950d8 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -805,10 +805,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable>>( .unwrap() .contains(&data.trait_ref(self.tcx).def_id); + // only walk contained types if it's not a super trait if is_supertrait_of_current_trait { - ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200 + ControlFlow::Continue(()) } else { - t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error + t.super_visit_with(self) // POSSIBLY reporting an error } } _ => t.super_visit_with(self), // walk contained types, if any diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e3952679f96b3..f071dc6c78486 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -640,8 +640,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { - type Result = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); From 5fd5b650935c27754dcf8cef06df37c3b91818eb Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 5 Jul 2024 11:06:18 -0400 Subject: [PATCH 175/189] Rename edition 2021 fail test --- ....rs => ref_pat_eat_one_layer_2021_fail.rs} | 0 ...=> ref_pat_eat_one_layer_2021_fail.stderr} | 20 +++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) rename tests/ui/match/ref_pat_eat_one_layer_2024/{ref_pat_eat_one_layer_2021.rs => ref_pat_eat_one_layer_2021_fail.rs} (100%) rename tests/ui/match/ref_pat_eat_one_layer_2024/{ref_pat_eat_one_layer_2021.stderr => ref_pat_eat_one_layer_2021_fail.stderr} (88%) diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs similarity index 100% rename from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs rename to tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr similarity index 88% rename from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr rename to tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr index 28706f89c066b..1a921234ea069 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:5:22 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:5:22 | LL | if let Some(Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -14,7 +14,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:10:23 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:10:23 | LL | let _: &u32 = x; | ---- ^ expected `&u32`, found integer @@ -27,7 +27,7 @@ LL | let _: &u32 = &x; | + error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:13:23 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:13:23 | LL | if let Some(Some(&&x)) = &Some(Some(&0)) { | ^^ --------------- this expression has type `&Option>` @@ -43,7 +43,7 @@ LL + if let Some(Some(&x)) = &Some(Some(&0)) { | error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:17:17 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:17:17 | LL | if let Some(&Some(x)) = &Some(Some(0)) { | ^^^^^^^^ -------------- this expression has type `&Option>` @@ -54,7 +54,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) { found reference `&_` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` @@ -64,7 +64,7 @@ LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22 | LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { | ^^^^^^ @@ -74,7 +74,7 @@ LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:25:22 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:25:22 | LL | if let Some(Some(&x)) = &Some(&Some(0)) { | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` @@ -89,7 +89,7 @@ LL | if let Some(Some(x)) = &Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:29:27 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:29:27 | LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` @@ -104,7 +104,7 @@ LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23 | LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` @@ -114,7 +114,7 @@ LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { = note: expected type `{integer}` found mutable reference `&mut _` note: to declare a mutable binding use: `mut x` - --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23 + --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23 | LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) { | ^^^^^^ From 291ed596f71b4a9829cb1d93a177a52b677deabd Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Fri, 5 Jul 2024 18:10:05 +0300 Subject: [PATCH 176/189] Added dots at the sentence ends of rustc AST doc --- compiler/rustc_ast/src/ast.rs | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index dbbc4980050de..1e1339fe14457 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -176,7 +176,7 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), - /// `(..)` in return type notation + /// `(..)` in return type notation. ParenthesizedElided(Span), } @@ -197,11 +197,11 @@ impl GenericArgs { /// Concrete argument in the sequence of generic args. #[derive(Clone, Encodable, Decodable, Debug)] pub enum GenericArg { - /// `'a` in `Foo<'a>` + /// `'a` in `Foo<'a>`. Lifetime(Lifetime), - /// `Bar` in `Foo` + /// `Bar` in `Foo`. Type(P), - /// `1` in `Foo<1>` + /// `1` in `Foo<1>`. Const(AnonConst), } @@ -355,7 +355,7 @@ pub enum GenericParamKind { ty: P, /// Span of the `const` keyword. kw_span: Span, - /// Optional default value for the const generic param + /// Optional default value for the const generic param. default: Option, }, } @@ -832,7 +832,7 @@ pub enum PatKind { /// only one rest pattern may occur in the pattern sequences. Rest, - // A never pattern `!` + // A never pattern `!`. Never, /// Parentheses in patterns used for grouping (i.e., `(PAT)`). @@ -1121,9 +1121,9 @@ impl LocalKind { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Arm { pub attrs: AttrVec, - /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }` + /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`. pub pat: P, - /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }` + /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`. pub guard: Option>, /// Match arm body. Omitted if the pattern is a never pattern. pub body: Option>, @@ -1354,12 +1354,12 @@ pub struct Closure { pub fn_arg_span: Span, } -/// Limit types of a range (inclusive or exclusive) +/// Limit types of a range (inclusive or exclusive). #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)] pub enum RangeLimits { - /// Inclusive at the beginning, exclusive at the end + /// Inclusive at the beginning, exclusive at the end. HalfOpen, - /// Inclusive at the beginning and end + /// Inclusive at the beginning and end. Closed, } @@ -1400,9 +1400,9 @@ pub struct StructExpr { pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). Array(ThinVec>), - /// Allow anonymous constants from an inline `const` block + /// Allow anonymous constants from an inline `const` block. ConstBlock(AnonConst), - /// A function call + /// A function call. /// /// The first field resolves to the function itself, /// and the second field is the list of arguments. @@ -1456,7 +1456,7 @@ pub enum ExprKind { /// A block (`'label: { ... }`). Block(P, Option(legacy::Range); + +impl IterRange { + /// Returns the remainder of the range being iterated over. + pub fn remainder(self) -> Range { + Range { start: self.0.start, end: self.0.end } + } +} + +/// Safety: This macro must only be used on types that are `Copy` and result in ranges +/// which have an exact `size_hint()` where the upper bound must not be `None`. +macro_rules! unsafe_range_trusted_random_access_impl { + ($($t:ty)*) => ($( + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe impl TrustedRandomAccess for IterRange<$t> {} + + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe impl TrustedRandomAccessNoCoerce for IterRange<$t> { + const MAY_HAVE_SIDE_EFFECT: bool = false; + } + )*) +} + +unsafe_range_trusted_random_access_impl! { + usize u8 u16 + isize i8 i16 +} + +#[cfg(target_pointer_width = "32")] +unsafe_range_trusted_random_access_impl! { + u32 i32 +} + +#[cfg(target_pointer_width = "64")] +unsafe_range_trusted_random_access_impl! { + u32 i32 + u64 i64 +} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl Iterator for IterRange { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.0.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.0.last() + } + + #[inline] + fn min(self) -> Option + where + A: Ord, + { + self.0.min() + } + + #[inline] + fn max(self) -> Option + where + A: Ord, + { + self.0.max() + } + + #[inline] + fn is_sorted(self) -> bool { + true + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.0.advance_by(n) + } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccessNoCoerce, + { + // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + // Additionally Self: TrustedRandomAccess is only implemented for Copy types + // which means even repeated reads of the same index would be safe. + unsafe { Step::forward_unchecked(self.0.start.clone(), idx) } + } +} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl DoubleEndedIterator for IterRange { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.0.advance_back_by(n) + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IterRange {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl FusedIterator for IterRange {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl IntoIterator for Range { + type Item = A; + type IntoIter = IterRange; + + fn into_iter(self) -> Self::IntoIter { + IterRange(self.into()) + } +} + +/// By-value [`RangeInclusive`] iterator. +#[unstable(feature = "new_range_api", issue = "125687")] +#[derive(Debug, Clone)] +pub struct IterRangeInclusive(legacy::RangeInclusive); + +impl IterRangeInclusive { + /// Returns the remainder of the range being iterated over. + /// + /// If the iterator is exhausted or empty, returns `None`. + pub fn remainder(self) -> Option> { + if self.0.is_empty() { + return None; + } + + Some(RangeInclusive { start: self.0.start, end: self.0.end }) + } +} + +#[unstable(feature = "trusted_random_access", issue = "none")] +impl Iterator for IterRangeInclusive { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.0.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.0.last() + } + + #[inline] + fn min(self) -> Option + where + A: Ord, + { + self.0.min() + } + + #[inline] + fn max(self) -> Option + where + A: Ord, + { + self.0.max() + } + + #[inline] + fn is_sorted(self) -> bool { + true + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.0.advance_by(n) + } +} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl DoubleEndedIterator for IterRangeInclusive { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.0.advance_back_by(n) + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IterRangeInclusive {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl FusedIterator for IterRangeInclusive {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl IntoIterator for RangeInclusive { + type Item = A; + type IntoIter = IterRangeInclusive; + + fn into_iter(self) -> Self::IntoIter { + IterRangeInclusive(self.into()) + } +} + +// These macros generate `ExactSizeIterator` impls for various range types. +// +// * `ExactSizeIterator::len` is required to always return an exact `usize`, +// so no range can be longer than `usize::MAX`. +// * For integer types in `Range<_>` this is the case for types narrower than or as wide as `usize`. +// For integer types in `RangeInclusive<_>` +// this is the case for types *strictly narrower* than `usize` +// since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`. +macro_rules! range_exact_iter_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "new_range_api", issue = "125687")] + impl ExactSizeIterator for IterRange<$t> { } + )*) +} + +macro_rules! range_incl_exact_iter_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "new_range_api", issue = "125687")] + impl ExactSizeIterator for IterRangeInclusive<$t> { } + )*) +} + +range_exact_iter_impl! { + usize u8 u16 + isize i8 i16 +} + +range_incl_exact_iter_impl! { + u8 + i8 +} + +/// By-value [`RangeFrom`] iterator. +#[unstable(feature = "new_range_api", issue = "125687")] +#[derive(Debug, Clone)] +pub struct IterRangeFrom(legacy::RangeFrom); + +impl IterRangeFrom { + /// Returns the remainder of the range being iterated over. + pub fn remainder(self) -> RangeFrom { + RangeFrom { start: self.0.start } + } +} + +#[unstable(feature = "trusted_random_access", issue = "none")] +impl Iterator for IterRangeFrom { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IterRangeFrom {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl FusedIterator for IterRangeFrom {} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl IntoIterator for RangeFrom { + type Item = A; + type IntoIter = IterRangeFrom; + + fn into_iter(self) -> Self::IntoIter { + IterRangeFrom(self.into()) + } +} diff --git a/library/core/src/range/legacy.rs b/library/core/src/range/legacy.rs new file mode 100644 index 0000000000000..6723c4903f756 --- /dev/null +++ b/library/core/src/range/legacy.rs @@ -0,0 +1,10 @@ +//! # Legacy range types +//! +//! The types within this module will be replaced by the types +//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent +//! module, [`core::range`]. +//! +//! The types here are equivalent to those in [`core::ops`]. + +#[doc(inline)] +pub use crate::ops::{Range, RangeFrom, RangeInclusive}; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 143dbd8a496d0..2624a44bb4bcb 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -2,6 +2,7 @@ use crate::intrinsics::const_eval_select; use crate::ops; +use crate::range; use crate::ub_checks::assert_unsafe_precondition; #[stable(feature = "rust1", since = "1.0.0")] @@ -147,7 +148,8 @@ const unsafe fn get_offset_len_mut_noubcheck( } mod private_slice_index { - use super::ops; + use super::{ops, range}; + #[stable(feature = "slice_get_slice", since = "1.28.0")] pub trait Sealed {} @@ -168,6 +170,13 @@ mod private_slice_index { #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] impl Sealed for (ops::Bound, ops::Bound) {} + #[unstable(feature = "new_range_api", issue = "125687")] + impl Sealed for range::Range {} + #[unstable(feature = "new_range_api", issue = "125687")] + impl Sealed for range::RangeInclusive {} + #[unstable(feature = "new_range_api", issue = "125687")] + impl Sealed for range::RangeFrom {} + impl Sealed for ops::IndexRange {} } @@ -473,6 +482,43 @@ unsafe impl SliceIndex<[T]> for ops::Range { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex<[T]> for range::Range { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + ops::Range::from(self).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + ops::Range::from(self).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { ops::Range::from(self).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { ops::Range::from(self).get_unchecked_mut(slice) } + } + + #[inline(always)] + fn index(self, slice: &[T]) -> &[T] { + ops::Range::from(self).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + ops::Range::from(self).index_mut(slice) + } +} + /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] @@ -559,6 +605,43 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex<[T]> for range::RangeFrom { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + ops::RangeFrom::from(self).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + ops::RangeFrom::from(self).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { ops::RangeFrom::from(self).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { ops::RangeFrom::from(self).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + ops::RangeFrom::from(self).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + ops::RangeFrom::from(self).index_mut(slice) + } +} + #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::RangeFull { @@ -643,6 +726,43 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex<[T]> for range::RangeInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + ops::RangeInclusive::from(self).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + ops::RangeInclusive::from(self).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { ops::RangeInclusive::from(self).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { ops::RangeInclusive::from(self).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + ops::RangeInclusive::from(self).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + ops::RangeInclusive::from(self).index_mut(slice) + } +} + /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] @@ -780,7 +900,7 @@ where /// Performs bounds-checking of a range without panicking. /// -/// This is a version of [`range`] that returns [`None`] instead of panicking. +/// This is a version of [`range()`] that returns [`None`] instead of panicking. /// /// # Examples /// diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index ba2d6f644962e..3de5546c4d4e3 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -4,6 +4,7 @@ use crate::cmp::Ordering; use crate::intrinsics::unchecked_sub; use crate::ops; use crate::ptr; +use crate::range; use crate::slice::SliceIndex; use crate::ub_checks::assert_unsafe_precondition; @@ -261,6 +262,108 @@ unsafe impl SliceIndex for ops::Range { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex for range::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + // We also checked char boundaries, so this is valid UTF-8. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary. + // We know the pointer is unique because we got it from `slice`. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + + assert_unsafe_precondition!( + // We'd like to check that the bounds are on char boundaries, + // but there's not really a way to do so without reading + // behind the pointer, which has aliasing implications. + // It's also not possible to move this check up to + // `str::get_unchecked` without adding a special function + // to `SliceIndex` just for this. + check_library_ub, + "str::get_unchecked requires that the range is within the string slice", + ( + start: usize = self.start, + end: usize = self.end, + len: usize = slice.len() + ) => end >= start && end <= len, + ); + + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str + } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + + assert_unsafe_precondition!( + check_library_ub, + "str::get_unchecked_mut requires that the range is within the string slice", + ( + start: usize = self.start, + end: usize = self.end, + len: usize = slice.len() + ) => end >= start && end <= len, + ); + + // SAFETY: see comments for `get_unchecked`. + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str + } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // cannot reuse `get` as above, because of NLL trouble + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } +} + /// Implements substring slicing for arbitrary bounds. /// /// Returns a slice of the given string bounded by the byte indices @@ -453,6 +556,61 @@ unsafe impl SliceIndex for ops::RangeFrom { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex for range::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let len = (slice as *const [u8]).len(); + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (self.start..len).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let len = (slice as *mut [u8]).len(); + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (self.start..len).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } +} + /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut /// self[begin ..= end]`. /// @@ -507,6 +665,43 @@ unsafe impl SliceIndex for ops::RangeInclusive { } } +#[unstable(feature = "new_range_api", issue = "125687")] +unsafe impl SliceIndex for range::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { self.into_slice_range().get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { self.into_slice_range().get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + self.into_slice_range().index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + self.into_slice_range().index_mut(slice) + } +} + /// Implements substring slicing with syntax `&self[..= end]` or `&mut /// self[..= end]`. /// diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 7321bd1bb52f2..72ae3ed26e89f 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -59,6 +59,8 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ // This is being used in the sense of 'inclusive range', not a markdown link ("core/ops/struct.RangeInclusive.html", &["begin, end"]), ("std/ops/struct.RangeInclusive.html", &["begin, end"]), + ("core/range/legacy/struct.RangeInclusive.html", &["begin, end"]), + ("std/range/legacy/struct.RangeInclusive.html", &["begin, end"]), ("core/slice/trait.SliceIndex.html", &["begin, end"]), ("alloc/slice/trait.SliceIndex.html", &["begin, end"]), ("std/slice/trait.SliceIndex.html", &["begin, end"]), diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 1694d514f4251..f15a0ae61389a 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -7,7 +7,7 @@ LL | take_range(0..1); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `Range<{integer}>` + found struct `core::ops::Range<{integer}>` note: function defined here --> $DIR/issue-54505-no-std.rs:25:4 | @@ -27,7 +27,7 @@ LL | take_range(1..); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeFrom<{integer}>` + found struct `core::ops::RangeFrom<{integer}>` note: function defined here --> $DIR/issue-54505-no-std.rs:25:4 | @@ -67,7 +67,7 @@ LL | take_range(0..=1); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeInclusive<{integer}>` + found struct `core::ops::RangeInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-std.rs:25:4 | From 99429a6a18cbc671c313ac8df17aa163729bc284 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 5 Jul 2024 16:02:35 -0400 Subject: [PATCH 189/189] Split out transitive_bounds_that_define_assoc_item --- compiler/rustc_infer/src/traits/util.rs | 39 ++++++++++++++++--------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index def341beceb9d..18d36c3a5df34 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -3,6 +3,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -82,7 +83,6 @@ pub struct Elaborator<'tcx, O> { enum Filter { All, OnlySelf, - OnlySelfThatDefines(Ident), } /// Describes how to elaborate an obligation into a sub-obligation. @@ -252,12 +252,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { self } - /// Filter to only the supertraits of trait predicates that define the assoc_ty. - pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self { - self.mode = Filter::OnlySelfThatDefines(assoc_ty); - self - } - fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; @@ -277,9 +271,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let predicates = match self.mode { Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), - Filter::OnlySelfThatDefines(ident) => { - tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) - } }; let obligations = @@ -427,10 +418,30 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, assoc_name: Ident, -) -> FilterToTraits>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) - .filter_only_self_that_defines(assoc_name) - .filter_to_traits() +) -> impl Iterator> { + let mut seen = FxHashSet::default(); + let mut stack: Vec<_> = trait_refs.collect(); + + std::iter::from_fn(move || { + while let Some(trait_ref) = stack.pop() { + if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) { + continue; + } + + stack.extend( + tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name)) + .instantiate_own_identity() + .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref)) + .filter_map(|clause| clause.as_trait_clause()) + // FIXME: Negative supertraits are elaborated here lol + .map(|trait_pred| trait_pred.to_poly_trait_ref()), + ); + + return Some(trait_ref); + } + + None + }) } ///////////////////////////////////////////////////////////////////////////