From 7e3e8bdec4c992d2ec7474c1b70fb61aaaa9ed7e Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 10:32:12 +0200 Subject: [PATCH 01/34] Updated feature and stable flags --- library/core/src/result.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 736ffb7d0caf..1bf713eaa890 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1692,7 +1692,6 @@ impl Result, E> { /// # Examples /// /// ``` - /// #![feature(result_flattening)] /// let x: Result, u32> = Ok(Ok("hello")); /// assert_eq!(Ok("hello"), x.flatten()); /// @@ -1706,14 +1705,14 @@ impl Result, E> { /// Flattening only removes one level of nesting at a time: /// /// ``` - /// #![feature(result_flattening)] /// let x: Result, u32>, u32> = Ok(Ok(Ok("hello"))); /// assert_eq!(Ok(Ok("hello")), x.flatten()); /// assert_eq!(Ok("hello"), x.flatten().flatten()); /// ``` #[inline] - #[unstable(feature = "result_flattening", issue = "70142")] - #[rustc_const_unstable(feature = "result_flattening", issue = "70142")] + #[stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] pub const fn flatten(self) -> Result { // FIXME(const-hack): could be written with `and_then` match self { From 4c2d3bc8bd663d619ae8502bc62afb49efb0ddfa Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 12:00:44 +0200 Subject: [PATCH 02/34] Removed feature flag from `compiler/rustc_driver_impl` --- compiler/rustc_driver_impl/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 056c476d5e12..54a331a49044 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -12,7 +12,6 @@ #![feature(decl_macro)] #![feature(panic_backtrace_config)] #![feature(panic_update_hook)] -#![feature(result_flattening)] #![feature(rustdoc_internals)] #![feature(try_blocks)] // tidy-alphabetical-end From 48538ed16b8f32eddaa5476dab4d461e4b35026c Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 13:28:33 +0200 Subject: [PATCH 03/34] Updated feature flag and output of `clippy/tests/ui/map_flatten*` --- src/tools/clippy/tests/ui/map_flatten.rs | 2 +- .../clippy/tests/ui/map_flatten_fixable.fixed | 1 - .../clippy/tests/ui/map_flatten_fixable.rs | 1 - .../clippy/tests/ui/map_flatten_fixable.stderr | 18 +++++++++--------- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index d7e9c9d9900d..0970da8039a4 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -1,5 +1,5 @@ #![warn(clippy::map_flatten)] -#![feature(result_flattening)] + //@no-rustfix // issue #8506, multi-line #[rustfmt::skip] diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed index f8379ed23c5b..6d8a27d3018d 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs index 040a9ca85f64..845e3a79ae2b 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr index fe68eb7e4ab4..05d4d9a6ad85 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:17:47 + --> tests/ui/map_flatten_fixable.rs:16:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` @@ -8,43 +8,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:19:47 + --> tests/ui/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:21:47 + --> tests/ui/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:23:47 + --> tests/ui/map_flatten_fixable.rs:22:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:27:47 + --> tests/ui/map_flatten_fixable.rs:26:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:31:40 + --> tests/ui/map_flatten_fixable.rs:30:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten_fixable.rs:35:42 + --> tests/ui/map_flatten_fixable.rs:34:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:45:10 + --> tests/ui/map_flatten_fixable.rs:44:10 | LL | .map(|n| match n { | __________^ @@ -74,7 +74,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:66:10 + --> tests/ui/map_flatten_fixable.rs:65:10 | LL | .map(|_| { | __________^ From cb07fd8cf767d1f158ab1bfb06a7f99deebf8c82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 May 2025 08:56:00 +0200 Subject: [PATCH 04/34] Miri CI: test aarch64-apple-darwin in PRs instead of the x86_64 target --- src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh | 6 +++--- src/ci/github-actions/jobs.yml | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 9222710b8437..62e0451814b3 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -53,8 +53,8 @@ MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zm case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. - # Fully test all main OSes, including a 32bit target. - python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target x86_64-apple-darwin + # Fully test all main OSes, and all main architectures. + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target aarch64-apple-darwin python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc # Only run "pass" tests for the remaining targets, which is quite a bit faster. python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass @@ -69,7 +69,7 @@ case $HOST_TARGET in #FIXME: Re-enable this once CI issues are fixed # See # For now, these tests are moved to `x86_64-msvc-ext2` in `src/ci/github-actions/jobs.yml`. - #python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass + #python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass ;; *) echo "FATAL: unexpected host $HOST_TARGET" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 42ad5acbdac1..988d1057630d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -522,11 +522,13 @@ auto: - name: x86_64-msvc-ext2 env: SCRIPT: > - python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass && + python x.py test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass && python x.py test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass && python x.py miri --stage 2 library/core --test-args notest && python x.py miri --stage 2 library/alloc --test-args notest && python x.py miri --stage 2 library/std --test-args notest + # The last 3 lines smoke-test `x.py miri`. This doesn't run any actual tests (that would take + # too long), but it ensures that the crates build properly when tested with Miri. RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld <<: *job-windows From 31ee8400004dd9850fa11cce311e412ceadd7062 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 8 May 2025 16:07:53 +0800 Subject: [PATCH 05/34] Add ui test func-pointer-issue-140491 Signed-off-by: xizheyin --- tests/ui/cast/func-pointer-issue-140491.rs | 7 +++++++ tests/ui/cast/func-pointer-issue-140491.stderr | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/cast/func-pointer-issue-140491.rs create mode 100644 tests/ui/cast/func-pointer-issue-140491.stderr diff --git a/tests/ui/cast/func-pointer-issue-140491.rs b/tests/ui/cast/func-pointer-issue-140491.rs new file mode 100644 index 000000000000..d5d86a66f5a9 --- /dev/null +++ b/tests/ui/cast/func-pointer-issue-140491.rs @@ -0,0 +1,7 @@ +fn my_fn(event: &Event<'_>) {} + +struct Event<'a>(&'a ()); + +fn main() { + const ptr: &fn(&Event<'_>) = &my_fn as _; //~ ERROR non-primitive cast: `&for<'a, 'b> fn(&'a Event<'b>) {my_fn}` as `&for<'a, 'b> fn(&'a Event<'b>)` [E0605] +} diff --git a/tests/ui/cast/func-pointer-issue-140491.stderr b/tests/ui/cast/func-pointer-issue-140491.stderr new file mode 100644 index 000000000000..ebd4b18502ec --- /dev/null +++ b/tests/ui/cast/func-pointer-issue-140491.stderr @@ -0,0 +1,9 @@ +error[E0605]: non-primitive cast: `&for<'a, 'b> fn(&'a Event<'b>) {my_fn}` as `&for<'a, 'b> fn(&'a Event<'b>)` + --> $DIR/func-pointer-issue-140491.rs:6:34 + | +LL | ..._>) = &my_fn as _; + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0605`. From 45197887cb7bd7fd3148249f49e396de625d9a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 27 May 2025 20:18:39 +0000 Subject: [PATCH 06/34] move `MaybeInitializedPlaces` computation to where it's used This dataflow analysis is only used by `liveness::trace`. We move it there to make it lazy. --- compiler/rustc_borrowck/src/lib.rs | 9 +-------- compiler/rustc_borrowck/src/nll.rs | 6 +----- compiler/rustc_borrowck/src/type_check/liveness/mod.rs | 7 ++----- compiler/rustc_borrowck/src/type_check/liveness/trace.rs | 8 +++++--- compiler/rustc_borrowck/src/type_check/mod.rs | 8 ++------ 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 676cb618b725..2bd0ffd143be 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -40,9 +40,7 @@ use rustc_middle::ty::{ self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions, }; use rustc_middle::{bug, span_bug}; -use rustc_mir_dataflow::impls::{ - EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, -}; +use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; @@ -324,10 +322,6 @@ fn do_mir_borrowck<'tcx>( let move_data = MoveData::gather_moves(body, tcx, |_| true); - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .iterate_to_fixpoint(tcx, body, Some("borrowck")) - .into_results_cursor(body); - let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure(); let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data); @@ -346,7 +340,6 @@ fn do_mir_borrowck<'tcx>( body, &promoted, &location_table, - flow_inits, &move_data, &borrow_set, consumer_options, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index fe899bb054fa..8664e99cae36 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -11,8 +11,6 @@ use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; -use rustc_mir_dataflow::ResultsCursor; -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_session::config::MirIncludeSpans; @@ -75,14 +73,13 @@ pub(crate) fn replace_regions_in_mir<'tcx>( /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. -pub(crate) fn compute_regions<'a, 'tcx>( +pub(crate) fn compute_regions<'tcx>( root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, location_table: &PoloniusLocationTable, - flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, consumer_options: Option, @@ -112,7 +109,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( location_table, borrow_set, &mut polonius_facts, - flow_inits, move_data, Rc::clone(&location_map), ); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index b7a21cf48c8f..ca1b850f7665 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -5,8 +5,6 @@ use rustc_middle::mir::{Body, Local, Location, SourceInfo}; use rustc_middle::span_bug; use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeVisitable}; -use rustc_mir_dataflow::ResultsCursor; -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use tracing::debug; @@ -28,10 +26,9 @@ mod trace; /// /// N.B., this computation requires normalization; therefore, it must be /// performed before -pub(super) fn generate<'a, 'tcx>( +pub(super) fn generate<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, location_map: &DenseLocationMap, - flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { debug!("liveness::generate"); @@ -58,7 +55,7 @@ pub(super) fn generate<'a, 'tcx>( let (relevant_live_locals, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body); - trace::trace(typeck, location_map, flow_inits, move_data, relevant_live_locals, boring_locals); + trace::trace(typeck, location_map, move_data, relevant_live_locals, boring_locals); // Mark regions that should be live where they appear within rvalues or within a call: like // args, regions, and types. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 512288a0f7d8..9c00628f71b4 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -7,10 +7,10 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Loc use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; -use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; +use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; @@ -37,15 +37,17 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; /// DROP-LIVE set are to the liveness sets for regions found in the /// `dropck_outlives` result of the variable's type (in particular, /// this respects `#[may_dangle]` annotations). -pub(super) fn trace<'a, 'tcx>( +pub(super) fn trace<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, location_map: &DenseLocationMap, - flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, boring_locals: Vec, ) { let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body); + let flow_inits = MaybeInitializedPlaces::new(typeck.tcx(), typeck.body, move_data) + .iterate_to_fixpoint(typeck.tcx(), typeck.body, Some("borrowck")) + .into_results_cursor(typeck.body); let cx = LivenessContext { typeck, flow_inits, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8c5122571209..9dff03a8a709 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,8 +30,6 @@ use rustc_middle::ty::{ TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, }; use rustc_middle::{bug, span_bug}; -use rustc_mir_dataflow::ResultsCursor; -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; @@ -97,10 +95,9 @@ mod relate_tys; /// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s /// - `borrow_set` -- information about borrows occurring in `body` /// - `polonius_facts` -- when using Polonius, this is the generated set of Polonius facts -/// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `location_map` -- map between MIR `Location` and `PointIndex` -pub(crate) fn type_check<'a, 'tcx>( +pub(crate) fn type_check<'tcx>( root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, @@ -109,7 +106,6 @@ pub(crate) fn type_check<'a, 'tcx>( location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, polonius_facts: &mut Option, - flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, location_map: Rc, ) -> MirTypeckResults<'tcx> { @@ -167,7 +163,7 @@ pub(crate) fn type_check<'a, 'tcx>( typeck.equate_inputs_and_outputs(&normalized_inputs_and_output); typeck.check_signature_annotation(); - liveness::generate(&mut typeck, &location_map, flow_inits, move_data); + liveness::generate(&mut typeck, &location_map, move_data); let opaque_type_values = opaque_types::take_opaques_and_register_member_constraints(&mut typeck); From 10d39f52a94e25181609a415742a43cbccebc51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 27 May 2025 20:21:28 +0000 Subject: [PATCH 07/34] remove unneeded lifetime --- .../src/type_check/liveness/trace.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 9c00628f71b4..151c1ef08504 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -67,7 +67,7 @@ pub(super) fn trace<'tcx>( } /// Contextual state for the type-liveness coroutine. -struct LivenessContext<'a, 'typeck, 'b, 'tcx> { +struct LivenessContext<'a, 'typeck, 'tcx> { /// Current type-checker, giving us our inference context etc. /// /// This also stores the body we're currently analyzing. @@ -84,7 +84,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> { /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. @@ -96,8 +96,8 @@ struct DropData<'tcx> { region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>, } -struct LivenessResults<'a, 'typeck, 'b, 'tcx> { - cx: LivenessContext<'a, 'typeck, 'b, 'tcx>, +struct LivenessResults<'a, 'typeck, 'tcx> { + cx: LivenessContext<'a, 'typeck, 'tcx>, /// Set of points that define the current local. defs: DenseBitSet, @@ -118,8 +118,8 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> { stack: Vec, } -impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { - fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self { +impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> { + fn new(cx: LivenessContext<'a, 'typeck, 'tcx>) -> Self { let num_points = cx.location_map.num_points(); LivenessResults { cx, @@ -461,10 +461,11 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { } } -impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { +impl<'tcx> LivenessContext<'_, '_, 'tcx> { fn body(&self) -> &Body<'tcx> { self.typeck.body } + /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. From 430e23044914f759f5674cfae542a366f6cca7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 27 May 2025 20:55:58 +0000 Subject: [PATCH 08/34] fast path: compute `MaybeInitializedPlaces` lazily Only drop-liveness checks for maybe-initializedness of move paths, and it does so only for the relevant live locals that have drop points. This adds a fast path by computing this dataflow analysis only when checking for such initializedness. This avoids this expensive computation for the common case. For example, it avoids computing initializedness for 20K locals in the `cranelift-codegen` benchmark, it has 7K relevant live locals but none with drop points. That saves 900ms on end-to-end compilation times. --- .../src/type_check/liveness/trace.rs | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 151c1ef08504..cf7bd9751e19 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -45,12 +45,9 @@ pub(super) fn trace<'tcx>( boring_locals: Vec, ) { let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body); - let flow_inits = MaybeInitializedPlaces::new(typeck.tcx(), typeck.body, move_data) - .iterate_to_fixpoint(typeck.tcx(), typeck.body, Some("borrowck")) - .into_results_cursor(typeck.body); let cx = LivenessContext { typeck, - flow_inits, + flow_inits: None, location_map, local_use_map, move_data, @@ -83,8 +80,8 @@ struct LivenessContext<'a, 'typeck, 'tcx> { drop_data: FxIndexMap, DropData<'tcx>>, /// Results of dataflow tracking which variables (and paths) have been - /// initialized. - flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + /// initialized. Computed lazily when needed by drop-liveness. + flow_inits: Option>>, /// Index indicating where each variable is assigned, used, or /// dropped. @@ -461,6 +458,28 @@ impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> { } } +impl<'a, 'typeck, 'tcx> LivenessContext<'a, 'typeck, 'tcx> { + /// Computes the `MaybeInitializedPlaces` dataflow analysis if it hasn't been done already. + /// + /// In practice, the results of this dataflow analysis are rarely needed but can be expensive to + /// compute on big functions, so we compute them lazily as a fast path when: + /// - there are relevant live locals + /// - there are drop points for these relevant live locals. + /// + /// This happens as part of the drop-liveness computation: it's the only place checking for + /// maybe-initializedness of `MovePathIndex`es. + fn flow_inits(&mut self) -> &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>> { + self.flow_inits.get_or_insert_with(|| { + let tcx = self.typeck.tcx(); + let body = self.typeck.body; + let flow_inits = MaybeInitializedPlaces::new(tcx, body, self.move_data) + .iterate_to_fixpoint(tcx, body, Some("borrowck")) + .into_results_cursor(body); + flow_inits + }) + } +} + impl<'tcx> LivenessContext<'_, '_, 'tcx> { fn body(&self) -> &Body<'tcx> { self.typeck.body @@ -469,13 +488,14 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. - fn initialized_at_curr_loc(&self, mpi: MovePathIndex) -> bool { - let state = self.flow_inits.get(); + fn initialized_at_curr_loc(&mut self, mpi: MovePathIndex) -> bool { + let flow_inits = self.flow_inits(); + let state = flow_inits.get(); if state.contains(mpi) { return true; } - let move_paths = &self.flow_inits.analysis().move_data().move_paths; + let move_paths = &flow_inits.analysis().move_data().move_paths; move_paths[mpi].find_descendant(move_paths, |mpi| state.contains(mpi)).is_some() } @@ -484,7 +504,8 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { /// DROP of some local variable will have an effect -- note that /// drops, as they may unwind, are always terminators. fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_before_primary_effect(self.body().terminator_loc(block)); + let terminator_location = self.body().terminator_loc(block); + self.flow_inits().seek_before_primary_effect(terminator_location); self.initialized_at_curr_loc(mpi) } @@ -494,7 +515,8 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { /// **Warning:** Does not account for the result of `Call` /// instructions. fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_after_primary_effect(self.body().terminator_loc(block)); + let terminator_location = self.body().terminator_loc(block); + self.flow_inits().seek_after_primary_effect(terminator_location); self.initialized_at_curr_loc(mpi) } From 703e051f36013e620eece08151fd3f6e435fd278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 27 May 2025 21:17:01 +0000 Subject: [PATCH 09/34] add perf fixme for `MaybeInitializedPlaces` domain --- .../rustc_borrowck/src/type_check/liveness/trace.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index cf7bd9751e19..5d30fa71e92c 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -472,6 +472,18 @@ impl<'a, 'typeck, 'tcx> LivenessContext<'a, 'typeck, 'tcx> { self.flow_inits.get_or_insert_with(|| { let tcx = self.typeck.tcx(); let body = self.typeck.body; + // FIXME: reduce the `MaybeInitializedPlaces` domain to the useful `MovePath`s. + // + // This dataflow analysis computes maybe-initializedness of all move paths, which + // explains why it can be expensive on big functions. But this data is only used in + // drop-liveness. Therefore, most of the move paths computed here are ultimately unused, + // even if the results are computed lazily and "no relevant live locals with drop + // points" is the common case. + // + // So we only need the ones for 1) relevant live locals 2) that have drop points. That's + // a much, much smaller domain: in our benchmarks, when it's not zero (the most likely + // case), there are a few dozens compared to e.g. thousands or tens of thousands of + // locals and move paths. let flow_inits = MaybeInitializedPlaces::new(tcx, body, self.move_data) .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); From ddeae148c511d9a0c56f0a442dbefe3fa73213c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 27 May 2025 08:42:00 +0000 Subject: [PATCH 10/34] switch dataflow test to a maybe-uninit analysis This mir-opt test used the maybe-init dataflow analysis but it's now lazy and doesn't emit the graphviz graph when it's not needed anymore. --- tests/mir-opt/dataflow.main.maybe_init.borrowck.dot | 6 ------ tests/mir-opt/dataflow.main.maybe_uninit.borrowck.dot | 6 ++++++ tests/mir-opt/dataflow.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 tests/mir-opt/dataflow.main.maybe_init.borrowck.dot create mode 100644 tests/mir-opt/dataflow.main.maybe_uninit.borrowck.dot diff --git a/tests/mir-opt/dataflow.main.maybe_init.borrowck.dot b/tests/mir-opt/dataflow.main.maybe_init.borrowck.dot deleted file mode 100644 index 7c7d8921fb36..000000000000 --- a/tests/mir-opt/dataflow.main.maybe_init.borrowck.dot +++ /dev/null @@ -1,6 +0,0 @@ -digraph graph_for_def_id_0_3 { - graph[fontname="Courier, monospace"]; - node[fontname="Courier, monospace"]; - edge[fontname="Courier, monospace"]; - bb_0[label=<
bb0
MIRSTATE
(on start){}
0_0 = const ()+_0
Treturn
(on end){_0}
>][shape="none"]; -} diff --git a/tests/mir-opt/dataflow.main.maybe_uninit.borrowck.dot b/tests/mir-opt/dataflow.main.maybe_uninit.borrowck.dot new file mode 100644 index 000000000000..258404b8da78 --- /dev/null +++ b/tests/mir-opt/dataflow.main.maybe_uninit.borrowck.dot @@ -0,0 +1,6 @@ +digraph graph_for_def_id_0_3 { + graph[fontname="Courier, monospace"]; + node[fontname="Courier, monospace"]; + edge[fontname="Courier, monospace"]; + bb_0[label=<
bb0
MIRSTATE
(on start){_0}
0_0 = const ()-_0
Treturn
(on end){}
>][shape="none"]; +} diff --git a/tests/mir-opt/dataflow.rs b/tests/mir-opt/dataflow.rs index 3a28f5d47b9a..5ed3da4c531a 100644 --- a/tests/mir-opt/dataflow.rs +++ b/tests/mir-opt/dataflow.rs @@ -2,5 +2,5 @@ // Test graphviz dataflow output //@ compile-flags: -Z dump-mir=main -Z dump-mir-dataflow -// EMIT_MIR dataflow.main.maybe_init.borrowck.dot +// EMIT_MIR dataflow.main.maybe_uninit.borrowck.dot fn main() {} From b0f6b69b813aae1b7525d222ca1d2ba9c1fa25f1 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Wed, 28 May 2025 14:39:51 +0200 Subject: [PATCH 11/34] Do not move thread-locals before dropping --- .../std/src/sys/thread_local/native/lazy.rs | 84 ++++++++++++------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index 51294285ba01..0cb7fa0ef248 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -1,9 +1,9 @@ -use crate::cell::UnsafeCell; -use crate::hint::unreachable_unchecked; +use crate::cell::{Cell, UnsafeCell}; +use crate::mem::MaybeUninit; use crate::ptr; use crate::sys::thread_local::{abort_on_dtor_unwind, destructors}; -pub unsafe trait DestroyedState: Sized { +pub unsafe trait DestroyedState: Sized + Copy { fn register_dtor(s: &Storage); } @@ -19,15 +19,18 @@ unsafe impl DestroyedState for () { } } -enum State { - Initial, - Alive(T), +#[derive(Copy, Clone)] +enum State { + Uninitialized, + Initializing, + Alive, Destroyed(D), } #[allow(missing_debug_implementations)] pub struct Storage { - state: UnsafeCell>, + state: Cell>, + value: UnsafeCell>, } impl Storage @@ -35,7 +38,10 @@ where D: DestroyedState, { pub const fn new() -> Storage { - Storage { state: UnsafeCell::new(State::Initial) } + Storage { + state: Cell::new(State::Uninitialized), + value: UnsafeCell::new(MaybeUninit::uninit()), + } } /// Gets a pointer to the TLS value, potentially initializing it with the @@ -49,35 +55,45 @@ where /// The `self` reference must remain valid until the TLS destructor is run. #[inline] pub unsafe fn get_or_init(&self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - let state = unsafe { &*self.state.get() }; - match state { - State::Alive(v) => v, - State::Destroyed(_) => ptr::null(), - State::Initial => unsafe { self.initialize(i, f) }, + if let State::Alive = self.state.get() { + self.value.get().cast() + } else { + self.get_or_init_slow(i, f) } } #[cold] - unsafe fn initialize(&self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - // Perform initialization + fn get_or_init_slow(&self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { + // Ensure we have unique access to an uninitialized value. + match self.state.get() { + State::Uninitialized => self.state.set(State::Initializing), + State::Initializing => panic!("thread_local initializer recursively depends on itself"), + State::Alive => return self.value.get().cast(), + State::Destroyed(_) => return ptr::null(), + } + struct BackToUninitOnPanic<'a, D>(&'a Cell>); + impl<'a, D> Drop for BackToUninitOnPanic<'a, D> { + fn drop(&mut self) { + self.0.set(State::Uninitialized); + } + } + + // Get the initial value, making sure that we restore the state to uninitialized + // should f panic. + let on_panic = BackToUninitOnPanic(&self.state); let v = i.and_then(Option::take).unwrap_or_else(f); + crate::mem::forget(on_panic); - let old = unsafe { self.state.get().replace(State::Alive(v)) }; - match old { - // If the variable is not being recursively initialized, register - // the destructor. This might be a noop if the value does not need - // destruction. - State::Initial => D::register_dtor(self), - // Else, drop the old value. This might be changed to a panic. - val => drop(val), - } - - // SAFETY: the state was just set to `Alive` + // SAFETY: we are !Sync so we have exclusive access to self.value. We also ensured + // that the state was uninitialized so we aren't replacing a value we must keep alive. unsafe { - let State::Alive(v) = &*self.state.get() else { unreachable_unchecked() }; - v + self.value.get().write(MaybeUninit::new(v)); } + + self.state.set(State::Alive); + D::register_dtor(self); + self.value.get().cast() } } @@ -92,9 +108,13 @@ unsafe extern "C" fn destroy(ptr: *mut u8) { // Print a nice abort message if a panic occurs. abort_on_dtor_unwind(|| { let storage = unsafe { &*(ptr as *const Storage) }; - // Update the state before running the destructor as it may attempt to - // access the variable. - let val = unsafe { storage.state.get().replace(State::Destroyed(())) }; - drop(val); + if let State::Alive = storage.state.replace(State::Destroyed(())) { + // SAFETY: we ensured the state was Alive, and prevented running the destructor + // twice by updating the state to Destroyed. This is necessary as the destructor + // may attempt to access the variable. + unsafe { + crate::ptr::drop_in_place(storage.value.get().cast::()); + } + } }) } From f70cf59fc19b7717397e9701b4783f744983275f Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Wed, 28 May 2025 14:51:52 +0200 Subject: [PATCH 12/34] Improve safety comment, double-drop is not relevant here --- library/std/src/sys/thread_local/native/lazy.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index 0cb7fa0ef248..7cf2ba5eed84 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -109,9 +109,10 @@ unsafe extern "C" fn destroy(ptr: *mut u8) { abort_on_dtor_unwind(|| { let storage = unsafe { &*(ptr as *const Storage) }; if let State::Alive = storage.state.replace(State::Destroyed(())) { - // SAFETY: we ensured the state was Alive, and prevented running the destructor - // twice by updating the state to Destroyed. This is necessary as the destructor - // may attempt to access the variable. + // SAFETY: we ensured the state was Alive so the value was initialized. + // We also updated the state to Destroyed to prevent the destructor + // from accessing the thread-local variable, as this would violate + // the exclusive access provided by &mut T in Drop::drop. unsafe { crate::ptr::drop_in_place(storage.value.get().cast::()); } From 13bce27e378267203f681470f947208b3e267558 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Wed, 28 May 2025 16:56:02 +0200 Subject: [PATCH 13/34] Do not panic, maintain old behavior --- .../std/src/sys/thread_local/native/lazy.rs | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index 7cf2ba5eed84..c5e2618e10f3 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -22,7 +22,6 @@ unsafe impl DestroyedState for () { #[derive(Copy, Clone)] enum State { Uninitialized, - Initializing, Alive, Destroyed(D), } @@ -64,36 +63,31 @@ where #[cold] fn get_or_init_slow(&self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - // Ensure we have unique access to an uninitialized value. match self.state.get() { - State::Uninitialized => self.state.set(State::Initializing), - State::Initializing => panic!("thread_local initializer recursively depends on itself"), + State::Uninitialized => {} State::Alive => return self.value.get().cast(), State::Destroyed(_) => return ptr::null(), } - struct BackToUninitOnPanic<'a, D>(&'a Cell>); - impl<'a, D> Drop for BackToUninitOnPanic<'a, D> { - fn drop(&mut self) { - self.0.set(State::Uninitialized); - } - } - - // Get the initial value, making sure that we restore the state to uninitialized - // should f panic. - let on_panic = BackToUninitOnPanic(&self.state); let v = i.and_then(Option::take).unwrap_or_else(f); - crate::mem::forget(on_panic); - // SAFETY: we are !Sync so we have exclusive access to self.value. We also ensured - // that the state was uninitialized so we aren't replacing a value we must keep alive. - unsafe { - self.value.get().write(MaybeUninit::new(v)); + match self.state.replace(State::Alive) { + State::Uninitialized => D::register_dtor(self), + + State::Alive => { + // An init occurred during a recursive call, this could be a panic in the future. + + // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer + // has already returned and the next scope only starts after we return + // the pointer. Therefore, there can be no references to the old value. + unsafe { (*self.value.get()).assume_init_drop() } + } + + State::Destroyed(_) => unreachable!(), } - self.state.set(State::Alive); - D::register_dtor(self); - self.value.get().cast() + // SAFETY: we are !Sync so we have exclusive access to self.value. + unsafe { (*self.value.get()).write(v) } } } @@ -113,9 +107,7 @@ unsafe extern "C" fn destroy(ptr: *mut u8) { // We also updated the state to Destroyed to prevent the destructor // from accessing the thread-local variable, as this would violate // the exclusive access provided by &mut T in Drop::drop. - unsafe { - crate::ptr::drop_in_place(storage.value.get().cast::()); - } + unsafe { (*storage.value.get()).assume_init_drop() } } }) } From 8785f7b122bbb83d308035565f243ceb95ce4736 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Wed, 28 May 2025 17:09:15 +0200 Subject: [PATCH 14/34] Add same unsafe bound on get_or_init_slow --- library/std/src/sys/thread_local/native/lazy.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index c5e2618e10f3..2eb1c981edb0 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -57,12 +57,18 @@ where if let State::Alive = self.state.get() { self.value.get().cast() } else { - self.get_or_init_slow(i, f) + unsafe { self.get_or_init_slow(i, f) } } } + /// # Safety + /// The `self` reference must remain valid until the TLS destructor is run. #[cold] - fn get_or_init_slow(&self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { + unsafe fn get_or_init_slow( + &self, + i: Option<&mut Option>, + f: impl FnOnce() -> T, + ) -> *const T { match self.state.get() { State::Uninitialized => {} State::Alive => return self.value.get().cast(), From 9ffbc62cb60f2151a38b6c5e18c016e406d10a62 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Wed, 28 May 2025 17:52:24 +0200 Subject: [PATCH 15/34] When replacing an old value we may not drop it in place --- .../std/src/sys/thread_local/native/lazy.rs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index 2eb1c981edb0..a2bf8d8b968a 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -77,23 +77,19 @@ where let v = i.and_then(Option::take).unwrap_or_else(f); + // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer + // has already returned and the next scope only starts after we return + // the pointer. Therefore, there can be no references to the old value, + // even if it was initialized. Thus because we are !Sync we have exclusive + // access to self.value and may replace it. + let mut old_value = unsafe { self.value.get().replace(MaybeUninit::new(v)) }; match self.state.replace(State::Alive) { State::Uninitialized => D::register_dtor(self), - - State::Alive => { - // An init occurred during a recursive call, this could be a panic in the future. - - // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer - // has already returned and the next scope only starts after we return - // the pointer. Therefore, there can be no references to the old value. - unsafe { (*self.value.get()).assume_init_drop() } - } - + State::Alive => unsafe { old_value.assume_init_drop() }, State::Destroyed(_) => unreachable!(), } - // SAFETY: we are !Sync so we have exclusive access to self.value. - unsafe { (*self.value.get()).write(v) } + self.value.get().cast() } } From 22c5e1d686967d8ef69fec69475f8bbe25b71b2f Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Thu, 29 May 2025 02:47:23 +0200 Subject: [PATCH 16/34] Add test --- .../tls-dont-move-after-init.rs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/ui/threads-sendsync/tls-dont-move-after-init.rs diff --git a/tests/ui/threads-sendsync/tls-dont-move-after-init.rs b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs new file mode 100644 index 000000000000..2cd2a88a2c7d --- /dev/null +++ b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs @@ -0,0 +1,39 @@ +//@ run-pass +#![allow(stable_features)] +//@ needs-threads +#![feature(thread_local_try_with)] + +use std::cell::Cell; +use std::thread; + +#[derive(Default)] +struct Foo { + ptr: Cell<*const Foo>, +} + +impl Foo { + fn touch(&self) { + if self.ptr.get().is_null() { + self.ptr.set(self); + } else { + assert!(self.ptr.get() == self); + } + } +} + +impl Drop for Foo { + fn drop(&mut self) { + self.touch(); + } +} + +thread_local!(static FOO: Foo = Foo::default()); + +fn main() { + thread::spawn(|| { + FOO.with(|foo| foo.touch()); + FOO.with(|foo| foo.touch()); + }) + .join() + .unwrap(); +} From aff29df28e312e6ec247a62eaee5c50d431e7015 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Thu, 29 May 2025 02:48:57 +0200 Subject: [PATCH 17/34] Remove unneeded feature --- tests/ui/threads-sendsync/tls-dont-move-after-init.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ui/threads-sendsync/tls-dont-move-after-init.rs b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs index 2cd2a88a2c7d..f986202ab89e 100644 --- a/tests/ui/threads-sendsync/tls-dont-move-after-init.rs +++ b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs @@ -1,7 +1,6 @@ //@ run-pass #![allow(stable_features)] //@ needs-threads -#![feature(thread_local_try_with)] use std::cell::Cell; use std::thread; From f8887aa5afd5ec20b3074e798c29146da3d91f91 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 28 May 2025 15:18:48 +1000 Subject: [PATCH 18/34] Reorder fields in `hir::ItemKind` variants. Specifically `TyAlias`, `Enum`, `Struct`, `Union`. So the fields match the textual order in the source code. The interesting part of the change is in `compiler/rustc_hir/src/hir.rs`. The rest is extremely mechanical refactoring. --- compiler/rustc_ast_lowering/src/index.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 12 ++-- compiler/rustc_hir/src/hir.rs | 56 +++++++++---------- compiler/rustc_hir/src/intravisit.rs | 16 +++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 22 ++++---- compiler/rustc_hir_analysis/src/collect.rs | 22 ++++---- .../src/collect/resolve_bound_vars.rs | 10 ++-- .../rustc_hir_analysis/src/collect/type_of.rs | 8 +-- .../src/hir_ty_lowering/lint.rs | 6 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 6 +- compiler/rustc_hir_pretty/src/lib.rs | 30 +++++----- compiler/rustc_hir_typeck/src/demand.rs | 4 +- compiler/rustc_lint/src/builtin.rs | 36 ++++++------ .../src/default_could_be_derived.rs | 2 +- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_lint/src/types.rs | 10 ++-- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 8 +-- compiler/rustc_passes/src/dead.rs | 6 +- compiler/rustc_passes/src/stability.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 20 +++---- .../src/error_reporting/infer/mod.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 20 +++---- src/librustdoc/clean/mod.rs | 18 +++--- .../passes/calculate_doc_coverage.rs | 2 +- .../src/arbitrary_source_item_ordering.rs | 4 +- .../clippy_lints/src/empty_with_brackets.rs | 2 +- .../clippy/clippy_lints/src/enum_clike.rs | 2 +- .../clippy_lints/src/excessive_bools.rs | 2 +- .../clippy_lints/src/exhaustive_items.rs | 2 +- .../clippy_lints/src/functions/result.rs | 2 +- .../clippy_lints/src/item_name_repetitions.rs | 4 +- .../clippy_lints/src/large_const_arrays.rs | 2 +- .../clippy_lints/src/large_enum_variant.rs | 2 +- .../clippy_lints/src/manual_non_exhaustive.rs | 4 +- .../src/missing_fields_in_debug.rs | 2 +- .../clippy_lints/src/non_std_lazy_statics.rs | 2 +- .../clippy_lints/src/pub_underscore_fields.rs | 2 +- .../clippy_lints/src/trailing_empty_array.rs | 2 +- .../clippy/clippy_lints/src/types/mod.rs | 2 +- .../clippy_lints/src/upper_case_acronyms.rs | 2 +- .../clippy_utils/src/check_proc_macro.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 45 files changed, 184 insertions(+), 186 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 26c0e7e5f82a..956cb580d103 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -164,7 +164,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_item(&mut self, i: &'hir Item<'hir>) { debug_assert_eq!(i.owner_id, self.owner); self.with_parent(i.hir_id(), |this| { - if let ItemKind::Struct(_, struct_def, _) = &i.kind { + if let ItemKind::Struct(_, _, struct_def) = &i.kind { // If this is a tuple or unit-like struct, register the constructor. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7f7d45790ee2..6aa967f15bfa 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -180,7 +180,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); self.lower_define_opaque(hir_id, define_opaque); - hir::ItemKind::Static(ident, ty, *m, body_id) + hir::ItemKind::Static(*m, ident, ty, body_id) } ItemKind::Const(box ast::ConstItem { ident, @@ -200,7 +200,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ); self.lower_define_opaque(hir_id, &define_opaque); - hir::ItemKind::Const(ident, ty, generics, body_id) + hir::ItemKind::Const(ident, generics, ty, body_id) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, @@ -304,7 +304,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), }, ); - hir::ItemKind::TyAlias(ident, ty, generics) + hir::ItemKind::TyAlias(ident, generics, ty) } ItemKind::Enum(ident, generics, enum_definition) => { let ident = self.lower_ident(*ident); @@ -318,7 +318,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics) + hir::ItemKind::Enum(ident, generics, hir::EnumDef { variants }) } ItemKind::Struct(ident, generics, struct_def) => { let ident = self.lower_ident(*ident); @@ -328,7 +328,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), ); - hir::ItemKind::Struct(ident, struct_def, generics) + hir::ItemKind::Struct(ident, generics, struct_def) } ItemKind::Union(ident, generics, vdata) => { let ident = self.lower_ident(*ident); @@ -338,7 +338,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), ); - hir::ItemKind::Union(ident, vdata, generics) + hir::ItemKind::Union(ident, generics, vdata) } ItemKind::Impl(box Impl { safety, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f63ab3036891..8024151214a0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4106,11 +4106,11 @@ impl<'hir> Item<'hir> { expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk); - expect_static, (Ident, &'hir Ty<'hir>, Mutability, BodyId), - ItemKind::Static(ident, ty, mutbl, body), (*ident, ty, *mutbl, *body); + expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId), + ItemKind::Static(mutbl, ident, ty, body), (*mutbl, *ident, ty, *body); - expect_const, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Const(ident, ty, generics, body), (*ident, ty, generics, *body); + expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), + ItemKind::Const(ident, generics, ty, body), (*ident, generics, ty, *body); expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); @@ -4125,17 +4125,17 @@ impl<'hir> Item<'hir> { expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm; - expect_ty_alias, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>), - ItemKind::TyAlias(ident, ty, generics), (*ident, ty, generics); + expect_ty_alias, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>), + ItemKind::TyAlias(ident, generics, ty), (*ident, generics, ty); - expect_enum, (Ident, &EnumDef<'hir>, &'hir Generics<'hir>), - ItemKind::Enum(ident, def, generics), (*ident, def, generics); + expect_enum, (Ident, &'hir Generics<'hir>, &EnumDef<'hir>), + ItemKind::Enum(ident, generics, def), (*ident, generics, def); - expect_struct, (Ident, &VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Struct(ident, data, generics), (*ident, data, generics); + expect_struct, (Ident, &'hir Generics<'hir>, &VariantData<'hir>), + ItemKind::Struct(ident, generics, data), (*ident, generics, data); - expect_union, (Ident, &VariantData<'hir>, &'hir Generics<'hir>), - ItemKind::Union(ident, data, generics), (*ident, data, generics); + expect_union, (Ident, &'hir Generics<'hir>, &VariantData<'hir>), + ItemKind::Union(ident, generics, data), (*ident, generics, data); expect_trait, ( @@ -4278,9 +4278,9 @@ pub enum ItemKind<'hir> { Use(&'hir UsePath<'hir>, UseKind), /// A `static` item. - Static(Ident, &'hir Ty<'hir>, Mutability, BodyId), + Static(Mutability, Ident, &'hir Ty<'hir>, BodyId), /// A `const` item. - Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), + Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), /// A function declaration. Fn { ident: Ident, @@ -4309,13 +4309,13 @@ pub enum ItemKind<'hir> { fake_body: BodyId, }, /// A type alias, e.g., `type Foo = Bar`. - TyAlias(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>), + TyAlias(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>), /// An enum definition, e.g., `enum Foo { C, D }`. - Enum(Ident, EnumDef<'hir>, &'hir Generics<'hir>), + Enum(Ident, &'hir Generics<'hir>, EnumDef<'hir>), /// A struct definition, e.g., `struct Foo {x: A}`. - Struct(Ident, VariantData<'hir>, &'hir Generics<'hir>), + Struct(Ident, &'hir Generics<'hir>, VariantData<'hir>), /// A union definition, e.g., `union Foo {x: A, y: B}`. - Union(Ident, VariantData<'hir>, &'hir Generics<'hir>), + Union(Ident, &'hir Generics<'hir>, VariantData<'hir>), /// A trait definition. Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), /// A trait alias. @@ -4352,7 +4352,7 @@ impl ItemKind<'_> { match *self { ItemKind::ExternCrate(_, ident) | ItemKind::Use(_, UseKind::Single(ident)) - | ItemKind::Static(ident, ..) + | ItemKind::Static(_, ident, ..) | ItemKind::Const(ident, ..) | ItemKind::Fn { ident, .. } | ItemKind::Macro(ident, ..) @@ -4374,11 +4374,11 @@ impl ItemKind<'_> { pub fn generics(&self) -> Option<&Generics<'_>> { Some(match self { ItemKind::Fn { generics, .. } - | ItemKind::TyAlias(_, _, generics) - | ItemKind::Const(_, _, generics, _) - | ItemKind::Enum(_, _, generics) - | ItemKind::Struct(_, _, generics) - | ItemKind::Union(_, _, generics) + | ItemKind::TyAlias(_, generics, _) + | ItemKind::Const(_, generics, _, _) + | ItemKind::Enum(_, generics, _) + | ItemKind::Struct(_, generics, _) + | ItemKind::Union(_, generics, _) | ItemKind::Trait(_, _, _, generics, _, _) | ItemKind::TraitAlias(_, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, @@ -4802,9 +4802,9 @@ impl<'hir> Node<'hir> { pub fn ty(self) -> Option<&'hir Ty<'hir>> { match self { Node::Item(it) => match it.kind { - ItemKind::TyAlias(_, ty, _) - | ItemKind::Static(_, ty, _, _) - | ItemKind::Const(_, ty, _, _) => Some(ty), + ItemKind::TyAlias(_, _, ty) + | ItemKind::Static(_, _, ty, _) + | ItemKind::Const(_, _, ty, _) => Some(ty), ItemKind::Impl(impl_item) => Some(&impl_item.self_ty), _ => None, }, @@ -4824,7 +4824,7 @@ impl<'hir> Node<'hir> { pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> { match self { - Node::Item(Item { kind: ItemKind::TyAlias(_, ty, _), .. }) => Some(ty), + Node::Item(Item { kind: ItemKind::TyAlias(_, _, ty), .. }) => Some(ty), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a60de4b1fc31..1fd44e44b9ce 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -545,15 +545,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: UseKind::Glob | UseKind::ListStem => {} } } - ItemKind::Static(ident, ref typ, _, body) => { + ItemKind::Static(_, ident, ref typ, body) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } - ItemKind::Const(ident, ref typ, ref generics, body) => { + ItemKind::Const(ident, ref generics, ref typ, body) => { try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_generics(generics)); + try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Fn { ident, sig, generics, body: body_id, .. } => { @@ -583,12 +583,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: // typeck results set correctly. try_visit!(visitor.visit_nested_body(fake_body)); } - ItemKind::TyAlias(ident, ref ty, ref generics) => { + ItemKind::TyAlias(ident, ref generics, ref ty) => { try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_ty_unambig(ty)); try_visit!(visitor.visit_generics(generics)); + try_visit!(visitor.visit_ty_unambig(ty)); } - ItemKind::Enum(ident, ref enum_definition, ref generics) => { + ItemKind::Enum(ident, ref generics, ref enum_definition) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_enum_def(enum_definition)); @@ -609,8 +609,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ty_unambig(self_ty)); walk_list!(visitor, visit_impl_item_ref, *items); } - ItemKind::Struct(ident, ref struct_definition, ref generics) - | ItemKind::Union(ident, ref struct_definition, ref generics) => { + ItemKind::Struct(ident, ref generics, ref struct_definition) + | ItemKind::Union(ident, ref generics, ref struct_definition) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f85ff5a6f4be..b764b714fe17 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -297,32 +297,30 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() hir::ItemKind::Fn { ident, sig, .. } => { check_item_fn(tcx, def_id, ident, item.span, sig.decl) } - hir::ItemKind::Static(_, ty, ..) => { + hir::ItemKind::Static(_, _, ty, _) => { check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid) } - hir::ItemKind::Const(_, ty, ..) => check_const_item(tcx, def_id, ty.span, item.span), - hir::ItemKind::Struct(_, _, hir_generics) => { + hir::ItemKind::Const(_, _, ty, _) => check_const_item(tcx, def_id, ty.span, item.span), + hir::ItemKind::Struct(_, generics, _) => { let res = check_type_defn(tcx, item, false); - check_variances_for_type_defn(tcx, item, hir_generics); + check_variances_for_type_defn(tcx, item, generics); res } - hir::ItemKind::Union(_, _, hir_generics) => { + hir::ItemKind::Union(_, generics, _) => { let res = check_type_defn(tcx, item, true); - check_variances_for_type_defn(tcx, item, hir_generics); + check_variances_for_type_defn(tcx, item, generics); res } - hir::ItemKind::Enum(_, _, hir_generics) => { + hir::ItemKind::Enum(_, generics, _) => { let res = check_type_defn(tcx, item, true); - check_variances_for_type_defn(tcx, item, hir_generics); + check_variances_for_type_defn(tcx, item, generics); res } hir::ItemKind::Trait(..) => check_trait(tcx, item), hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), // `ForeignItem`s are handled separately. hir::ItemKind::ForeignMod { .. } => Ok(()), - hir::ItemKind::TyAlias(_, hir_ty, hir_generics) - if tcx.type_alias_is_lazy(item.owner_id) => - { + hir::ItemKind::TyAlias(_, generics, hir_ty) if tcx.type_alias_is_lazy(item.owner_id) => { let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { let ty = tcx.type_of(def_id).instantiate_identity(); let item_ty = @@ -335,7 +333,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() check_where_clauses(wfcx, item.span, def_id); Ok(()) }); - check_variances_for_type_defn(tcx, item, hir_generics); + check_variances_for_type_defn(tcx, item, generics); res } _ => Ok(()), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8a2edd843f20..a649e7d67af3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -248,13 +248,13 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( item: &'tcx hir::Item<'tcx>, ) { let (generics, suggest) = match &item.kind { - hir::ItemKind::Union(_, _, generics) - | hir::ItemKind::Enum(_, _, generics) + hir::ItemKind::Union(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::TraitAlias(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) - | hir::ItemKind::Struct(_, _, generics) => (generics, true), - hir::ItemKind::TyAlias(_, _, generics) => (generics, false), + | hir::ItemKind::Struct(_, generics, _) => (generics, true), + hir::ItemKind::TyAlias(_, generics, _) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. _ => return, }; @@ -470,9 +470,9 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { .tcx .hir_expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id); match &item.kind { - hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Union(_, _, generics) => { + hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Union(_, generics, _) => { let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics); let (lt_sp, sugg) = match generics.params { [] => (generics.span, format!("<{lt_name}>")), @@ -740,7 +740,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure_ok().predicates_of(def_id); } - hir::ItemKind::Struct(_, struct_def, _) | hir::ItemKind::Union(_, struct_def, _) => { + hir::ItemKind::Struct(_, _, struct_def) | hir::ItemKind::Union(_, _, struct_def) => { tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); tcx.ensure_ok().predicates_of(def_id); @@ -762,7 +762,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure_ok().predicates_of(def_id); } - hir::ItemKind::Static(_, ty, ..) | hir::ItemKind::Const(_, ty, ..) => { + hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => { tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); tcx.ensure_ok().predicates_of(def_id); @@ -1093,7 +1093,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { let repr = tcx.repr_options_of_def(def_id); let (kind, variants) = match &item.kind { - ItemKind::Enum(_, def, _) => { + ItemKind::Enum(_, _, def) => { let mut distance_from_explicit = 0; let variants = def .variants @@ -1121,7 +1121,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { (AdtKind::Enum, variants) } - ItemKind::Struct(ident, def, _) | ItemKind::Union(ident, def, _) => { + ItemKind::Struct(ident, _, def) | ItemKind::Union(ident, _, def) => { let adt_kind = match item.kind { ItemKind::Struct(..) => AdtKind::Struct, _ => AdtKind::Union, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 709446d09cd2..d45f0475e991 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -634,11 +634,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemKind::TyAlias(_, _, generics) - | hir::ItemKind::Const(_, _, generics, _) - | hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Union(_, _, generics) + hir::ItemKind::TyAlias(_, generics, _) + | hir::ItemKind::Const(_, generics, _, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::TraitAlias(_, generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c20b14df7704..141d96b57e57 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -206,7 +206,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ }, Node::Item(item) => match item.kind { - ItemKind::Static(ident, ty, .., body_id) => { + ItemKind::Static(_, ident, ty, body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -220,7 +220,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ icx.lower_ty(ty) } } - ItemKind::Const(ident, ty, _, body_id) => { + ItemKind::Const(ident, _, ty, body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -234,7 +234,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ icx.lower_ty(ty) } } - ItemKind::TyAlias(_, self_ty, _) => icx.lower_ty(self_ty), + ItemKind::TyAlias(_, _, self_ty) => icx.lower_ty(self_ty), ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() { spans if spans.len() > 0 => { let guar = tcx @@ -532,5 +532,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> } } } - HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().1).is_break() + HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().2).is_break() } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 1f4692b19f1a..9abae33ffdbb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -141,7 +141,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let generics = match tcx.hir_node_by_def_id(parent_item) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, variant, generics), + kind: hir::ItemKind::Struct(_, generics, variant), .. }) => { if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) { @@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } generics } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, def, generics), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => { if !def .variants .iter() @@ -269,7 +269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::Node::Field(field) => { // Enums can't have unsized fields, fields can only have an unsized tail field. if let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, variant, _), .. + kind: hir::ItemKind::Struct(_, _, variant), .. }) = tcx.parent_hir_node(field.hir_id) && variant .fields() diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 64c1a78bd1c8..4633f3951a78 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -145,9 +145,9 @@ fn diagnostic_hir_wf_check<'tcx>( ref item => bug!("Unexpected TraitItem {:?}", item), }, hir::Node::Item(item) => match item.kind { - hir::ItemKind::TyAlias(_, ty, _) - | hir::ItemKind::Static(_, ty, _, _) - | hir::ItemKind::Const(_, ty, _, _) => vec![ty], + hir::ItemKind::TyAlias(_, _, ty) + | hir::ItemKind::Static(_, _, ty, _) + | hir::ItemKind::Const(_, _, ty, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 04f9c831b0ac..5222c0252ba6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -593,7 +593,7 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } - hir::ItemKind::Static(ident, ty, m, expr) => { + hir::ItemKind::Static(m, ident, ty, expr) => { let (cb, ib) = self.head("static"); if m.is_mut() { self.word_space("mut"); @@ -609,7 +609,7 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } - hir::ItemKind::Const(ident, ty, generics, expr) => { + hir::ItemKind::Const(ident, generics, ty, expr) => { let (cb, ib) = self.head("const"); self.print_ident(ident); self.print_generic_params(generics.params); @@ -660,7 +660,7 @@ impl<'a> State<'a> { self.end(cb); self.end(ib); } - hir::ItemKind::TyAlias(ident, ty, generics) => { + hir::ItemKind::TyAlias(ident, generics, ty) => { let (cb, ib) = self.head("type"); self.print_ident(ident); self.print_generic_params(generics.params); @@ -673,16 +673,16 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } - hir::ItemKind::Enum(ident, ref enum_definition, params) => { - self.print_enum_def(enum_definition, params, ident.name, item.span); + hir::ItemKind::Enum(ident, generics, ref enum_def) => { + self.print_enum_def(ident.name, generics, enum_def, item.span); } - hir::ItemKind::Struct(ident, ref struct_def, generics) => { + hir::ItemKind::Struct(ident, generics, ref struct_def) => { let (cb, ib) = self.head("struct"); - self.print_struct(struct_def, generics, ident.name, item.span, true, cb, ib); + self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib); } - hir::ItemKind::Union(ident, ref struct_def, generics) => { + hir::ItemKind::Union(ident, generics, ref struct_def) => { let (cb, ib) = self.head("union"); - self.print_struct(struct_def, generics, ident.name, item.span, true, cb, ib); + self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib); } hir::ItemKind::Impl(&hir::Impl { constness, @@ -791,9 +791,9 @@ impl<'a> State<'a> { fn print_enum_def( &mut self, - enum_definition: &hir::EnumDef<'_>, - generics: &hir::Generics<'_>, name: Symbol, + generics: &hir::Generics<'_>, + enum_def: &hir::EnumDef<'_>, span: rustc_span::Span, ) { let (cb, ib) = self.head("enum"); @@ -801,7 +801,7 @@ impl<'a> State<'a> { self.print_generic_params(generics.params); self.print_where_clause(generics); self.space(); - self.print_variants(enum_definition.variants, span, cb, ib); + self.print_variants(enum_def.variants, span, cb, ib); } fn print_variants( @@ -834,9 +834,9 @@ impl<'a> State<'a> { fn print_struct( &mut self, - struct_def: &hir::VariantData<'_>, - generics: &hir::Generics<'_>, name: Symbol, + generics: &hir::Generics<'_>, + struct_def: &hir::VariantData<'_>, span: rustc_span::Span, print_finalizer: bool, cb: BoxMarker, @@ -886,7 +886,7 @@ impl<'a> State<'a> { pub fn print_variant(&mut self, v: &hir::Variant<'_>) { let (cb, ib) = self.head(""); let generics = hir::Generics::empty(); - self.print_struct(&v.data, generics, v.ident.name, v.span, false, cb, ib); + self.print_struct(v.ident.name, generics, &v.data, v.span, false, cb, ib); if let Some(ref d) = v.disr_expr { self.space(); self.word_space("="); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 8182851a015b..152c88ad92a5 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -722,8 +722,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) => { if let Some(hir::Node::Item(hir::Item { kind: - hir::ItemKind::Static(ident, ty, ..) - | hir::ItemKind::Const(ident, ty, ..), + hir::ItemKind::Static(_, ident, ty, _) + | hir::ItemKind::Const(ident, _, ty, _), .. })) = self.tcx.hir_get_if_local(*def_id) { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 95e31e4af1e3..47b80135bae9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -545,22 +545,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } let (def, ty) = match item.kind { - hir::ItemKind::Struct(_, _, ast_generics) => { - if !ast_generics.params.is_empty() { + hir::ItemKind::Struct(_, generics, _) => { + if !generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); (def, Ty::new_adt(cx.tcx, def, ty::List::empty())) } - hir::ItemKind::Union(_, _, ast_generics) => { - if !ast_generics.params.is_empty() { + hir::ItemKind::Union(_, generics, _) => { + if !generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); (def, Ty::new_adt(cx.tcx, def, ty::List::empty())) } - hir::ItemKind::Enum(_, _, ast_generics) => { - if !ast_generics.params.is_empty() { + hir::ItemKind::Enum(_, generics, _) => { + if !generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); @@ -1422,7 +1422,7 @@ impl TypeAliasBounds { impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - let hir::ItemKind::TyAlias(_, hir_ty, generics) = item.kind else { return }; + let hir::ItemKind::TyAlias(_, generics, hir_ty) = item.kind else { return }; // There must not be a where clause. if generics.predicates.is_empty() { @@ -2125,9 +2125,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { use rustc_middle::middle::resolve_bound_vars::ResolvedArg; let def_id = item.owner_id.def_id; - if let hir::ItemKind::Struct(_, _, hir_generics) - | hir::ItemKind::Enum(_, _, hir_generics) - | hir::ItemKind::Union(_, _, hir_generics) = item.kind + if let hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Union(_, generics, _) = item.kind { let inferred_outlives = cx.tcx.inferred_outlives_of(def_id); if inferred_outlives.is_empty() { @@ -2135,7 +2135,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } let ty_generics = cx.tcx.generics_of(def_id); - let num_where_predicates = hir_generics + let num_where_predicates = generics .predicates .iter() .filter(|predicate| predicate.kind.in_where_clause()) @@ -2145,7 +2145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let mut lint_spans = Vec::new(); let mut where_lint_spans = Vec::new(); let mut dropped_where_predicate_count = 0; - for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { + for (i, where_predicate) in generics.predicates.iter().enumerate() { let (relevant_lifetimes, bounds, predicate_span, in_where_clause) = match where_predicate.kind { hir::WherePredicateKind::RegionPredicate(predicate) => { @@ -2228,7 +2228,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } else if i + 1 < num_where_predicates { // If all the bounds on a predicate were inferable and there are // further predicates, we want to eat the trailing comma. - let next_predicate_span = hir_generics.predicates[i + 1].span; + let next_predicate_span = generics.predicates[i + 1].span; if next_predicate_span.from_expansion() { where_lint_spans.push(predicate_span); } else { @@ -2237,7 +2237,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } } else { // Eat the optional trailing comma after the last predicate. - let where_span = hir_generics.where_clause_span; + let where_span = generics.where_clause_span; if where_span.from_expansion() { where_lint_spans.push(predicate_span); } else { @@ -2255,18 +2255,18 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { // If all predicates in where clause are inferable, drop the entire clause // (including the `where`) - if hir_generics.has_where_clause_predicates + if generics.has_where_clause_predicates && dropped_where_predicate_count == num_where_predicates { - let where_span = hir_generics.where_clause_span; + let where_span = generics.where_clause_span; // Extend the where clause back to the closing `>` of the // generics, except for tuple struct, which have the `where` // after the fields of the struct. let full_where_span = - if let hir::ItemKind::Struct(_, hir::VariantData::Tuple(..), _) = item.kind { + if let hir::ItemKind::Struct(_, _, hir::VariantData::Tuple(..)) = item.kind { where_span } else { - hir_generics.span.shrink_to_hi().to(where_span) + generics.span.shrink_to_hi().to(where_span) }; // Due to macro expansions, the `full_where_span` might not actually contain all diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 78d129642dc7..7734f441df2e 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -95,8 +95,8 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { kind: hir::ItemKind::Struct( _, - hir::VariantData::Struct { fields, recovered: _ }, _generics, + hir::VariantData::Struct { fields, recovered: _ }, ), .. })) => fields.iter().map(|f| (f.ident.name, f)).collect::>(), diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 9ed11d9cc82f..b877f909fc02 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { && parent_opt_item_name != Some(kw::Underscore) && let Some(parent) = parent.as_local() && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) - && let ItemKind::Const(ident, ty, _, _) = item.kind + && let ItemKind::Const(ident, _, ty, _) = item.kind && let TyKind::Tup(&[]) = ty.kind { Some(ident.span) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 048d377b78fb..31c180744668 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -513,7 +513,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); match it.kind { - hir::ItemKind::Static(ident, ..) + hir::ItemKind::Static(_, ident, ..) if !ast::attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index af134622d38c..77dc63351136 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1710,7 +1710,7 @@ impl ImproperCTypesDefinitions { && cx.tcx.sess.target.os == "aix" && !adt_def.all_fields().next().is_none() { - let struct_variant_data = item.expect_struct().1; + let struct_variant_data = item.expect_struct().2; for field_def in struct_variant_data.fields().iter().skip(1) { // Struct fields (after the first field) are checked for the // power alignment rule, as fields after the first are likely @@ -1735,9 +1735,9 @@ impl ImproperCTypesDefinitions { impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { match item.kind { - hir::ItemKind::Static(_, ty, ..) - | hir::ItemKind::Const(_, ty, ..) - | hir::ItemKind::TyAlias(_, ty, ..) => { + hir::ItemKind::Static(_, _, ty, _) + | hir::ItemKind::Const(_, _, ty, _) + | hir::ItemKind::TyAlias(_, _, ty) => { self.check_ty_maybe_containing_foreign_fnptr( cx, ty, @@ -1804,7 +1804,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - if let hir::ItemKind::Enum(_, ref enum_definition, _) = it.kind { + if let hir::ItemKind::Enum(_, _, ref enum_definition) = it.kind { let t = cx.tcx.type_of(it.owner_id).instantiate_identity(); let ty = cx.tcx.erase_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 9c8f1c9eccf3..3de97c8c0d99 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -920,7 +920,7 @@ impl<'tcx> TyCtxt<'tcx> { }) => until_within(*outer_span, generics.where_clause_span), // Constants and Statics. Node::Item(Item { - kind: ItemKind::Const(_, ty, ..) | ItemKind::Static(_, ty, ..), + kind: ItemKind::Const(_, _, ty, _) | ItemKind::Static(_, _, ty, _), span: outer_span, .. }) diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 127b191e3353..3d5f6f4cf451 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -558,7 +558,7 @@ fn construct_const<'a, 'tcx>( // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir_node(hir_id) { Node::Item(hir::Item { - kind: hir::ItemKind::Static(_, ty, _, _) | hir::ItemKind::Const(_, ty, _, _), + kind: hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _), span, .. }) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index df8b5a6b1818..0777d442b594 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -802,7 +802,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct => { if let Some(ItemLike::Item(hir::Item { - kind: hir::ItemKind::Struct(_, hir::VariantData::Struct { fields, .. }, _), + kind: hir::ItemKind::Struct(_, _, hir::VariantData::Struct { fields, .. }), .. })) = item && !fields.is_empty() @@ -1130,12 +1130,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; match item.kind { - ItemKind::Enum(_, _, generics) | ItemKind::Struct(_, _, generics) + ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) if generics.params.len() != 0 => {} ItemKind::Trait(_, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {} - ItemKind::TyAlias(_, _, generics) if generics.params.len() != 0 => {} + ItemKind::TyAlias(_, generics, _) if generics.params.len() != 0 => {} _ => { self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); } @@ -2792,7 +2792,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn is_c_like_enum(item: &Item<'_>) -> bool { - if let ItemKind::Enum(_, ref def, _) = item.kind { + if let ItemKind::Enum(_, _, ref def) = item.kind { for variant in def.variants { match variant.data { hir::VariantData::Unit(..) => { /* continue */ } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6e5357d80074..d8f7fde3a584 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -749,7 +749,7 @@ fn check_item<'tcx>( match tcx.def_kind(id.owner_id) { DefKind::Enum => { let item = tcx.hir_item(id); - if let hir::ItemKind::Enum(_, ref enum_def, _) = item.kind { + if let hir::ItemKind::Enum(_, _, ref enum_def) = item.kind { if let Some(comes_from_allow) = allow_dead_code { worklist.extend( enum_def.variants.iter().map(|variant| (variant.def_id, comes_from_allow)), @@ -804,7 +804,7 @@ fn check_item<'tcx>( } DefKind::Struct => { let item = tcx.hir_item(id); - if let hir::ItemKind::Struct(_, ref variant_data, _) = item.kind + if let hir::ItemKind::Struct(_, _, ref variant_data) = item.kind && let Some(ctor_def_id) = variant_data.ctor_def_id() { struct_constructors.insert(ctor_def_id, item.owner_id.def_id); @@ -1061,7 +1061,7 @@ impl<'tcx> DeadVisitor<'tcx> { let tuple_fields = if let Some(parent_id) = parent_item && let node = tcx.hir_node_by_def_id(parent_id) && let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(fields, _, _), _), + kind: hir::ItemKind::Struct(_, _, hir::VariantData::Tuple(fields, _, _)), .. }) = node { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9884386d68f8..45e26c8999a9 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -430,7 +430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { kind = AnnotationKind::DeprecationProhibited; const_stab_inherit = InheritConstStability::Yes; } - hir::ItemKind::Struct(_, ref sd, _) => { + hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { self.annotate( ctor_def_id, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e2dfaec61b3c..963f4c77d809 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -599,8 +599,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. let item = self.tcx.hir_expect_item(def_id); - if let hir::ItemKind::Struct(_, ref struct_def, _) - | hir::ItemKind::Union(_, ref struct_def, _) = item.kind + if let hir::ItemKind::Struct(_, _, ref struct_def) + | hir::ItemKind::Union(_, _, ref struct_def) = item.kind { for field in struct_def.fields() { let field_vis = self.tcx.local_visibility(field.def_id); @@ -725,7 +725,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::Enum(_, ref def, _) => { + hir::ItemKind::Enum(_, _, ref def) => { if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } @@ -763,8 +763,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::Struct(_, ref struct_def, _) - | hir::ItemKind::Union(_, ref struct_def, _) => { + hir::ItemKind::Struct(_, _, ref struct_def) + | hir::ItemKind::Union(_, _, ref struct_def) => { if let Some(item_ev) = item_ev { self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for field in struct_def.fields() { @@ -868,7 +868,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> { self.effective_visibility_diagnostic(item.owner_id.def_id); match item.kind { - hir::ItemKind::Enum(_, ref def, _) => { + hir::ItemKind::Enum(_, _, ref def) => { for variant in def.variants.iter() { self.effective_visibility_diagnostic(variant.def_id); if let Some(ctor_def_id) = variant.data.ctor_def_id() { @@ -879,7 +879,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> { } } } - hir::ItemKind::Struct(_, ref def, _) | hir::ItemKind::Union(_, ref def, _) => { + hir::ItemKind::Struct(_, _, ref def) | hir::ItemKind::Union(_, _, ref def) => { if let Some(ctor_def_id) = def.ctor_def_id() { self.effective_visibility_diagnostic(ctor_def_id); } @@ -1651,7 +1651,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { } DefKind::Enum => { let item = tcx.hir_item(id); - if let hir::ItemKind::Enum(_, ref def, _) = item.kind { + if let hir::ItemKind::Enum(_, _, ref def) = item.kind { self.check_unnameable(item.owner_id.def_id, effective_vis); self.check(item.owner_id.def_id, item_visibility, effective_vis) @@ -1689,8 +1689,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { // Subitems of structs and unions have their own publicity. DefKind::Struct | DefKind::Union => { let item = tcx.hir_item(id); - if let hir::ItemKind::Struct(_, ref struct_def, _) - | hir::ItemKind::Union(_, ref struct_def, _) = item.kind + if let hir::ItemKind::Struct(_, _, ref struct_def) + | hir::ItemKind::Union(_, _, ref struct_def) = item.kind { self.check_unnameable(item.owner_id.def_id, effective_vis); self.check(item.owner_id.def_id, item_visibility, effective_vis) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index aeadb32ac2b4..8e2137da6552 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2026,7 +2026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } LetVisitor { span }.visit_body(body).break_value() } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, _, _), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _), .. }) => { Some(&ty.peel_refs().kind) } _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6863857f9ecb..c4f1f7d712a7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -351,14 +351,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: - hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Union(_, _, generics) + hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } - | hir::ItemKind::TyAlias(_, _, generics) - | hir::ItemKind::Const(_, _, generics, _) + | hir::ItemKind::TyAlias(_, generics, _) + | hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) @@ -411,14 +411,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: - hir::ItemKind::Struct(_, _, generics) - | hir::ItemKind::Enum(_, _, generics) - | hir::ItemKind::Union(_, _, generics) + hir::ItemKind::Struct(_, generics, _) + | hir::ItemKind::Enum(_, generics, _) + | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } - | hir::ItemKind::TyAlias(_, _, generics) - | hir::ItemKind::Const(_, _, generics, _) + | hir::ItemKind::TyAlias(_, generics, _) + | hir::ItemKind::Const(_, generics, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) if !param_ty => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7a95384e3f9..28401f08d337 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1750,7 +1750,7 @@ fn maybe_expand_private_type_alias<'tcx>( } else { return None; }; - let hir::ItemKind::TyAlias(_, ty, generics) = alias else { return None }; + let hir::ItemKind::TyAlias(_, generics, ty) = alias else { return None }; let final_seg = &path.segments.last().expect("segments were empty"); let mut args = DefIdMap::default(); @@ -2804,21 +2804,21 @@ fn clean_maybe_renamed_item<'tcx>( let mut name = get_name(cx, item, renamed).unwrap(); let kind = match item.kind { - ItemKind::Static(_, ty, mutability, body_id) => StaticItem(Static { + ItemKind::Static(mutability, _, ty, body_id) => StaticItem(Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: Some(body_id), }), - ItemKind::Const(_, ty, generics, body_id) => ConstantItem(Box::new(Constant { + ItemKind::Const(_, generics, ty, body_id) => ConstantItem(Box::new(Constant { generics: clean_generics(generics, cx), type_: clean_ty(ty, cx), kind: ConstantKind::Local { body: body_id, def_id }, })), - ItemKind::TyAlias(_, hir_ty, generics) => { + ItemKind::TyAlias(_, generics, ty) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; - let rustdoc_ty = clean_ty(hir_ty, cx); + let rustdoc_ty = clean_ty(ty, cx); let type_ = - clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, hir_ty)), cx, None, None); + clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, ty)), cx, None, None); let generics = clean_generics(generics, cx); if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { *count -= 1; @@ -2847,7 +2847,7 @@ fn clean_maybe_renamed_item<'tcx>( )); return ret; } - ItemKind::Enum(_, def, generics) => EnumItem(Enum { + ItemKind::Enum(_, generics, def) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), generics: clean_generics(generics, cx), }), @@ -2855,11 +2855,11 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), - ItemKind::Union(_, variant_data, generics) => UnionItem(Union { + ItemKind::Union(_, generics, variant_data) => UnionItem(Union { generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - ItemKind::Struct(_, variant_data, generics) => StructItem(Struct { + ItemKind::Struct(_, generics, variant_data) => StructItem(Struct { ctor_kind: variant_data.ctor_kind(), generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index c9f0baaaa4c1..66d8b667a4ca 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -241,7 +241,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> { data: hir::VariantData::Tuple(_, _, _), .. }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(_, _, _), _), + kind: hir::ItemKind::Struct(_, _, hir::VariantData::Tuple(_, _, _)), .. }) ) diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 5c1c85d39184..59a0c7c88684 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -272,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { return; } match &item.kind { - ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => { + ItemKind::Enum(_, _generics, enum_def) if self.enable_ordering_for_enum => { let mut cur_v: Option<&Variant<'_>> = None; for variant in enum_def.variants { if variant.span.in_external_macro(cx.sess().source_map()) { @@ -288,7 +288,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { cur_v = Some(variant); } }, - ItemKind::Struct(_, VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => { + ItemKind::Struct(_, _generics, VariantData::Struct { fields, .. }) if self.enable_ordering_for_struct => { let mut cur_f: Option<&FieldDef<'_>> = None; for field in *fields { if field.span.in_external_macro(cx.sess().source_map()) { 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 8c12364883c7..4414aebbf9a3 100644 --- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs @@ -92,7 +92,7 @@ impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VA impl LateLintPass<'_> for EmptyWithBrackets { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if let ItemKind::Struct(ident, var_data, _) = &item.kind + if let ItemKind::Struct(ident, _, var_data) = &item.kind && !item.span.from_expansion() && has_brackets(var_data) && let span_after_ident = item.span.with_lo(ident.span.hi()) diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index ec81294624ef..098571a53512 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { if cx.tcx.data_layout.pointer_size.bits() != 64 { return; } - if let ItemKind::Enum(_, def, _) = &item.kind { + if let ItemKind::Enum(_, _, def) = &item.kind { for var in def.variants { if let Some(anon_const) = &var.disr_expr { let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body); diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 38d115b878c7..686dc5c3c4fc 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -127,7 +127,7 @@ fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) { impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Struct(_, variant_data, _) = &item.kind + if let ItemKind::Struct(_, _, variant_data) = &item.kind && variant_data.fields().len() as u64 > self.max_struct_bools && has_n_bools( variant_data.fields().iter().map(|field| field.ty), diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 5a74e97c97c5..1fb0e4d24d06 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems { "exported enums should not be exhaustive", [].as_slice(), ), - ItemKind::Struct(_, v, ..) => ( + ItemKind::Struct(_, _, v) => ( EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive", v.fields(), diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 00ce4cfcc526..bb98ae826111 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -103,7 +103,7 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty .did() .as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) - && let hir::ItemKind::Enum(_, ref def, _) = item.kind + && let hir::ItemKind::Enum(_, _, ref def) = item.kind { let variants_size = AdtVariantInfo::new(cx, *adt, subst); if let Some((first_variant, variants)) = variants_size.split_first() diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 3d4dcd020702..9c91cf680851 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -535,10 +535,10 @@ impl LateLintPass<'_> for ItemNameRepetitions { if span_is_local(item.span) { match item.kind { - ItemKind::Enum(_, def, _) => { + ItemKind::Enum(_, _, def) => { self.check_variants(cx, item, &def); }, - ItemKind::Struct(_, VariantData::Struct { fields, .. }, _) => { + ItemKind::Struct(_, _, VariantData::Struct { fields, .. }) => { self.check_fields(cx, item, fields); }, _ => (), diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 394005e99129..cee8ca1261e5 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -48,7 +48,7 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Const(ident, _, generics, _) = &item.kind + if let ItemKind::Const(ident, generics, _, _) = &item.kind // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index d08efa0ec9cc..e85d779b4880 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -73,7 +73,7 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if let ItemKind::Enum(ident, ref def, _) = item.kind + if let ItemKind::Enum(ident, _, ref def) = item.kind && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Adt(adt, subst) = ty.kind() && adt.variants().len() > 1 diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 067b92cd46ee..3562b1ff5cce 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { } match item.kind { - ItemKind::Enum(_, def, _) if def.variants.len() > 1 => { + ItemKind::Enum(_, _, def) if def.variants.len() > 1 => { let iter = def.variants.iter().filter_map(|v| { (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); } }, - ItemKind::Struct(_, variant_data, _) => { + ItemKind::Struct(_, _, variant_data) => { let fields = variant_data.fields(); let private_fields = fields .iter() diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index be7dd74fd62b..d4d33029dbdb 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { && let typeck_results = cx.tcx.typeck_body(*body_id) && should_lint(cx, typeck_results, block) // we intentionally only lint structs, see lint description - && let ItemKind::Struct(_, data, _) = &self_item.kind + && let ItemKind::Struct(_, _, data) = &self_item.kind { check_struct(cx, typeck_results, block, self_ty, item, data); } diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs index f66b9519317b..abee3c44c5a3 100644 --- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs +++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs @@ -187,7 +187,7 @@ struct LazyInfo { impl LazyInfo { fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option { // Check if item is a `once_cell:sync::Lazy` static. - if let ItemKind::Static(_, ty, _, body_id) = item.kind + if let ItemKind::Static(_, _, ty, body_id) = item.kind && let Some(path_def_id) = path_def_id(cx, ty) && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && paths::ONCE_CELL_SYNC_LAZY.matches(cx, path_def_id) diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs index e4a9bf7a8481..66c59cb70d36 100644 --- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs +++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs @@ -58,7 +58,7 @@ impl PubUnderscoreFields { impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { // This lint only pertains to structs. - let ItemKind::Struct(_, variant_data, _) = &item.kind else { + let ItemKind::Struct(_, _, variant_data) = &item.kind else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 20bf3a0bff1c..75a82770af04 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { } fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { - if let ItemKind::Struct(_, data, _) = &item.kind + if let ItemKind::Struct(_, _, data) = &item.kind && let Some(last_field) = data.fields().last() && let field_ty = cx.tcx.normalize_erasing_regions( cx.typing_env(), diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index c1c7cc516565..515be5adeed0 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -447,7 +447,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { - ItemKind::Static(_, ty, _, _) | ItemKind::Const(_, ty, _, _) => self.check_ty( + ItemKind::Static(_, _, ty, _) | ItemKind::Const(_, _, ty, _) => self.check_ty( cx, ty, CheckTyContext { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 8922478e7183..02281b9e9223 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -134,7 +134,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => { check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, - ItemKind::Enum(ident, ref enumdef, _) => { + ItemKind::Enum(ident, _, ref enumdef) => { check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive); // check enum variants separately because again we only want to lint on private enums and // the fn check_variant does not know about the vis of the enum of its variants diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 004c840c3310..407e92d88fb0 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -249,7 +249,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), - ItemKind::Struct(_, VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")), + ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), ItemKind::Trait(_, Safety::Unsafe, ..) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8716ee48c88f..2020f3d6b5bd 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2362,7 +2362,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(& for id in tcx.hir_module_free_items(module) { if matches!(tcx.def_kind(id.owner_id), DefKind::Const) && let item = tcx.hir_item(id) - && let ItemKind::Const(ident, ty, _generics, _body) = item.kind + && let ItemKind::Const(ident, _generics, ty, _body) = item.kind && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind // We could also check for the type name `test::TestDescAndFn` && let Res::Def(DefKind::Struct, _) = path.res From aa3009dff69a52d0cba00f9b5011a879a4b7eb18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 May 2025 00:51:42 +1000 Subject: [PATCH 19/34] Reorder hir fn stuff. In `Fn`, put `ident` next to `generics` as is common in many other types. In `print_fn`, make the argument order match the printing order. --- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6aa967f15bfa..d3aacaa15a8c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -467,8 +467,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, id, false); hir::ItemKind::Fn { - ident: delegation_results.ident, sig: delegation_results.sig, + ident: delegation_results.ident, generics: delegation_results.generics, body: delegation_results.body_id, has_body: true, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8024151214a0..b4fcc16c09c8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4283,8 +4283,8 @@ pub enum ItemKind<'hir> { Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), /// A function declaration. Fn { - ident: Ident, sig: FnSig<'hir>, + ident: Ident, generics: &'hir Generics<'hir>, body: BodyId, /// Whether this function actually has a body. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5222c0252ba6..b23b3125c59a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -477,10 +477,10 @@ impl<'a> State<'a> { hir::ForeignItemKind::Fn(sig, arg_idents, generics) => { let (cb, ib) = self.head(""); self.print_fn( - sig.decl, sig.header, Some(item.ident.name), generics, + sig.decl, arg_idents, None, ); @@ -626,7 +626,7 @@ impl<'a> State<'a> { } hir::ItemKind::Fn { ident, sig, generics, body, .. } => { let (cb, ib) = self.head(""); - self.print_fn(sig.decl, sig.header, Some(ident.name), generics, &[], Some(body)); + self.print_fn(sig.header, Some(ident.name), generics, sig.decl, &[], Some(body)); self.word(" "); self.end(ib); self.end(cb); @@ -902,7 +902,7 @@ impl<'a> State<'a> { arg_idents: &[Option], body_id: Option, ) { - self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_idents, body_id); + self.print_fn(m.header, Some(ident.name), generics, m.decl, arg_idents, body_id); } fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { @@ -2141,10 +2141,10 @@ impl<'a> State<'a> { fn print_fn( &mut self, - decl: &hir::FnDecl<'_>, header: hir::FnHeader, name: Option, generics: &hir::Generics<'_>, + decl: &hir::FnDecl<'_>, arg_idents: &[Option], body_id: Option, ) { @@ -2483,7 +2483,6 @@ impl<'a> State<'a> { self.print_formal_generic_params(generic_params); let generics = hir::Generics::empty(); self.print_fn( - decl, hir::FnHeader { safety: safety.into(), abi, @@ -2492,6 +2491,7 @@ impl<'a> State<'a> { }, name, generics, + decl, arg_idents, None, ); From b374adc9dbeec2cc969723dbfcb5c8ee990953bd Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Fri, 30 May 2025 12:13:55 +0200 Subject: [PATCH 20/34] Address review comments. --- library/std/src/sys/thread_local/native/lazy.rs | 7 +++++++ tests/ui/threads-sendsync/tls-dont-move-after-init.rs | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index a2bf8d8b968a..b556dd9aa25e 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -84,8 +84,15 @@ where // access to self.value and may replace it. let mut old_value = unsafe { self.value.get().replace(MaybeUninit::new(v)) }; match self.state.replace(State::Alive) { + // If the variable is not being recursively initialized, register + // the destructor. This might be a noop if the value does not need + // destruction. State::Uninitialized => D::register_dtor(self), + + // Recursive initialization, we only need to drop the old value + // as we've already registered the destructor. State::Alive => unsafe { old_value.assume_init_drop() }, + State::Destroyed(_) => unreachable!(), } diff --git a/tests/ui/threads-sendsync/tls-dont-move-after-init.rs b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs index f986202ab89e..54fcc32e9bd7 100644 --- a/tests/ui/threads-sendsync/tls-dont-move-after-init.rs +++ b/tests/ui/threads-sendsync/tls-dont-move-after-init.rs @@ -1,5 +1,4 @@ //@ run-pass -#![allow(stable_features)] //@ needs-threads use std::cell::Cell; From ca1c67ad762afd68788841071d2ee63c088994f0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 May 2025 23:30:47 +0000 Subject: [PATCH 21/34] Update `compiler-builtins` to 0.1.160 Includes the following changes: * Enable `__powitf2` on MSVC [1] * Update `CmpResult` to use a pointer-sized return type [2] * Better code reuse between `libm` and `compiler-builtins` [3], [4] * Stop building C versions of `__netf2` [5] since we have our own implementation [1]: https://github.com/rust-lang/compiler-builtins/pull/918 [2]: https://github.com/rust-lang/compiler-builtins/pull/920 [3]: https://github.com/rust-lang/compiler-builtins/pull/879 [4]: https://github.com/rust-lang/compiler-builtins/pull/925 [5]: https://github.com/rust-lang/compiler-builtins/pull/828 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 02018057ed53..0c75977ee798 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.159" +version = "0.1.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448068da8f2326b2a0472353cb401dd8795a89c007ef30fff90f50706e862e72" +checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 9d0d957226d2..365c9dc00dfc 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 4ff4895ecde7..31371f06b386 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.159" } +compiler_builtins = { version = "=0.1.160" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 4668124cc709372c76a0a9a0b2108a3cadd98b78 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 29 Mar 2025 02:34:15 -0700 Subject: [PATCH 22/34] `slice.get(i)` should use a slice projection in MIR, like `slice[i]` does --- .../rustc_hir_analysis/src/check/intrinsic.rs | 1 + .../src/lower_intrinsics.rs | 46 ++++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/bounds.rs | 39 +++++++++ library/core/src/intrinsics/mod.rs | 45 +++++++--- library/core/src/slice/index.rs | 56 ++++++++++-- tests/mir-opt/lower_intrinsics.rs | 21 +++++ ...slice_get.LowerIntrinsics.panic-abort.diff | 85 +++++++++++++++++++ ...lice_get.LowerIntrinsics.panic-unwind.diff | 85 +++++++++++++++++++ ...mut_usize.PreCodegen.after.panic-abort.mir | 22 +---- ...ut_usize.PreCodegen.after.panic-unwind.mir | 22 +---- ...mut_range.PreCodegen.after.panic-abort.mir | 12 ++- ...ut_range.PreCodegen.after.panic-unwind.mir | 12 ++- ...ked_range.PreCodegen.after.panic-abort.mir | 12 ++- ...ed_range.PreCodegen.after.panic-unwind.mir | 12 ++- 15 files changed, 385 insertions(+), 86 deletions(-) create mode 100644 library/core/src/intrinsics/bounds.rs create mode 100644 tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-abort.diff create mode 100644 tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-unwind.diff diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 54bb3ac41130..09610a2f3ec6 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -265,6 +265,7 @@ pub(crate) fn check_intrinsic_type( vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.isize], Ty::new_imm_ptr(tcx, param(0)), ), + sym::slice_get_unchecked => (3, 0, vec![param(1), tcx.types.usize], param(0)), sym::ptr_mask => ( 1, 0, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 9c21bcfc0d26..52f4c39c09bb 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -262,6 +262,52 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }); terminator.kind = TerminatorKind::Goto { target }; } + sym::slice_get_unchecked => { + let target = target.unwrap(); + let Ok([ptrish, index]) = take_array(args) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for {intrinsic:?}", + ); + }; + + let place = ptrish.node.place().unwrap(); + assert!(!place.is_indirect()); + let updated_place = place.project_deeper( + &[ + ProjectionElem::Deref, + ProjectionElem::Index( + index.node.place().unwrap().as_local().unwrap(), + ), + ], + tcx, + ); + + let ret_ty = generic_args.type_at(0); + let rvalue = match *ret_ty.kind() { + ty::RawPtr(_, Mutability::Not) => { + Rvalue::RawPtr(RawPtrKind::Const, updated_place) + } + ty::RawPtr(_, Mutability::Mut) => { + Rvalue::RawPtr(RawPtrKind::Mut, updated_place) + } + ty::Ref(region, _, Mutability::Not) => { + Rvalue::Ref(region, BorrowKind::Shared, updated_place) + } + ty::Ref(region, _, Mutability::Mut) => Rvalue::Ref( + region, + BorrowKind::Mut { kind: MutBorrowKind::Default }, + updated_place, + ), + _ => bug!("Unknown return type {ret_ty:?}"), + }; + + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new((*destination, rvalue))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } sym::transmute | sym::transmute_unchecked => { let dst_ty = destination.ty(local_decls, tcx).ty; let Ok([arg]) = take_array(args) else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ae94169b01dc..970faf2997c5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2000,6 +2000,7 @@ symbols! { slice, slice_from_raw_parts, slice_from_raw_parts_mut, + slice_get_unchecked, slice_into_vec, slice_iter, slice_len_fn, diff --git a/library/core/src/intrinsics/bounds.rs b/library/core/src/intrinsics/bounds.rs new file mode 100644 index 000000000000..046e191212cc --- /dev/null +++ b/library/core/src/intrinsics/bounds.rs @@ -0,0 +1,39 @@ +//! Various traits used to restrict intrinsics to not-completely-wrong types. + +/// Types with a built-in dereference operator in runtime MIR, +/// aka references and raw pointers. +/// +/// # Safety +/// Must actually *be* such a type. +pub unsafe trait BuiltinDeref: Sized { + type Pointee: ?Sized; +} + +unsafe impl BuiltinDeref for &mut T { + type Pointee = T; +} +unsafe impl BuiltinDeref for &T { + type Pointee = T; +} +unsafe impl BuiltinDeref for *mut T { + type Pointee = T; +} +unsafe impl BuiltinDeref for *const T { + type Pointee = T; +} + +pub trait ChangePointee: BuiltinDeref { + type Output; +} +impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee for &'a mut T { + type Output = &'a mut U; +} +impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee for &'a T { + type Output = &'a U; +} +impl ChangePointee for *mut T { + type Output = *mut U; +} +impl ChangePointee for *const T { + type Output = *const U; +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f89baef76f09..10c5ab10390a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -53,6 +53,7 @@ use crate::marker::{ConstParamTy, DiscriminantKind, Tuple}; use crate::ptr; +mod bounds; pub mod fallback; pub mod mir; pub mod simd; @@ -1730,7 +1731,7 @@ pub const fn needs_drop() -> bool; #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn offset(dst: Ptr, offset: Delta) -> Ptr; +pub const unsafe fn offset(dst: Ptr, offset: Delta) -> Ptr; /// Calculates the offset from a pointer, potentially wrapping. /// @@ -1751,6 +1752,33 @@ pub const unsafe fn offset(dst: Ptr, offset: Delta) -> Ptr; #[rustc_intrinsic] pub const unsafe fn arith_offset(dst: *const T, offset: isize) -> *const T; +/// Projects to the `index`-th element of `slice_ptr`, as the same kind of pointer +/// as the slice was provided -- so `&mut [T] → &mut T`, `&[T] → &T`, +/// `*mut [T] → *mut T`, or `*const [T] → *const T` -- without a bounds check. +/// +/// This is exposed via `::get(_unchecked)(_mut)`, +/// and isn't intended to be used elsewhere. +/// +/// Expands in MIR to `{&, &mut, &raw const, &raw mut} (*slice_ptr)[index]`, +/// depending on the types involved, so no backend support is needed. +/// +/// # Safety +/// +/// - `index < PtrMetadata(slice_ptr)`, so the indexing is in-bounds for the slice +/// - the resulting offsetting is in-bounds of the allocated object, which is +/// always the case for references, but needs to be upheld manually for pointers +#[cfg(not(bootstrap))] +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn slice_get_unchecked< + ItemPtr: bounds::ChangePointee<[T], Pointee = T, Output = SlicePtr>, + SlicePtr, + T, +>( + slice_ptr: SlicePtr, + index: usize, +) -> ItemPtr; + /// Masks out bits of the pointer according to a mask. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -3575,18 +3603,9 @@ pub const fn type_id() -> u128; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn aggregate_raw_ptr, D, M>(data: D, meta: M) -> P; - -#[unstable(feature = "core_intrinsics", issue = "none")] -pub trait AggregateRawPtr { - type Metadata: Copy; -} -impl AggregateRawPtr<*const T> for *const P { - type Metadata =

::Metadata; -} -impl AggregateRawPtr<*mut T> for *mut P { - type Metadata =

::Metadata; -} +pub const fn aggregate_raw_ptr(data: D, meta: M) -> P +where +

::Pointee: ptr::Pointee; /// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`. /// diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index b18d316c73a6..69160a911b21 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,5 +1,7 @@ //! Indexing implementations for `[T]`. +#[cfg(not(bootstrap))] +use crate::intrinsics::slice_get_unchecked; use crate::panic::const_panic; use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; @@ -83,6 +85,7 @@ const fn slice_end_index_overflow_fail() -> ! { // Both the safe and unsafe public methods share these helpers, // which use intrinsics directly to get *no* extra checks. +#[cfg(bootstrap)] #[inline(always)] const unsafe fn get_noubcheck(ptr: *const [T], index: usize) -> *const T { let ptr = ptr as *const T; @@ -90,6 +93,7 @@ const unsafe fn get_noubcheck(ptr: *const [T], index: usize) -> *const T { unsafe { crate::intrinsics::offset(ptr, index) } } +#[cfg(bootstrap)] #[inline(always)] const unsafe fn get_mut_noubcheck(ptr: *mut [T], index: usize) -> *mut T { let ptr = ptr as *mut T; @@ -103,8 +107,9 @@ const unsafe fn get_offset_len_noubcheck( offset: usize, len: usize, ) -> *const [T] { + let ptr = ptr as *const T; // SAFETY: The caller already checked these preconditions - let ptr = unsafe { get_noubcheck(ptr, offset) }; + let ptr = unsafe { crate::intrinsics::offset(ptr, offset) }; crate::intrinsics::aggregate_raw_ptr(ptr, len) } @@ -114,8 +119,9 @@ const unsafe fn get_offset_len_mut_noubcheck( offset: usize, len: usize, ) -> *mut [T] { + let ptr = ptr as *mut T; // SAFETY: The caller already checked these preconditions - let ptr = unsafe { get_mut_noubcheck(ptr, offset) }; + let ptr = unsafe { crate::intrinsics::offset(ptr, offset) }; crate::intrinsics::aggregate_raw_ptr(ptr, len) } @@ -224,15 +230,35 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] fn get(self, slice: &[T]) -> Option<&T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*get_noubcheck(slice, self)) } } else { None } + if self < slice.len() { + #[cfg(bootstrap)] + // SAFETY: `self` is checked to be in bounds. + unsafe { + Some(&*get_noubcheck(slice, self)) + } + #[cfg(not(bootstrap))] + // SAFETY: `self` is checked to be in bounds. + unsafe { + Some(slice_get_unchecked(slice, self)) + } + } else { + None + } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { if self < slice.len() { + #[cfg(bootstrap)] // SAFETY: `self` is checked to be in bounds. - unsafe { Some(&mut *get_mut_noubcheck(slice, self)) } + unsafe { + Some(&mut *get_mut_noubcheck(slice, self)) + } + #[cfg(not(bootstrap))] + // SAFETY: `self` is checked to be in bounds. + unsafe { + Some(slice_get_unchecked(slice, self)) + } } else { None } @@ -254,7 +280,14 @@ unsafe impl SliceIndex<[T]> for usize { // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the // precondition of this function twice. crate::intrinsics::assume(self < slice.len()); - get_noubcheck(slice, self) + #[cfg(bootstrap)] + { + get_noubcheck(slice, self) + } + #[cfg(not(bootstrap))] + { + slice_get_unchecked(slice, self) + } } } @@ -267,7 +300,16 @@ unsafe impl SliceIndex<[T]> for usize { (this: usize = self, len: usize = slice.len()) => this < len ); // SAFETY: see comments for `get_unchecked` above. - unsafe { get_mut_noubcheck(slice, self) } + unsafe { + #[cfg(bootstrap)] + { + get_mut_noubcheck(slice, self) + } + #[cfg(not(bootstrap))] + { + slice_get_unchecked(slice, self) + } + } } #[inline] diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 4e000b05a4b4..1e4f20241947 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -263,3 +263,24 @@ pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug let _usize = ptr_metadata(b); let _vtable = ptr_metadata(c); } + +// EMIT_MIR lower_intrinsics.slice_get.LowerIntrinsics.diff +pub unsafe fn slice_get<'a, 'b>( + r: &'a [i8], + rm: &'b mut [i16], + p: *const [i32], + pm: *mut [i64], + i: usize, +) -> (&'a i8, &'b mut i16, *const i32, *mut i64) { + use std::intrinsics::slice_get_unchecked; + // CHECK: = &(*_{{[0-9]+}})[_{{[0-9]+}}] + // CHECK: = &mut (*_{{[0-9]+}})[_{{[0-9]+}}] + // CHECK: = &raw const (*_{{[0-9]+}})[_{{[0-9]+}}] + // CHECK: = &raw mut (*_{{[0-9]+}})[_{{[0-9]+}}] + ( + slice_get_unchecked(r, i), + slice_get_unchecked(rm, i), + slice_get_unchecked(p, i), + slice_get_unchecked(pm, i), + ) +} diff --git a/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-abort.diff new file mode 100644 index 000000000000..d18bdc431683 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-abort.diff @@ -0,0 +1,85 @@ +- // MIR for `slice_get` before LowerIntrinsics ++ // MIR for `slice_get` after LowerIntrinsics + + fn slice_get(_1: &[i8], _2: &mut [i16], _3: *const [i32], _4: *mut [i64], _5: usize) -> (&i8, &mut i16, *const i32, *mut i64) { + debug r => _1; + debug rm => _2; + debug p => _3; + debug pm => _4; + debug i => _5; + let mut _0: (&i8, &mut i16, *const i32, *mut i64); + let mut _6: &i8; + let mut _7: &[i8]; + let mut _8: usize; + let mut _9: &mut i16; + let mut _10: &mut [i16]; + let mut _11: usize; + let mut _12: *const i32; + let mut _13: *const [i32]; + let mut _14: usize; + let mut _15: *mut i64; + let mut _16: *mut [i64]; + let mut _17: usize; + + bb0: { + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; + StorageLive(_8); + _8 = copy _5; +- _6 = slice_get_unchecked::<&i8, &[i8], i8>(move _7, move _8) -> [return: bb1, unwind unreachable]; ++ _6 = &(*_7)[_8]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_8); + StorageDead(_7); + StorageLive(_9); + StorageLive(_10); + _10 = move _2; + StorageLive(_11); + _11 = copy _5; +- _9 = slice_get_unchecked::<&mut i16, &mut [i16], i16>(move _10, move _11) -> [return: bb2, unwind unreachable]; ++ _9 = &mut (*_10)[_11]; ++ goto -> bb2; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = copy _3; + StorageLive(_14); + _14 = copy _5; +- _12 = slice_get_unchecked::<*const i32, *const [i32], i32>(move _13, move _14) -> [return: bb3, unwind unreachable]; ++ _12 = &raw const (*_13)[_14]; ++ goto -> bb3; + } + + bb3: { + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + StorageLive(_16); + _16 = copy _4; + StorageLive(_17); + _17 = copy _5; +- _15 = slice_get_unchecked::<*mut i64, *mut [i64], i64>(move _16, move _17) -> [return: bb4, unwind unreachable]; ++ _15 = &raw mut (*_16)[_17]; ++ goto -> bb4; + } + + bb4: { + StorageDead(_17); + StorageDead(_16); + _0 = (move _6, move _9, move _12, move _15); + StorageDead(_15); + StorageDead(_12); + StorageDead(_9); + StorageDead(_6); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-unwind.diff new file mode 100644 index 000000000000..d18bdc431683 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.slice_get.LowerIntrinsics.panic-unwind.diff @@ -0,0 +1,85 @@ +- // MIR for `slice_get` before LowerIntrinsics ++ // MIR for `slice_get` after LowerIntrinsics + + fn slice_get(_1: &[i8], _2: &mut [i16], _3: *const [i32], _4: *mut [i64], _5: usize) -> (&i8, &mut i16, *const i32, *mut i64) { + debug r => _1; + debug rm => _2; + debug p => _3; + debug pm => _4; + debug i => _5; + let mut _0: (&i8, &mut i16, *const i32, *mut i64); + let mut _6: &i8; + let mut _7: &[i8]; + let mut _8: usize; + let mut _9: &mut i16; + let mut _10: &mut [i16]; + let mut _11: usize; + let mut _12: *const i32; + let mut _13: *const [i32]; + let mut _14: usize; + let mut _15: *mut i64; + let mut _16: *mut [i64]; + let mut _17: usize; + + bb0: { + StorageLive(_6); + StorageLive(_7); + _7 = copy _1; + StorageLive(_8); + _8 = copy _5; +- _6 = slice_get_unchecked::<&i8, &[i8], i8>(move _7, move _8) -> [return: bb1, unwind unreachable]; ++ _6 = &(*_7)[_8]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_8); + StorageDead(_7); + StorageLive(_9); + StorageLive(_10); + _10 = move _2; + StorageLive(_11); + _11 = copy _5; +- _9 = slice_get_unchecked::<&mut i16, &mut [i16], i16>(move _10, move _11) -> [return: bb2, unwind unreachable]; ++ _9 = &mut (*_10)[_11]; ++ goto -> bb2; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = copy _3; + StorageLive(_14); + _14 = copy _5; +- _12 = slice_get_unchecked::<*const i32, *const [i32], i32>(move _13, move _14) -> [return: bb3, unwind unreachable]; ++ _12 = &raw const (*_13)[_14]; ++ goto -> bb3; + } + + bb3: { + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + StorageLive(_16); + _16 = copy _4; + StorageLive(_17); + _17 = copy _5; +- _15 = slice_get_unchecked::<*mut i64, *mut [i64], i64>(move _16, move _17) -> [return: bb4, unwind unreachable]; ++ _15 = &raw mut (*_16)[_17]; ++ goto -> bb4; + } + + bb4: { + StorageDead(_17); + StorageDead(_16); + _0 = (move _6, move _9, move _12, move _15); + StorageDead(_15); + StorageDead(_12); + StorageDead(_9); + StorageDead(_6); + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index ec67193bc794..d1b1e3d7dd73 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -8,19 +8,11 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { scope 2 (inlined >::get_mut) { let mut _3: usize; let mut _4: bool; - let mut _5: *mut [u32]; - let mut _7: *mut u32; - let mut _8: &mut u32; - scope 3 (inlined core::slice::index::get_mut_noubcheck::) { - let _6: *mut u32; - scope 4 { - } - } + let mut _5: &mut u32; } } bb0: { - StorageLive(_8); StorageLive(_4); StorageLive(_3); _3 = PtrMetadata(copy _1); @@ -36,23 +28,15 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { bb2: { StorageDead(_3); - StorageLive(_7); StorageLive(_5); - _5 = &raw mut (*_1); - StorageLive(_6); - _6 = copy _5 as *mut u32 (PtrToPtr); - _7 = Offset(copy _6, copy _2); - StorageDead(_6); + _5 = &mut (*_1)[_2]; + _0 = Option::<&mut u32>::Some(move _5); StorageDead(_5); - _8 = &mut (*_7); - _0 = Option::<&mut u32>::Some(copy _8); - StorageDead(_7); goto -> bb3; } bb3: { StorageDead(_4); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index ec67193bc794..d1b1e3d7dd73 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -8,19 +8,11 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { scope 2 (inlined >::get_mut) { let mut _3: usize; let mut _4: bool; - let mut _5: *mut [u32]; - let mut _7: *mut u32; - let mut _8: &mut u32; - scope 3 (inlined core::slice::index::get_mut_noubcheck::) { - let _6: *mut u32; - scope 4 { - } - } + let mut _5: &mut u32; } } bb0: { - StorageLive(_8); StorageLive(_4); StorageLive(_3); _3 = PtrMetadata(copy _1); @@ -36,23 +28,15 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { bb2: { StorageDead(_3); - StorageLive(_7); StorageLive(_5); - _5 = &raw mut (*_1); - StorageLive(_6); - _6 = copy _5 as *mut u32 (PtrToPtr); - _7 = Offset(copy _6, copy _2); - StorageDead(_6); + _5 = &mut (*_1)[_2]; + _0 = Option::<&mut u32>::Some(move _5); StorageDead(_5); - _8 = &mut (*_7); - _0 = Option::<&mut u32>::Some(copy _8); - StorageDead(_7); goto -> bb3; } bb3: { StorageDead(_4); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 597f02e837ab..6fb1637a6e02 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -15,12 +15,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let _8: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { - let _10: *mut u32; + let _9: *mut u32; scope 7 { - } - scope 8 (inlined core::slice::index::get_mut_noubcheck::) { - let _9: *mut u32; - scope 9 { + let _10: *mut u32; + scope 8 { } } } @@ -47,13 +45,13 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> bb1: { StorageDead(_6); _8 = SubUnchecked(copy _4, copy _3); - StorageLive(_10); StorageLive(_9); + StorageLive(_10); _9 = copy _5 as *mut u32 (PtrToPtr); _10 = Offset(copy _9, copy _3); - StorageDead(_9); _11 = *mut [u32] from (copy _10, copy _8); StorageDead(_10); + StorageDead(_9); StorageDead(_8); StorageDead(_5); _0 = &mut (*_11); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 597f02e837ab..6fb1637a6e02 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -15,12 +15,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let _8: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { - let _10: *mut u32; + let _9: *mut u32; scope 7 { - } - scope 8 (inlined core::slice::index::get_mut_noubcheck::) { - let _9: *mut u32; - scope 9 { + let _10: *mut u32; + scope 8 { } } } @@ -47,13 +45,13 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> bb1: { StorageDead(_6); _8 = SubUnchecked(copy _4, copy _3); - StorageLive(_10); StorageLive(_9); + StorageLive(_10); _9 = copy _5 as *mut u32 (PtrToPtr); _10 = Offset(copy _9, copy _3); - StorageDead(_9); _11 = *mut [u32] from (copy _10, copy _8); StorageDead(_10); + StorageDead(_9); StorageDead(_8); StorageDead(_5); _0 = &mut (*_11); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index e34723898e4a..ad1ca5dff43a 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -13,12 +13,10 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - let _7: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { - let _9: *const u32; + let _8: *const u32; scope 7 { - } - scope 8 (inlined core::slice::index::get_noubcheck::) { - let _8: *const u32; - scope 9 { + let _9: *const u32; + scope 8 { } } } @@ -42,13 +40,13 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - bb1: { StorageDead(_5); _7 = SubUnchecked(copy _4, copy _3); - StorageLive(_9); StorageLive(_8); + StorageLive(_9); _8 = copy _1 as *const u32 (PtrToPtr); _9 = Offset(copy _8, copy _3); - StorageDead(_8); _0 = *const [u32] from (copy _9, copy _7); StorageDead(_9); + StorageDead(_8); StorageDead(_7); return; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index e34723898e4a..ad1ca5dff43a 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -13,12 +13,10 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - let _7: usize; scope 3 { scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { - let _9: *const u32; + let _8: *const u32; scope 7 { - } - scope 8 (inlined core::slice::index::get_noubcheck::) { - let _8: *const u32; - scope 9 { + let _9: *const u32; + scope 8 { } } } @@ -42,13 +40,13 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - bb1: { StorageDead(_5); _7 = SubUnchecked(copy _4, copy _3); - StorageLive(_9); StorageLive(_8); + StorageLive(_9); _8 = copy _1 as *const u32 (PtrToPtr); _9 = Offset(copy _8, copy _3); - StorageDead(_8); _0 = *const [u32] from (copy _9, copy _7); StorageDead(_9); + StorageDead(_8); StorageDead(_7); return; } From cea87ecad6360e06abbead84d9ffdf78c01db7d1 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 18 May 2025 16:38:43 +0800 Subject: [PATCH 23/34] std: clarify Clone trait documentation about duplication semantics This commit improves the Clone trait documentation to address confusion around what "duplication" means for different types, especially for smart pointers like Arc>. Signed-off-by: xizheyin --- library/core/src/clone.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index c237ac84cf40..2c0662c96290 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -38,7 +38,16 @@ mod uninit; -/// A common trait for the ability to explicitly duplicate an object. +/// A common trait that allows explicit creation of a duplicate value. +/// +/// Calling [`clone`] always produces a new value. +/// However, for types that are references to other data (such as smart pointers or references), +/// the new value may still point to the same underlying data, rather than duplicating it. +/// See [`Clone::clone`] for more details. +/// +/// This distinction is especially important when using `#[derive(Clone)]` on structs containing +/// smart pointers like `Arc>` - the cloned struct will share mutable state with the +/// original. /// /// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while /// `Clone` is always explicit and may or may not be expensive. In order to enforce @@ -147,7 +156,16 @@ mod uninit; #[rustc_diagnostic_item = "Clone"] #[rustc_trivial_field_reads] pub trait Clone: Sized { - /// Returns a copy of the value. + /// Returns a duplicate of the value. + /// + /// Note that what "duplicate" means varies by type: + /// - For most types, this creates a deep, independent copy + /// - For reference types like `&T`, this creates another reference to the same value + /// - For smart pointers like [`Arc`] or [`Rc`], this increments the reference count + /// but still points to the same underlying data + /// + /// [`Arc`]: ../../std/sync/struct.Arc.html + /// [`Rc`]: ../../std/rc/struct.Rc.html /// /// # Examples /// @@ -157,6 +175,23 @@ pub trait Clone: Sized { /// /// assert_eq!("Hello", hello.clone()); /// ``` + /// + /// Example with a reference-counted type: + /// + /// ``` + /// use std::sync::{Arc, Mutex}; + /// + /// let data = Arc::new(Mutex::new(vec![1, 2, 3])); + /// let data_clone = data.clone(); // Creates another Arc pointing to the same Mutex + /// + /// { + /// let mut lock = data.lock().unwrap(); + /// lock.push(4); + /// } + /// + /// // Changes are visible through the clone because they share the same underlying data + /// assert_eq!(*data_clone.lock().unwrap(), vec![1, 2, 3, 4]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] // Clone::clone is special because the compiler generates MIR to implement it for some types. From 17352e6937fde53c4f75dfd8600ecff4f1077ca2 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 9 May 2025 15:30:16 +0800 Subject: [PATCH 24/34] Note ref expr being cast when encounter NonScalar cast error Signed-off-by: xizheyin --- compiler/rustc_hir_typeck/src/cast.rs | 10 ++++++++++ tests/ui/cast/func-pointer-issue-140491.stderr | 2 ++ tests/ui/coercion/issue-73886.stderr | 2 ++ 3 files changed, 14 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c044c4f7c37d..e144a6ab5999 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -408,6 +408,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, fcx.ty_to_string(self.cast_ty) ); + + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) + && matches!(self.expr.kind, ExprKind::AddrOf(..)) + { + err.note(format!( + "casting reference expression `{}` because `&` binds tighter than `as`", + snippet + )); + } + let mut sugg = None; let mut sugg_mutref = false; if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { diff --git a/tests/ui/cast/func-pointer-issue-140491.stderr b/tests/ui/cast/func-pointer-issue-140491.stderr index ebd4b18502ec..e1c07010e691 100644 --- a/tests/ui/cast/func-pointer-issue-140491.stderr +++ b/tests/ui/cast/func-pointer-issue-140491.stderr @@ -3,6 +3,8 @@ error[E0605]: non-primitive cast: `&for<'a, 'b> fn(&'a Event<'b>) {my_fn}` as `& | LL | ..._>) = &my_fn as _; | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | + = note: casting reference expression `&my_fn` because `&` binds tighter than `as` error: aborting due to 1 previous error diff --git a/tests/ui/coercion/issue-73886.stderr b/tests/ui/coercion/issue-73886.stderr index 0d4c90017cf1..a287aa29e118 100644 --- a/tests/ui/coercion/issue-73886.stderr +++ b/tests/ui/coercion/issue-73886.stderr @@ -3,6 +3,8 @@ error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]` | LL | let _ = &&[0] as &[_]; | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | + = note: casting reference expression `&&[0]` because `&` binds tighter than `as` error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 From 3253de651f5811fd33a09652139234a427349c83 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 May 2025 10:59:26 +0000 Subject: [PATCH 25/34] Add some new solver to PGO --- src/build_helper/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 7e580db48aa9..1f5cf7236411 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -29,4 +29,5 @@ pub const RUSTC_PGO_CRATES: &[&str] = &[ "tuple-stress", "diesel-2.2.10", "bitmaps-3.2.1", + "serde-1.0.219-new-solver", ]; From 7e9aee773ae3d58aeee403a5e0900b034849f2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 15 May 2025 21:13:29 +0200 Subject: [PATCH 26/34] Enable non-leaf Frame Pointers for mingw-w64 Arm64 Windows --- .../src/spec/targets/aarch64_pc_windows_gnullvm.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index a8b133d19bb0..eee668cc67ed 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -1,4 +1,4 @@ -use crate::spec::{Target, TargetMetadata, base}; +use crate::spec::{FramePointer, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut base = base::windows_gnullvm::opts(); @@ -6,6 +6,12 @@ pub(crate) fn target() -> Target { base.features = "+v8a,+neon,+fp-armv8".into(); base.linker = Some("aarch64-w64-mingw32-clang".into()); + // Microsoft recommends enabling frame pointers on Arm64 Windows. + // From https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#integer-registers + // "The frame pointer (x29) is required for compatibility with fast stack walking used by ETW + // and other services. It must point to the previous {x29, x30} pair on the stack." + base.frame_pointer = FramePointer::NonLeaf; + Target { llvm_target: "aarch64-pc-windows-gnu".into(), metadata: TargetMetadata { From 98961cd3da999cda30a1ab6c751bc9cf0a6cb6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 27 Apr 2025 13:10:06 +0200 Subject: [PATCH 27/34] Fix incorrect comment --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d5ea96b43f56..38c1c8522105 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1409,7 +1409,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags); } - // Building with a static libstdc++ is only supported on linux right now, + // Building with a static libstdc++ is only supported on Linux and windows-gnu* right now, // not for MSVC or macOS if builder.config.llvm_static_stdcpp && !target.contains("freebsd") From 7eea11b27c602deed37d94c87c21f4b14f858170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Tue, 6 May 2025 18:29:31 +0200 Subject: [PATCH 28/34] Fix C++ standard library name for *-windows-gnullvm targets --- src/bootstrap/src/core/build_steps/compile.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 38c1c8522105..8668550bddf3 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1417,12 +1417,14 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect && !target.contains("apple") && !target.contains("solaris") { + let libstdcxx_name = + if target.contains("windows-gnullvm") { "libc++.a" } else { "libstdc++.a" }; let file = compiler_file( builder, &builder.cxx(target).unwrap(), target, CLang::Cxx, - "libstdc++.a", + libstdcxx_name, ); cargo.env("LLVM_STATIC_STDCPP", file); } From 885184ae41b5dd857d3e1b3c5a326a5858699550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Tue, 6 May 2025 18:41:18 +0200 Subject: [PATCH 29/34] Shared libLLVM linking is officially supported with MinGW and Clang --- src/bootstrap/src/core/build_steps/llvm.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 5e4a1c7d9f07..979ff3992672 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -285,7 +285,8 @@ impl Step for Llvm { LlvmBuildStatus::ShouldBuild(m) => m, }; - if builder.llvm_link_shared() && target.is_windows() { + if builder.llvm_link_shared() && target.is_windows() && !target.ends_with("windows-gnullvm") + { panic!("shared linking to LLVM is not currently supported on {}", target.triple); } From 3cba746b4968cf4c17ad0c638ef993dae33b2754 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 17 May 2025 15:19:05 +0800 Subject: [PATCH 30/34] std: note that `std::str::from_utf8*` functions are aliases to `std::::from_utf8*` methods Signed-off-by: xizheyin --- library/core/src/str/converts.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 058628797ea8..6da9dce2d870 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -6,6 +6,8 @@ use crate::{mem, ptr}; /// Converts a slice of bytes to a string slice. /// +/// This is an alias to [`str::from_utf8`]. +/// /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice /// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between /// the two. Not all byte slices are valid string slices, however: [`&str`] requires @@ -97,6 +99,8 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// Converts a mutable slice of bytes to a mutable string slice. /// +/// This is an alias to [`str::from_utf8_mut`]. +/// /// # Examples /// /// Basic usage: @@ -142,6 +146,8 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// +/// This is an alias to [`str::from_utf8_unchecked`]. +/// /// See the safe version, [`from_utf8`], for more information. /// /// # Safety @@ -178,6 +184,8 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8; mutable version. /// +/// This is an alias to [`str::from_utf8_unchecked_mut`]. +/// /// See the immutable version, [`from_utf8_unchecked()`] for documentation and safety requirements. /// /// # Examples From a261d167ac33c8fa9fc5fd46f70f46679fefb5b9 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 31 May 2025 18:29:25 +0200 Subject: [PATCH 31/34] Failing tests for "consider borrowing" --- .../ui/typeck/consider-borrowing-141810-1.rs | 9 +++++++ .../typeck/consider-borrowing-141810-1.stderr | 26 +++++++++++++++++++ .../ui/typeck/consider-borrowing-141810-2.rs | 8 ++++++ .../typeck/consider-borrowing-141810-2.stderr | 24 +++++++++++++++++ .../ui/typeck/consider-borrowing-141810-3.rs | 7 +++++ .../typeck/consider-borrowing-141810-3.stderr | 26 +++++++++++++++++++ .../ui/typeck/consider-borrowing-141810-4.rs | 11 ++++++++ .../typeck/consider-borrowing-141810-4.stderr | 14 ++++++++++ 8 files changed, 125 insertions(+) create mode 100644 tests/ui/typeck/consider-borrowing-141810-1.rs create mode 100644 tests/ui/typeck/consider-borrowing-141810-1.stderr create mode 100644 tests/ui/typeck/consider-borrowing-141810-2.rs create mode 100644 tests/ui/typeck/consider-borrowing-141810-2.stderr create mode 100644 tests/ui/typeck/consider-borrowing-141810-3.rs create mode 100644 tests/ui/typeck/consider-borrowing-141810-3.stderr create mode 100644 tests/ui/typeck/consider-borrowing-141810-4.rs create mode 100644 tests/ui/typeck/consider-borrowing-141810-4.stderr diff --git a/tests/ui/typeck/consider-borrowing-141810-1.rs b/tests/ui/typeck/consider-borrowing-141810-1.rs new file mode 100644 index 000000000000..94c2d6909151 --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-1.rs @@ -0,0 +1,9 @@ +fn main() { + let x = if true { + &true + } else if false { //~ ERROR `if` and `else` have incompatible types [E0308] + true //~ HELP consider borrowing here + } else { + true + }; +} diff --git a/tests/ui/typeck/consider-borrowing-141810-1.stderr b/tests/ui/typeck/consider-borrowing-141810-1.stderr new file mode 100644 index 000000000000..3cb5d23d3a7c --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-1.stderr @@ -0,0 +1,26 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/consider-borrowing-141810-1.rs:4:12 + | +LL | let x = if true { + | ______________- +LL | | &true + | | ----- expected because of this +LL | | } else if false { + | | ____________^ +LL | || true +LL | || } else { +LL | || true +LL | || }; + | || ^ + | ||_____| + | |_____`if` and `else` have incompatible types + | expected `&bool`, found `bool` + | +help: consider borrowing here + | +LL | } else &if false { + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/consider-borrowing-141810-2.rs b/tests/ui/typeck/consider-borrowing-141810-2.rs new file mode 100644 index 000000000000..e32e689efb7e --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-2.rs @@ -0,0 +1,8 @@ +fn main() { + let x = if true { + &() + } else if false { //~ ERROR `if` and `else` have incompatible types [E0308] + } else { + }; + +} diff --git a/tests/ui/typeck/consider-borrowing-141810-2.stderr b/tests/ui/typeck/consider-borrowing-141810-2.stderr new file mode 100644 index 000000000000..b00384d2d5a6 --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-2.stderr @@ -0,0 +1,24 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/consider-borrowing-141810-2.rs:4:12 + | +LL | let x = if true { + | ______________- +LL | | &() + | | --- expected because of this +LL | | } else if false { + | | ____________^ +LL | || } else { +LL | || }; + | || ^ + | ||_____| + | |_____`if` and `else` have incompatible types + | expected `&()`, found `()` + | +help: consider borrowing here + | +LL | } else &if false { + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/consider-borrowing-141810-3.rs b/tests/ui/typeck/consider-borrowing-141810-3.rs new file mode 100644 index 000000000000..d38828de7c17 --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-3.rs @@ -0,0 +1,7 @@ +fn main() { + let x = if true { + &() + } else if false { //~ ERROR `if` and `else` have incompatible types [E0308] + + }; +} diff --git a/tests/ui/typeck/consider-borrowing-141810-3.stderr b/tests/ui/typeck/consider-borrowing-141810-3.stderr new file mode 100644 index 000000000000..f33920d1325d --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-3.stderr @@ -0,0 +1,26 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/consider-borrowing-141810-3.rs:4:12 + | +LL | let x = if true { + | ______________- +LL | | &() + | | --- expected because of this +LL | | } else if false { + | | ____________^ +LL | || +LL | || }; + | || ^ + | ||_____| + | |_____`if` and `else` have incompatible types + | expected `&()`, found `()` + | + = note: `if` expressions without `else` evaluate to `()` + = note: consider adding an `else` block that evaluates to the expected type +help: consider borrowing here + | +LL | } else &if false { + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/consider-borrowing-141810-4.rs b/tests/ui/typeck/consider-borrowing-141810-4.rs new file mode 100644 index 000000000000..754af7920a85 --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-4.rs @@ -0,0 +1,11 @@ +fn baz(x: &String) {} + +fn bar() { + baz({ + String::from("hi") //~ ERROR mismatched types + }); +} + +fn main() { + bar(); +} diff --git a/tests/ui/typeck/consider-borrowing-141810-4.stderr b/tests/ui/typeck/consider-borrowing-141810-4.stderr new file mode 100644 index 000000000000..80869d4a5d5c --- /dev/null +++ b/tests/ui/typeck/consider-borrowing-141810-4.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/consider-borrowing-141810-4.rs:5:9 + | +LL | String::from("hi") + | ^^^^^^^^^^^^^^^^^^ expected `&String`, found `String` + | +help: consider borrowing here + | +LL | &String::from("hi") + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From b1a1df2efe0a2d3af7d71566d09d4724a89e039a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 31 May 2025 18:34:26 +0200 Subject: [PATCH 32/34] Fix consider borrowing for else-if --- .../src/fn_ctxt/suggestions.rs | 25 +++++++++++++++++++ .../typeck/consider-borrowing-141810-1.stderr | 6 +++-- .../typeck/consider-borrowing-141810-2.stderr | 5 ---- .../typeck/consider-borrowing-141810-3.stderr | 4 --- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 43b662ca453d..1c3bc338d85b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2713,6 +2713,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } + // Don't try to suggest ref/deref on an `if` expression, because: + // - The `if` could be part of a desugared `if else` statement, + // which would create impossible suggestions such as `if ... { ... } else &if { ... } else { ... }`. + // - In general the suggestions it creates such as `&if ... { ... } else { ... }` are not very helpful. + // We try to generate a suggestion such as `if ... { &... } else { &... }` instead. + if let hir::ExprKind::If(_c, then, els) = expr.kind { + // The `then` of a `Expr::If` always contains a block, and that block may have a final expression that we can borrow + // If the block does not have a final expression, it will return () and we do not make a suggestion to borrow that. + let ExprKind::Block(then, _) = then.kind else { return None }; + let Some(then) = then.expr else { return None }; + let (mut suggs, help, app, verbose, mutref) = + self.suggest_deref_or_ref(then, checked_ty, expected)?; + + // If there is no `else`, the return type of this `if` will be (), so suggesting to change the `then` block is useless + let els_expr = match els?.kind { + ExprKind::Block(block, _) => block.expr?, + _ => els?, + }; + let (else_suggs, ..) = + self.suggest_deref_or_ref(els_expr, checked_ty, expected)?; + suggs.extend(else_suggs); + + return Some((suggs, help, app, verbose, mutref)); + } + if let Some((sugg, msg)) = self.can_use_as_ref(expr) { return Some(( sugg, diff --git a/tests/ui/typeck/consider-borrowing-141810-1.stderr b/tests/ui/typeck/consider-borrowing-141810-1.stderr index 3cb5d23d3a7c..9291721ac712 100644 --- a/tests/ui/typeck/consider-borrowing-141810-1.stderr +++ b/tests/ui/typeck/consider-borrowing-141810-1.stderr @@ -18,8 +18,10 @@ LL | || }; | help: consider borrowing here | -LL | } else &if false { - | + +LL ~ &true +LL | } else { +LL ~ &true + | error: aborting due to 1 previous error diff --git a/tests/ui/typeck/consider-borrowing-141810-2.stderr b/tests/ui/typeck/consider-borrowing-141810-2.stderr index b00384d2d5a6..dd229897283b 100644 --- a/tests/ui/typeck/consider-borrowing-141810-2.stderr +++ b/tests/ui/typeck/consider-borrowing-141810-2.stderr @@ -13,11 +13,6 @@ LL | || }; | ||_____| | |_____`if` and `else` have incompatible types | expected `&()`, found `()` - | -help: consider borrowing here - | -LL | } else &if false { - | + error: aborting due to 1 previous error diff --git a/tests/ui/typeck/consider-borrowing-141810-3.stderr b/tests/ui/typeck/consider-borrowing-141810-3.stderr index f33920d1325d..0b0c5f191a0d 100644 --- a/tests/ui/typeck/consider-borrowing-141810-3.stderr +++ b/tests/ui/typeck/consider-borrowing-141810-3.stderr @@ -16,10 +16,6 @@ LL | || }; | = note: `if` expressions without `else` evaluate to `()` = note: consider adding an `else` block that evaluates to the expected type -help: consider borrowing here - | -LL | } else &if false { - | + error: aborting due to 1 previous error From f8e97badb26f1436d062b3bfdd4f50adc41b843a Mon Sep 17 00:00:00 2001 From: Ruan Comelli Date: Mon, 19 May 2025 18:34:32 -0300 Subject: [PATCH 33/34] Add const support for float rounding methods Add const support for the float rounding methods floor, ceil, trunc, fract, round and round_ties_even. This works by moving the calculation logic from src/tools/miri/src/intrinsics/mod.rs into compiler/rustc_const_eval/src/interpret/intrinsics.rs. All relevant method definitions were adjusted to include the `const` keyword for all supported float types: f16, f32, f64 and f128. The constness is hidden behind the feature gate feature(const_float_round_methods) which is tracked in https://github.com/rust-lang/rust/issues/141555 This commit is a squash of the following commits: - test: add tests that we expect to pass when float rounding becomes const - feat: make float rounding methods `const` - fix: replace `rustc_allow_const_fn_unstable(core_intrinsics)` attribute with `#[rustc_const_unstable(feature = "f128", issue = "116909")]` in `library/core/src/num/f128.rs` - revert: undo update to `library/stdarch` - refactor: replace multiple `float__intrinsic` rounding methods with a single, parametrized one - fix: add `#[cfg(not(bootstrap))]` to new const method tests - test: add extra sign tests to check `+0.0` and `-0.0` - revert: undo accidental changes to `round` docs - fix: gate `const` float round method behind `const_float_round_methods` - fix: remove unnecessary `#![feature(const_float_methods)]` - fix: remove unnecessary `#![feature(const_float_methods)]` [2] - revert: undo changes to `tests/ui/consts/const-eval/float_methods.rs` - fix: adjust after rebase - test: fix float tests - test: add tests for `fract` - chore: add commented-out `const_float_round_methods` feature gates to `f16` and `f128` - fix: adjust NaN when rounding floats - chore: add FIXME comment for de-duplicating float tests - test: remove unnecessary test file `tests/ui/consts/const-eval/float_methods.rs` - test: fix tests after upstream simplification of how float tests are run --- .../src/interpret/intrinsics.rs | 113 +++++++++++++++++ library/core/src/intrinsics/mod.rs | 40 +++--- library/core/src/num/f128.rs | 24 +++- library/core/src/num/f16.rs | 24 +++- library/core/src/num/f32.rs | 18 ++- library/core/src/num/f64.rs | 18 ++- library/coretests/tests/lib.rs | 1 + library/coretests/tests/num/mod.rs | 114 ++++++++++++++++++ library/std/src/lib.rs | 1 + library/std/src/num/f32.rs | 18 ++- library/std/src/num/f64.rs | 18 ++- src/tools/miri/src/intrinsics/mod.rs | 61 ---------- 12 files changed, 333 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index bf4152d4b8cd..64467a901369 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -518,6 +518,103 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::fabsf64 => self.float_abs_intrinsic::(args, dest)?, sym::fabsf128 => self.float_abs_intrinsic::(args, dest)?, + sym::floorf16 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardNegative, + )?, + sym::floorf32 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardNegative, + )?, + sym::floorf64 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardNegative, + )?, + sym::floorf128 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardNegative, + )?, + + sym::ceilf16 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardPositive, + )?, + sym::ceilf32 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardPositive, + )?, + sym::ceilf64 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardPositive, + )?, + sym::ceilf128 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::TowardPositive, + )?, + + sym::truncf16 => { + self.float_round_intrinsic::(args, dest, rustc_apfloat::Round::TowardZero)? + } + sym::truncf32 => { + self.float_round_intrinsic::(args, dest, rustc_apfloat::Round::TowardZero)? + } + sym::truncf64 => { + self.float_round_intrinsic::(args, dest, rustc_apfloat::Round::TowardZero)? + } + sym::truncf128 => { + self.float_round_intrinsic::(args, dest, rustc_apfloat::Round::TowardZero)? + } + + sym::roundf16 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToAway, + )?, + sym::roundf32 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToAway, + )?, + sym::roundf64 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToAway, + )?, + sym::roundf128 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToAway, + )?, + + sym::round_ties_even_f16 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToEven, + )?, + sym::round_ties_even_f32 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToEven, + )?, + sym::round_ties_even_f64 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToEven, + )?, + sym::round_ties_even_f128 => self.float_round_intrinsic::( + args, + dest, + rustc_apfloat::Round::NearestTiesToEven, + )?, + // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), } @@ -900,4 +997,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(x.abs(), dest)?; interp_ok(()) } + + fn float_round_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + mode: rustc_apfloat::Round, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let x: F = self.read_scalar(&args[0])?.to_float()?; + let res = x.round_to_integral(mode).value; + let res = self.adjust_nan(res, &[x]); + self.write_scalar(res, dest)?; + interp_ok(()) + } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f89baef76f09..bb3e870389c7 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2212,28 +2212,28 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// [`f16::floor`](../../std/primitive.f16.html#method.floor) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn floorf16(x: f16) -> f16; +pub const unsafe fn floorf16(x: f16) -> f16; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn floorf32(x: f32) -> f32; +pub const unsafe fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn floorf64(x: f64) -> f64; +pub const unsafe fn floorf64(x: f64) -> f64; /// Returns the largest integer less than or equal to an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::floor`](../../std/primitive.f128.html#method.floor) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn floorf128(x: f128) -> f128; +pub const unsafe fn floorf128(x: f128) -> f128; /// Returns the smallest integer greater than or equal to an `f16`. /// @@ -2241,28 +2241,28 @@ pub unsafe fn floorf128(x: f128) -> f128; /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn ceilf16(x: f16) -> f16; +pub const unsafe fn ceilf16(x: f16) -> f16; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn ceilf32(x: f32) -> f32; +pub const unsafe fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn ceilf64(x: f64) -> f64; +pub const unsafe fn ceilf64(x: f64) -> f64; /// Returns the smallest integer greater than or equal to an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn ceilf128(x: f128) -> f128; +pub const unsafe fn ceilf128(x: f128) -> f128; /// Returns the integer part of an `f16`. /// @@ -2270,28 +2270,28 @@ pub unsafe fn ceilf128(x: f128) -> f128; /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn truncf16(x: f16) -> f16; +pub const unsafe fn truncf16(x: f16) -> f16; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn truncf32(x: f32) -> f32; +pub const unsafe fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn truncf64(x: f64) -> f64; +pub const unsafe fn truncf64(x: f64) -> f64; /// Returns the integer part of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn truncf128(x: f128) -> f128; +pub const unsafe fn truncf128(x: f128) -> f128; /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number with an even /// least significant digit. @@ -2300,7 +2300,7 @@ pub unsafe fn truncf128(x: f128) -> f128; /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -pub fn round_ties_even_f16(x: f16) -> f16; +pub const fn round_ties_even_f16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number with an even /// least significant digit. @@ -2309,7 +2309,7 @@ pub fn round_ties_even_f16(x: f16) -> f16; /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -pub fn round_ties_even_f32(x: f32) -> f32; +pub const fn round_ties_even_f32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number with an even /// least significant digit. @@ -2318,7 +2318,7 @@ pub fn round_ties_even_f32(x: f32) -> f32; /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -pub fn round_ties_even_f64(x: f64) -> f64; +pub const fn round_ties_even_f64(x: f64) -> f64; /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number with an even /// least significant digit. @@ -2327,7 +2327,7 @@ pub fn round_ties_even_f64(x: f64) -> f64; /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) #[rustc_intrinsic] #[rustc_nounwind] -pub fn round_ties_even_f128(x: f128) -> f128; +pub const fn round_ties_even_f128(x: f128) -> f128; /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. /// @@ -2335,28 +2335,28 @@ pub fn round_ties_even_f128(x: f128) -> f128; /// [`f16::round`](../../std/primitive.f16.html#method.round) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn roundf16(x: f16) -> f16; +pub const unsafe fn roundf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn roundf32(x: f32) -> f32; +pub const unsafe fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn roundf64(x: f64) -> f64; +pub const unsafe fn roundf64(x: f64) -> f64; /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f128::round`](../../std/primitive.f128.html#method.round) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn roundf128(x: f128) -> f128; +pub const unsafe fn roundf128(x: f128) -> f128; /// Float addition that allows optimizations based on algebraic rules. /// May assume inputs are finite. diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 0c2c4155d66c..6b9b2ba86891 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1447,8 +1447,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f128 { + pub const fn floor(self) -> f128 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::floorf128(self) } } @@ -1477,8 +1479,10 @@ impl f128 { #[doc(alias = "ceiling")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f128 { + pub const fn ceil(self) -> f128 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf128(self) } } @@ -1513,8 +1517,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f128 { + pub const fn round(self) -> f128 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf128(self) } } @@ -1547,8 +1553,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f128 { + pub const fn round_ties_even(self) -> f128 { intrinsics::round_ties_even_f128(self) } @@ -1579,8 +1587,10 @@ impl f128 { #[doc(alias = "truncate")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f128 { + pub const fn trunc(self) -> f128 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf128(self) } } @@ -1610,8 +1620,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f128 { + pub const fn fract(self) -> f128 { self - self.trunc() } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 1a859f2277ff..eb7af993c60a 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1423,8 +1423,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f16 { + pub const fn floor(self) -> f16 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::floorf16(self) } } @@ -1453,8 +1455,10 @@ impl f16 { #[doc(alias = "ceiling")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f16 { + pub const fn ceil(self) -> f16 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf16(self) } } @@ -1489,8 +1493,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f16 { + pub const fn round(self) -> f16 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf16(self) } } @@ -1523,8 +1529,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f16 { + pub const fn round_ties_even(self) -> f16 { intrinsics::round_ties_even_f16(self) } @@ -1555,8 +1563,10 @@ impl f16 { #[doc(alias = "truncate")] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f16 { + pub const fn trunc(self) -> f16 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf16(self) } } @@ -1586,8 +1596,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f16 { + pub const fn fract(self) -> f16 { self - self.trunc() } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 6636054a659b..bf923d4070ad 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1591,8 +1591,9 @@ pub mod math { /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(x: f32) -> f32 { + pub const fn floor(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::floorf32(x) } } @@ -1621,7 +1622,8 @@ pub mod math { #[doc(alias = "ceiling")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - pub fn ceil(x: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + pub const fn ceil(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf32(x) } } @@ -1655,7 +1657,8 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(x: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + pub const fn round(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf32(x) } } @@ -1688,7 +1691,8 @@ pub mod math { #[inline] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(x: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + pub const fn round_ties_even(x: f32) -> f32 { intrinsics::round_ties_even_f32(x) } @@ -1718,7 +1722,8 @@ pub mod math { #[doc(alias = "truncate")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - pub fn trunc(x: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] + pub const fn trunc(x: f32) -> f32 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf32(x) } } @@ -1747,8 +1752,9 @@ pub mod math { /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(x: f32) -> f32 { + pub const fn fract(x: f32) -> f32 { x - trunc(x) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 8fbf2cffbaf4..0a63ed828aed 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1589,8 +1589,9 @@ pub mod math { /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(x: f64) -> f64 { + pub const fn floor(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::floorf64(x) } } @@ -1618,8 +1619,9 @@ pub mod math { #[inline] #[doc(alias = "ceiling")] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(x: f64) -> f64 { + pub const fn ceil(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::ceilf64(x) } } @@ -1652,8 +1654,9 @@ pub mod math { /// [`f64::round`]: ../../../std/primitive.f64.html#method.round #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(x: f64) -> f64 { + pub const fn round(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::roundf64(x) } } @@ -1685,8 +1688,9 @@ pub mod math { /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(x: f64) -> f64 { + pub const fn round_ties_even(x: f64) -> f64 { intrinsics::round_ties_even_f64(x) } @@ -1715,8 +1719,9 @@ pub mod math { #[inline] #[doc(alias = "truncate")] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(x: f64) -> f64 { + pub const fn trunc(x: f64) -> f64 { // SAFETY: intrinsic with no preconditions unsafe { intrinsics::truncf64(x) } } @@ -1745,8 +1750,9 @@ pub mod math { /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract #[inline] #[unstable(feature = "core_float_math", issue = "137578")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(x: f64) -> f64 { + pub const fn fract(x: f64) -> f64 { x - trunc(x) } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 693b14ef7620..dd7cdd79c0d6 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -16,6 +16,7 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] +#![feature(const_float_round_methods)] #![feature(const_trait_impl)] #![feature(core_float_math)] #![feature(core_intrinsics)] diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 1212d36a1b15..fa05bbdd9b77 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -731,6 +731,9 @@ assume_usize_width! { } } +// FIXME(141726): there is a lot of duplication between the following tests and +// the tests in `coretests/tests/floats/f*.rs` +// See issue https://github.com/rust-lang/rust/issues/141726 for more details. macro_rules! test_float { ($modname: ident, $fassert: ident, $fty: ty) => { mod $modname { @@ -947,6 +950,117 @@ macro_rules! test_float { assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); } + #[test] + #[cfg(not(bootstrap))] + fn floor() { + $fassert!((0.0 as $fty).floor(), 0.0); + $fassert!((0.0 as $fty).floor().is_sign_positive()); + $fassert!((-0.0 as $fty).floor(), -0.0); + $fassert!((-0.0 as $fty).floor().is_sign_negative()); + $fassert!((0.5 as $fty).floor(), 0.0); + $fassert!((-0.5 as $fty).floor(), -1.0); + $fassert!((1.5 as $fty).floor(), 1.0); + $fassert!(<$fty>::MAX.floor(), <$fty>::MAX); + $fassert!(<$fty>::MIN.floor(), <$fty>::MIN); + $fassert!(<$fty>::MIN_POSITIVE.floor(), 0.0); + $fassert!((-<$fty>::MIN_POSITIVE).floor(), -1.0); + $fassert!(<$fty>::NAN.floor().is_nan()); + $fassert!(<$fty>::INFINITY.floor(), <$fty>::INFINITY); + $fassert!(<$fty>::NEG_INFINITY.floor(), <$fty>::NEG_INFINITY); + } + #[test] + #[cfg(not(bootstrap))] + fn ceil() { + $fassert!((0.0 as $fty).ceil(), 0.0); + $fassert!((0.0 as $fty).ceil().is_sign_positive()); + $fassert!((-0.0 as $fty).ceil(), 0.0); + $fassert!((-0.0 as $fty).ceil().is_sign_negative()); + $fassert!((0.5 as $fty).ceil(), 1.0); + $fassert!((-0.5 as $fty).ceil(), 0.0); + $fassert!(<$fty>::MAX.ceil(), <$fty>::MAX); + $fassert!(<$fty>::MIN.ceil(), <$fty>::MIN); + $fassert!(<$fty>::MIN_POSITIVE.ceil(), 1.0); + $fassert!((-<$fty>::MIN_POSITIVE).ceil(), 0.0); + $fassert!(<$fty>::NAN.ceil().is_nan()); + $fassert!(<$fty>::INFINITY.ceil(), <$fty>::INFINITY); + $fassert!(<$fty>::NEG_INFINITY.ceil(), <$fty>::NEG_INFINITY); + } + #[test] + #[cfg(not(bootstrap))] + fn round() { + $fassert!((0.0 as $fty).round(), 0.0); + $fassert!((0.0 as $fty).round().is_sign_positive()); + $fassert!((-0.0 as $fty).round(), -0.0); + $fassert!((-0.0 as $fty).round().is_sign_negative()); + $fassert!((0.5 as $fty).round(), 1.0); + $fassert!((-0.5 as $fty).round(), -1.0); + $fassert!(<$fty>::MAX.round(), <$fty>::MAX); + $fassert!(<$fty>::MIN.round(), <$fty>::MIN); + $fassert!(<$fty>::MIN_POSITIVE.round(), 0.0); + $fassert!((-<$fty>::MIN_POSITIVE).round(), 0.0); + $fassert!(<$fty>::NAN.round().is_nan()); + $fassert!(<$fty>::INFINITY.round(), <$fty>::INFINITY); + $fassert!(<$fty>::NEG_INFINITY.round(), <$fty>::NEG_INFINITY); + } + #[test] + #[cfg(not(bootstrap))] + fn round_ties_even() { + $fassert!((0.0 as $fty).round_ties_even(), 0.0); + $fassert!((0.0 as $fty).round_ties_even().is_sign_positive()); + $fassert!((-0.0 as $fty).round_ties_even(), -0.0); + $fassert!((-0.0 as $fty).round_ties_even().is_sign_negative()); + $fassert!((0.5 as $fty).round_ties_even(), 0.0); + $fassert!((0.5 as $fty).round_ties_even().is_sign_positive()); + $fassert!((-0.5 as $fty).round_ties_even(), -0.0); + $fassert!((-0.5 as $fty).round_ties_even().is_sign_negative()); + $fassert!(<$fty>::MAX.round_ties_even(), <$fty>::MAX); + $fassert!(<$fty>::MIN.round_ties_even(), <$fty>::MIN); + $fassert!(<$fty>::MIN_POSITIVE.round_ties_even(), 0.0); + $fassert!((-<$fty>::MIN_POSITIVE).round_ties_even(), 0.0); + $fassert!(<$fty>::NAN.round_ties_even().is_nan()); + $fassert!(<$fty>::INFINITY.round_ties_even(), <$fty>::INFINITY); + $fassert!(<$fty>::NEG_INFINITY.round_ties_even(), <$fty>::NEG_INFINITY); + } + #[test] + #[cfg(not(bootstrap))] + fn trunc() { + $fassert!((0.0 as $fty).trunc(), 0.0); + $fassert!((0.0 as $fty).trunc().is_sign_positive()); + $fassert!((-0.0 as $fty).trunc(), -0.0); + $fassert!((-0.0 as $fty).trunc().is_sign_negative()); + $fassert!((0.5 as $fty).trunc(), 0.0); + $fassert!((0.5 as $fty).trunc().is_sign_positive()); + $fassert!((-0.5 as $fty).trunc(), -0.0); + $fassert!((-0.5 as $fty).trunc().is_sign_negative()); + $fassert!(<$fty>::MAX.trunc(), <$fty>::MAX); + $fassert!(<$fty>::MIN.trunc(), <$fty>::MIN); + $fassert!(<$fty>::MIN_POSITIVE.trunc(), 0.0); + $fassert!((-<$fty>::MIN_POSITIVE).trunc(), 0.0); + $fassert!(<$fty>::NAN.trunc().is_nan()); + $fassert!(<$fty>::INFINITY.trunc(), <$fty>::INFINITY); + $fassert!(<$fty>::NEG_INFINITY.trunc(), <$fty>::NEG_INFINITY); + } + #[test] + #[cfg(not(bootstrap))] + fn fract() { + $fassert!((0.0 as $fty).fract(), 0.0); + $fassert!((0.0 as $fty).fract().is_sign_positive()); + $fassert!((-0.0 as $fty).fract(), 0.0); + $fassert!((-0.0 as $fty).fract().is_sign_positive()); + $fassert!((0.5 as $fty).fract(), 0.5); + $fassert!((0.5 as $fty).fract().is_sign_positive()); + $fassert!((-0.5 as $fty).fract(), -0.5); + $fassert!((-0.5 as $fty).fract().is_sign_negative()); + $fassert!(<$fty>::MAX.fract(), 0.0); + $fassert!(<$fty>::MIN.fract(), 0.0); + $fassert!(<$fty>::MIN_POSITIVE.fract(), <$fty>::MIN_POSITIVE); + $fassert!(<$fty>::MIN_POSITIVE.fract().is_sign_positive()); + $fassert!((-<$fty>::MIN_POSITIVE).fract(), -<$fty>::MIN_POSITIVE); + $fassert!((-<$fty>::MIN_POSITIVE).fract().is_sign_negative()); + $fassert!(<$fty>::NAN.fract().is_nan()); + $fassert!(<$fty>::INFINITY.fract().is_nan()); + $fassert!(<$fty>::NEG_INFINITY.fract().is_nan()); + } } }; } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a3f0f3cc55a1..74a343398602 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -335,6 +335,7 @@ #![feature(bstr_internals)] #![feature(char_internals)] #![feature(clone_to_uninit)] +#![feature(const_float_round_methods)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(duration_constants)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 5210e75ec453..b7f6529ac402 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -44,8 +44,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn floor(self) -> f32 { + pub const fn floor(self) -> f32 { core::f32::math::floor(self) } @@ -66,8 +67,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn ceil(self) -> f32 { + pub const fn ceil(self) -> f32 { core::f32::math::ceil(self) } @@ -94,8 +96,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn round(self) -> f32 { + pub const fn round(self) -> f32 { core::f32::math::round(self) } @@ -120,8 +123,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn round_ties_even(self) -> f32 { + pub const fn round_ties_even(self) -> f32 { core::f32::math::round_ties_even(self) } @@ -145,8 +149,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn trunc(self) -> f32 { + pub const fn trunc(self) -> f32 { core::f32::math::trunc(self) } @@ -168,8 +173,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn fract(self) -> f32 { + pub const fn fract(self) -> f32 { core::f32::math::fract(self) } diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index f837800d6634..75e35a8db335 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -44,8 +44,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn floor(self) -> f64 { + pub const fn floor(self) -> f64 { core::f64::math::floor(self) } @@ -66,8 +67,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn ceil(self) -> f64 { + pub const fn ceil(self) -> f64 { core::f64::math::ceil(self) } @@ -94,8 +96,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn round(self) -> f64 { + pub const fn round(self) -> f64 { core::f64::math::round(self) } @@ -120,8 +123,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "round_ties_even", since = "1.77.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn round_ties_even(self) -> f64 { + pub const fn round_ties_even(self) -> f64 { core::f64::math::round_ties_even(self) } @@ -145,8 +149,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn trunc(self) -> f64 { + pub const fn trunc(self) -> f64 { core::f64::math::trunc(self) } @@ -168,8 +173,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")] #[inline] - pub fn fract(self) -> f64 { + pub const fn fract(self) -> f64 { core::f64::math::fract(self) } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 581005bc9a1e..a4882a201481 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -159,67 +159,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } - "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "round_ties_even_f16" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f16()?; - let mode = match intrinsic_name { - "floorf16" => Round::TowardNegative, - "ceilf16" => Round::TowardPositive, - "truncf16" => Round::TowardZero, - "roundf16" => Round::NearestTiesToAway, - "round_ties_even_f16" => Round::NearestTiesToEven, - _ => bug!(), - }; - let res = f.round_to_integral(mode).value; - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "round_ties_even_f32" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - let mode = match intrinsic_name { - "floorf32" => Round::TowardNegative, - "ceilf32" => Round::TowardPositive, - "truncf32" => Round::TowardZero, - "roundf32" => Round::NearestTiesToAway, - "round_ties_even_f32" => Round::NearestTiesToEven, - _ => bug!(), - }; - let res = f.round_to_integral(mode).value; - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "round_ties_even_f64" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - let mode = match intrinsic_name { - "floorf64" => Round::TowardNegative, - "ceilf64" => Round::TowardPositive, - "truncf64" => Round::TowardZero, - "roundf64" => Round::NearestTiesToAway, - "round_ties_even_f64" => Round::NearestTiesToEven, - _ => bug!(), - }; - let res = f.round_to_integral(mode).value; - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "round_ties_even_f128" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f128()?; - let mode = match intrinsic_name { - "floorf128" => Round::TowardNegative, - "ceilf128" => Round::TowardPositive, - "truncf128" => Round::TowardZero, - "roundf128" => Round::NearestTiesToAway, - "round_ties_even_f128" => Round::NearestTiesToEven, - _ => bug!(), - }; - let res = f.round_to_integral(mode).value; - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "sqrtf32" => { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; From 7f7c415d03e6ec431a65a6f5625026761ab9f913 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 1 May 2025 18:23:07 -0700 Subject: [PATCH 34/34] library: explain TOCTOU races in `fs::remove_dir_all` In the previous description it said there was a TOCTOU race but did not explain exactly what the problem was. I sat down with the CVE, reviewed its text, and created this explanation. This context should hopefully help people understand the actual risk as-such. Incidentally, it also fixes the capitalization on the name of Redox OS. --- library/std/src/fs.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 8ed5800e9d06..711efc7d011c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2915,17 +2915,28 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// # Platform-specific behavior /// -/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions -/// on Unix (except for REDOX) and the `CreateFileW`, `GetFileInformationByHandleEx`, -/// `SetFileInformationByHandle`, and `NtCreateFile` functions on Windows. Note that, this -/// [may change in the future][changes]. +/// These implementation details [may change in the future][changes]. +/// +/// - "Unix-like": By default, this function currently corresponds to +/// `openat`, `fdopendir`, `unlinkat` and `lstat` +/// on Unix-family platforms, except where noted otherwise. +/// - "Windows": This function currently corresponds to `CreateFileW`, +/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. +/// +/// ## Time-of-check to time-of-use (TOCTOU) race conditions +/// On a few platforms there is no way to remove a directory's contents without following symlinks +/// unless you perform a check and then operate on paths based on that directory. +/// This allows concurrently-running code to replace the directory with a symlink after the check, +/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race. +/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms +/// except the following. It should not be used in security-sensitive contexts on these platforms: +/// - Miri: Even when emulating targets where the underlying implementation will protect against +/// TOCTOU races, Miri will not do so. +/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement +/// the required platform support to do so. /// /// [changes]: io#platform-specific-behavior /// -/// On REDOX, as well as when running in Miri for any target, this function is not protected against -/// time-of-check to time-of-use (TOCTOU) race conditions, and should not be used in -/// security-sensitive code on those platforms. All other platforms are protected. -/// /// # Errors /// /// See [`fs::remove_file`] and [`fs::remove_dir`].