From 364f9fd74c19303511868616ef7f7b64643c3e3d Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Fri, 7 Aug 2026 20:29:47 -0700 Subject: [PATCH 1/7] fix borrowck not considering sibling index and constantindex projections to be overlapping in some cases --- .../rustc_borrowck/src/diagnostics/mod.rs | 4 +- .../src/diagnostics/move_errors.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 47 +++++++++---------- .../src/polonius/legacy/accesses.rs | 2 +- .../src/drop_flag_effects.rs | 4 +- .../rustc_mir_dataflow/src/move_paths/mod.rs | 25 ++++++---- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 2 +- .../src/elaborate_drops.rs | 8 ++-- .../src/lint_tail_expr_drop_order.rs | 2 +- .../ui/borrowck/index-after-constantindex.rs | 8 ++++ .../borrowck/index-after-constantindex.stderr | 18 +++++++ 11 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 tests/ui/borrowck/index-after-constantindex.rs create mode 100644 tests/ui/borrowck/index-after-constantindex.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index bde2529d855cf..6a2cbf507bad2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -557,7 +557,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // we'll use this to check whether it was originally from an overloaded // operator. match self.move_data.rev_lookup.find(deref_base) { - LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => { + LookupResult::Exact(mpi) | LookupResult::Parent { mpi, .. } => { debug!("borrowed_content_source: mpi={:?}", mpi); for i in &self.move_data.init_path_map[mpi] { @@ -594,7 +594,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } } // Base is a `static` so won't be from an overloaded operator - _ => (), + LookupResult::None => (), }; // If we didn't find an overloaded deref or index, then assume it's a diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 9fac00016eac2..b70b4aa1fc4a1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -189,7 +189,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { match self.move_data.rev_lookup.find(match_place.as_ref()) { // Error with the match place - LookupResult::Parent(_) => { + LookupResult::Parent { .. } | LookupResult::None => { for ge in &mut *grouped_errors { if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge && match_span == *span @@ -219,7 +219,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } // Error with the pattern LookupResult::Exact(_) => { - let LookupResult::Parent(Some(mpi)) = + let LookupResult::Parent { mpi, .. } = self.move_data.rev_lookup.find(move_from.as_ref()) else { // move_from should be a projection from match_place. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d990d72e3fb42..6001a99a918e9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2072,15 +2072,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // This code covers scenarios 1, 2, and 3. debug!("check_if_full_path_is_moved place: {:?}", place_span.0); - let (prefix, mpi) = self.move_path_closest_to(place_span.0); - if maybe_uninits.contains(mpi) { + + let uninit_mpi = match self.move_data.rev_lookup.find(place_span.0) { + // Index projections arbitrarily overlap sibling move paths, so we need to check all descendents of the parent + // Subslice and ConstantIndex projections of slices also overlap siblings, + // but the parent slice will never have a move path + // Subslice projections of arrays are specifically checked in `check_if_subslice_element_is_moved` + LookupResult::Parent { mpi, next_elem: PlaceElem::Index(..) } => self + .move_data + .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)), + + LookupResult::Exact(mpi) | LookupResult::Parent { mpi, next_elem: _ } => { + maybe_uninits.contains(mpi).then_some(mpi) + } + + LookupResult::None => bug!("should have move path for every Local"), + }; + + if let Some(mpi) = uninit_mpi { self.report_use_of_moved_or_uninitialized( location, desired_action, - (prefix, place_span.0, place_span.1), + (self.move_data.move_paths[mpi].place.as_ref(), place_span.0, place_span.1), mpi, ); - } // Only query longest prefix with a MovePath, not further + } + + // Only query longest prefix with a MovePath, not further // ancestors; dataflow recurs on children when parents // move (to support partial (re)inits). // @@ -2202,32 +2220,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - /// Currently MoveData does not store entries for all places in - /// the input MIR. For example it will currently filter out - /// places that are Copy; thus we do not track places of shared - /// reference type. This routine will walk up a place along its - /// prefixes, searching for a foundational place that *is* - /// tracked in the MoveData. - /// - /// An Err result includes a tag indicated why the search failed. - /// Currently this can only occur if the place is built off of a - /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) { - match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { - (self.move_data.move_paths[mpi].place.as_ref(), mpi) - } - LookupResult::Parent(None) => panic!("should have move path for every Local"), - } - } - fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option { // If returns None, then there is no move path corresponding // to a direct owner of `place` (which means there is nothing // that borrowck tracks for its analysis). match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(_) => None, + LookupResult::Parent { .. } | LookupResult::None => None, LookupResult::Exact(mpi) => Some(mpi), } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index dc174775af2e5..49858232b3563 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { match context { PlaceContext::NonMutatingUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) = + let (LookupResult::Exact(path) | LookupResult::Parent { mpi: path, .. }) = self.move_data.rev_lookup.find(place.as_ref()) else { // There's no path access to emit. diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs index b6fc1219a8503..bfebc552ceed9 100644 --- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs +++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs @@ -49,13 +49,13 @@ where pub fn on_lookup_result_bits<'tcx, F>( move_data: &MoveData<'tcx>, - lookup_result: LookupResult, + lookup_result: LookupResult<'tcx>, each_child: F, ) where F: FnMut(MovePathIndex), { match lookup_result { - LookupResult::Parent(..) => { + LookupResult::Parent { .. } | LookupResult::None => { // access to untracked value - do not touch children } LookupResult::Exact(e) => on_all_children_bits(move_data, e, each_child), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 83d40a5a2f284..a9b444e18c75e 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -340,15 +340,22 @@ pub struct MovePathLookup<'tcx> { mod builder; #[derive(Copy, Clone, Debug)] -pub enum LookupResult { +pub enum LookupResult<'tcx> { /// This exact thing has a move path. E.g. we looked up `x` or `x.m` and it has been moved. Exact(MovePathIndex), - /// - If the field is `None`, neither the exact thing nor any ancestor of it has a move path. - /// E.g. we looked up `x.m` and neither it nor `x` have a move path. - /// - If the field is `Some`, the exact thing has no move path, but an ancestor does. E.g. we - /// looked up `x.m` which has no move path but `x` has one. Not possible for locals. - Parent(Option), + /// The exact thing has no move path, but an ancestor does. + /// E.g. we looked up `x.m` which has no move path but `x` has one. Not possible for locals. + Parent { + mpi: MovePathIndex, + + /// The PlaceElem in the place immediately projecting from the parent move path. + next_elem: PlaceElem<'tcx>, + }, + + /// Neither the exact thing nor any ancestor of it has a move path. + /// E.g. we looked up `x.m` and neither it nor `x` have a move path. + None, } impl<'tcx> MovePathLookup<'tcx> { @@ -356,10 +363,10 @@ impl<'tcx> MovePathLookup<'tcx> { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult { + pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult<'tcx> { // Look first in the locals (roots). let Some(mut result) = self.find_local(place.local) else { - return LookupResult::Parent(None); + return LookupResult::None; }; // Look for a projection through the found local. @@ -372,7 +379,7 @@ impl<'tcx> MovePathLookup<'tcx> { }; let Some(&subpath) = subpath else { - return LookupResult::Parent(Some(result)); + return LookupResult::Parent { mpi: result, next_elem: elem }; }; result = subpath; } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 35c601f09acd4..9f6ae5013d18a 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -224,7 +224,7 @@ where } } - LookupResult::Parent(..) => { + LookupResult::Parent { .. } | LookupResult::None => { tcx.dcx().emit_err(PeekArgumentUntracked { span: call.span }); } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 84c9c044ae6a6..8133274604182 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -314,8 +314,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { } }); } - LookupResult::Parent(None) => {} - LookupResult::Parent(Some(parent)) => { + LookupResult::None => {} + LookupResult::Parent { mpi: parent, .. } => { if self.body.local_decls[place.local].is_deref_temp() { continue; } @@ -387,8 +387,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { drop, ) } - LookupResult::Parent(None) => {} - LookupResult::Parent(Some(_)) => { + LookupResult::None => {} + LookupResult::Parent { .. } => { if !replace { self.tcx.dcx().span_bug( terminator.source_info.span, diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index fe09594d7c5f3..330855d66da5f 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -76,7 +76,7 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { } MovePathIndexAtBlock::Unknown => { if let TerminatorKind::Drop { place, .. } = &terminator.kind - && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) = + && let LookupResult::Exact(idx) | LookupResult::Parent { mpi: idx, .. } = self.move_data.rev_lookup.find(place.as_ref()) { // Since we are working with MIRs at a very early stage, observing a `drop` diff --git a/tests/ui/borrowck/index-after-constantindex.rs b/tests/ui/borrowck/index-after-constantindex.rs new file mode 100644 index 0000000000000..5d78db4e411f5 --- /dev/null +++ b/tests/ui/borrowck/index-after-constantindex.rs @@ -0,0 +1,8 @@ +// test that an Index projection fails after a sibling ConstantIndex projection is moved out of +// regression test for #160525 + +fn main() { + let mut arr = [[Box::new(42)]]; + let alias = &mut arr[0][{ let [row] = arr; drop(row); 0 }]; //~ ERROR + println!("{}", **alias); // use-after-free of arr's dead stack slot +} diff --git a/tests/ui/borrowck/index-after-constantindex.stderr b/tests/ui/borrowck/index-after-constantindex.stderr new file mode 100644 index 0000000000000..d31a57df20a01 --- /dev/null +++ b/tests/ui/borrowck/index-after-constantindex.stderr @@ -0,0 +1,18 @@ +error[E0382]: borrow of moved value: `arr[..]` + --> $DIR/index-after-constantindex.rs:6:17 + | +LL | let alias = &mut arr[0][{ let [row] = arr; drop(row); 0 }]; + | ^^^^^^^^^^^^^^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | value moved here + | value borrowed here after move + | + = note: move occurs because `arr[..]` has type `[Box; 1]`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let alias = &mut arr[0][{ let [ref row] = arr; drop(row); 0 }]; + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. From e2ab0373fa07a4f6b82893767f9a23849d3d31f8 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:06:55 -0700 Subject: [PATCH 2/7] use ProjectionKind instead of PlaceElem for LookupResult and match exhaustively on it --- compiler/rustc_borrowck/src/lib.rs | 17 +++++++++++++---- .../rustc_mir_dataflow/src/drop_flag_effects.rs | 2 +- .../rustc_mir_dataflow/src/move_paths/mod.rs | 10 +++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 6001a99a918e9..bb9e42db5c3ca 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2078,13 +2078,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Subslice and ConstantIndex projections of slices also overlap siblings, // but the parent slice will never have a move path // Subslice projections of arrays are specifically checked in `check_if_subslice_element_is_moved` - LookupResult::Parent { mpi, next_elem: PlaceElem::Index(..) } => self + LookupResult::Parent { mpi, next_elem: ProjectionKind::Index(..) } => self .move_data .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)), - LookupResult::Exact(mpi) | LookupResult::Parent { mpi, next_elem: _ } => { - maybe_uninits.contains(mpi).then_some(mpi) - } + LookupResult::Exact(mpi) + | LookupResult::Parent { + mpi, + next_elem: + ProjectionKind::Deref + | ProjectionKind::Field(..) + | ProjectionKind::ConstantIndex { .. } + | ProjectionKind::Subslice { .. } + | ProjectionKind::Downcast(..) + | ProjectionKind::OpaqueCast(..) + | ProjectionKind::UnwrapUnsafeBinder(..), + } => maybe_uninits.contains(mpi).then_some(mpi), LookupResult::None => bug!("should have move path for every Local"), }; diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs index bfebc552ceed9..f4768e6f2569f 100644 --- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs +++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs @@ -49,7 +49,7 @@ where pub fn on_lookup_result_bits<'tcx, F>( move_data: &MoveData<'tcx>, - lookup_result: LookupResult<'tcx>, + lookup_result: LookupResult, each_child: F, ) where F: FnMut(MovePathIndex), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index a9b444e18c75e..c26fd8564e526 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -340,7 +340,7 @@ pub struct MovePathLookup<'tcx> { mod builder; #[derive(Copy, Clone, Debug)] -pub enum LookupResult<'tcx> { +pub enum LookupResult { /// This exact thing has a move path. E.g. we looked up `x` or `x.m` and it has been moved. Exact(MovePathIndex), @@ -349,8 +349,8 @@ pub enum LookupResult<'tcx> { Parent { mpi: MovePathIndex, - /// The PlaceElem in the place immediately projecting from the parent move path. - next_elem: PlaceElem<'tcx>, + /// The projection in the place immediately projecting from the parent move path. + next_elem: ProjectionKind, }, /// Neither the exact thing nor any ancestor of it has a move path. @@ -363,7 +363,7 @@ impl<'tcx> MovePathLookup<'tcx> { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult<'tcx> { + pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult { // Look first in the locals (roots). let Some(mut result) = self.find_local(place.local) else { return LookupResult::None; @@ -379,7 +379,7 @@ impl<'tcx> MovePathLookup<'tcx> { }; let Some(&subpath) = subpath else { - return LookupResult::Parent { mpi: result, next_elem: elem }; + return LookupResult::Parent { mpi: result, next_elem: elem.kind() }; }; result = subpath; } From 9acb7866d472c7055eabef228ce961c821251719 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 21 Sep 2026 10:16:30 -0400 Subject: [PATCH 3/7] rustc_codegen_llvm: catch up with LLVM 24 on wasm exceptions LLVM 24 removed the -wasm-enable-eh option in favor of relying on TargetMachine.Options.ExceptionModel == Wasm. We were already setting ExceptionModel to Wasm on LLVM 24 in PassWrapper.cpp for wasm targets so this is a no-op on LLVM 24. Further, we already implied the -wasm-enable-eh flag on LLVM 23, so the explicit pass in wasm-exceptions-nostd was redundant and can be safely dropped. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- tests/run-make/wasm-exceptions-nostd/rmake.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 718a500a9abec..e9d660b42bd9f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -127,7 +127,7 @@ unsafe fn configure_llvm(sess: &EarlySession) { } } - if wants_wasm_eh(&sess.target) { + if get_version() < (24, 0, 0) && wants_wasm_eh(&sess.target) { add("-wasm-enable-eh", false); } diff --git a/tests/run-make/wasm-exceptions-nostd/rmake.rs b/tests/run-make/wasm-exceptions-nostd/rmake.rs index e43d6bcd02b80..87eb5d501da44 100644 --- a/tests/run-make/wasm-exceptions-nostd/rmake.rs +++ b/tests/run-make/wasm-exceptions-nostd/rmake.rs @@ -10,7 +10,6 @@ fn main() { .input(Path::new("src").join("lib.rs")) .target("wasm32-unknown-unknown") .panic("unwind") - .arg("-Cllvm-args=-wasm-enable-eh") .arg("-Ctarget-feature=+exception-handling") .run(); From e0b4fd01c723c594f02026981e9d6634cf801a27 Mon Sep 17 00:00:00 2001 From: gmes23 Date: Thu, 24 Sep 2026 13:55:01 -0400 Subject: [PATCH 4/7] Fix provisional cache cleanup after trait evaluation failure --- .../rustc_trait_selection/src/traits/select/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cf8672814ff70..99016d37e49c9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -3082,16 +3082,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// Invoked when the node with dfn `dfn` does not get a successful /// result. This will clear out any provisional cache entries - /// that were added since `dfn` was created. This is because the - /// provisional entries are things which must assume that the - /// things on the stack at the time of their creation succeeded -- - /// since the failing node is presently at the top of the stack, - /// these provisional entries must either depend on it or some - /// ancestor of it. + /// originating from nodes visited before this node (`from_dfn < dfn`). + /// This is because the provisional entries are things which must + /// assume that the things on the stack at the time of their creation + /// succeeded -- since the failing node is presently at the top of + /// the stack, these provisional entries must either depend on it or + /// some ancestor of it. fn on_failure(&self, dfn: usize) { debug!(?dfn, "on_failure"); self.map.borrow_mut().retain(|key, eval| { - if !eval.from_dfn >= dfn { + if eval.from_dfn < dfn { debug!("on_failure: removing {:?}", key); false } else { From c01bd38bc07f4212de7f7781011bc24d510383af Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 9 Sep 2026 12:28:44 -0400 Subject: [PATCH 5/7] tests: accept more efficient simd output from LLVM 24 A recent change caused LLVM to identify `vpmov*, vpblend*` type instructions and merges them into single `vblendv*` instructions. --- tests/assembly-llvm/simd-intrinsic-select.rs | 71 +++++++++++++------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/tests/assembly-llvm/simd-intrinsic-select.rs b/tests/assembly-llvm/simd-intrinsic-select.rs index ca942f82ba5a3..073372b9deb7a 100644 --- a/tests/assembly-llvm/simd-intrinsic-select.rs +++ b/tests/assembly-llvm/simd-intrinsic-select.rs @@ -1,11 +1,17 @@ +// ignore-tidy-file-linelength //@ add-minicore -//@ revisions: x86-avx2 x86-avx512 aarch64 +//@ revisions: x86-avx2 x86-avx-512-llvm23 x86-avx-512 aarch64 //@ [x86-avx2] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel //@ [x86-avx2] compile-flags: -C target-feature=+avx2 //@ [x86-avx2] needs-llvm-components: x86 -//@ [x86-avx512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel -//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq -//@ [x86-avx512] needs-llvm-components: x86 +//@ [x86-avx-512-llvm23] max-llvm-major-version: 23 +//@ [x86-avx-512-llvm23] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx-512-llvm23] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx-512-llvm23] needs-llvm-components: x86 +//@ [x86-avx-512] min-llvm-version: 24 +//@ [x86-avx-512] compile-flags: --target=x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@ [x86-avx-512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq +//@ [x86-avx-512] needs-llvm-components: x86 //@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu //@ [aarch64] needs-llvm-components: aarch64 //@ assembly-output: emit-asm @@ -34,9 +40,13 @@ pub unsafe extern "C" fn select_i8x16(mask: m8x16, a: i8x16, b: i8x16) -> i8x16 // x86-avx2-NOT: vpsllw // x86-avx2: vpblendvb xmm0, xmm2, xmm1, xmm0 // - // x86-avx512-NOT: vpsllw - // x86-avx512: vpmovb2m k1, xmm0 - // x86-avx512-NEXT: vpblendmb xmm0 {k1}, xmm2, xmm1 + // x86-avx-512-llvm23-NOT: vpsllw + // x86-avx-512-llvm23: vpmovb2m k1, xmm0 + // x86-avx-512-llvm23-NEXT: vpblendmb xmm0 {k1}, xmm2, xmm1 + // + // x86-avx-512-NOT: vpsllw + // x86-avx-512: vpmovb2m k1, xmm0 + // x86-avx-512-NEXT: vpblendmb xmm0 {k1}, xmm2, xmm1 // // aarch64-NOT: shl // aarch64: cmlt v0.16b, v0.16b, #0 @@ -50,9 +60,12 @@ pub unsafe extern "C" fn select_f32x4(mask: m32x4, a: f32x4, b: f32x4) -> f32x4 // x86-avx2-NOT: vpslld // x86-avx2: vblendvps xmm0, xmm2, xmm1, xmm0 // - // x86-avx512-NOT: vpslld - // x86-avx512: vpmovd2m k1, xmm0 - // x86-avx512-NEXT: vblendmps xmm0 {k1}, xmm2, xmm1 + // x86-avx-512-llvm23-NOT: vpslld + // x86-avx-512-llvm23: vpmovd2m k1, xmm0 + // x86-avx-512-llvm23-NEXT: vblendmps xmm0 {k1}, xmm2, xmm1 + // + // x86-avx-512-NOT: vpslld + // x86-avx-512: vblendvps xmm0, xmm2, xmm1, xmm0 // // aarch64-NOT: shl // aarch64: cmlt v0.4s, v0.4s, #0 @@ -66,9 +79,12 @@ pub unsafe extern "C" fn select_f64x2(mask: m64x2, a: f64x2, b: f64x2) -> f64x2 // x86-avx2-NOT: vpsllq // x86-avx2: vblendvpd xmm0, xmm2, xmm1, xmm0 // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, xmm0 - // x86-avx512-NEXT: vblendmpd xmm0 {k1}, xmm2, xmm1 + // x86-avx-512-llvm23-NOT: vpsllq + // x86-avx-512-llvm23: vpmovq2m k1, xmm0 + // x86-avx-512-llvm23-NEXT: vblendmpd xmm0 {k1}, xmm2, xmm1 + // + // x86-avx-512-NOT: vpsllq + // x86-avx-512: vblendvpd xmm0, xmm2, xmm1, xmm0 // // aarch64-NOT: shl // aarch64: cmlt v0.2d, v0.2d, #0 @@ -77,29 +93,38 @@ pub unsafe extern "C" fn select_f64x2(mask: m64x2, a: f64x2, b: f64x2) -> f64x2 } // x86-avx2-LABEL: select_f64x4 -// x86-avx512-LABEL: select_f64x4 +// x86-avx-512-llvm23-LABEL: select_f64x4 +// x86-avx-512-LABEL: select_f64x4 #[no_mangle] -#[cfg(any(x86_avx2, x86_avx512))] +#[cfg(any(x86_avx2, x86_avx_512, x86_avx_512_llvm23))] pub unsafe extern "C" fn select_f64x4(mask: m64x4, a: f64x4, b: f64x4) -> f64x4 { // The parameter is a 256 bit vector which in the C abi is only valid for avx targets. // // x86-avx2-NOT: vpsllq // x86-avx2: vblendvpd ymm0, ymm2, ymm1, ymm0 // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, ymm0 - // x86-avx512-NEXT: vblendmpd ymm0 {k1}, ymm2, ymm1 + // x86-avx-512-llvm23-NOT: vpsllq + // x86-avx-512-llvm23: vpmovq2m k1, ymm0 + // x86-avx-512-llvm23-NEXT: vblendmpd ymm0 {k1}, ymm2, ymm1 + // + // x86-avx-512-NOT: vpsllq + // x86-avx-512: vblendvpd ymm0, ymm2, ymm1, ymm0 simd_select(mask, a, b) } -// x86-avx512-LABEL: select_f64x8 +// x86-avx-512-llvm23-LABEL: select_f64x8 +// x86-avx-512-LABEL: select_f64x8 #[no_mangle] -#[cfg(x86_avx512)] +#[cfg(any(x86_avx_512, x86_avx_512_llvm23))] pub unsafe extern "C" fn select_f64x8(mask: m64x8, a: f64x8, b: f64x8) -> f64x8 { // The parameter is a 256 bit vector which in the C abi is only valid for avx512 targets. // - // x86-avx512-NOT: vpsllq - // x86-avx512: vpmovq2m k1, zmm0 - // x86-avx512-NEXT: vblendmpd zmm0 {k1}, zmm2, zmm1 + // x86-avx-512-llvm23-NOT: vpsllq + // x86-avx-512-llvm23: vpmovq2m k1, zmm0 + // x86-avx-512-llvm23-NEXT: vblendmpd zmm0 {k1}, zmm2, zmm1 + // + // x86-avx-512-NOT: vpsllq + // x86-avx-512: vpmovq2m k1, zmm0 + // x86-avx-512-NEXT: vblendmpd zmm0 {k1}, zmm2, zmm1 simd_select(mask, a, b) } From dbc472b15467e68cb138282a1b0af8b8cfc3f995 Mon Sep 17 00:00:00 2001 From: Roland Xu Date: Fri, 25 Sep 2026 13:15:25 +0800 Subject: [PATCH 6/7] Use get to avoid ICE on unresolved imports --- compiler/rustc_resolve/src/check_unused.rs | 2 +- .../ui/imports/unused-import-issue-163294.rs | 9 ++++++++ .../imports/unused-import-issue-163294.stderr | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/unused-import-issue-163294.rs create mode 100644 tests/ui/imports/unused-import-issue-163294.stderr diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index daa816c276482..aac244ad6cf22 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -136,7 +136,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { ast::UseTreeKind::Simple(Some(ident)) => { if ident.name == kw::Underscore && !matches!( - self.r.current_owner.import_res[&id].type_ns, + self.r.current_owner.import_res.get(&id).and_then(|res| res.type_ns), Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) ) { diff --git a/tests/ui/imports/unused-import-issue-163294.rs b/tests/ui/imports/unused-import-issue-163294.rs new file mode 100644 index 0000000000000..7793f1da760e2 --- /dev/null +++ b/tests/ui/imports/unused-import-issue-163294.rs @@ -0,0 +1,9 @@ +//@ edition: 2015 + +#![deny(unused_imports)] + +pub use core as _; +//~^ ERROR unresolved import `core` +//~^^ ERROR unused import: `core as _` + +fn main() {} diff --git a/tests/ui/imports/unused-import-issue-163294.stderr b/tests/ui/imports/unused-import-issue-163294.stderr new file mode 100644 index 0000000000000..ebb319562189a --- /dev/null +++ b/tests/ui/imports/unused-import-issue-163294.stderr @@ -0,0 +1,23 @@ +error[E0432]: unresolved import `core` + --> $DIR/unused-import-issue-163294.rs:5:9 + | +LL | pub use core as _; + | ----^^^^^ + | | + | no `core` in the root + +error: unused import: `core as _` + --> $DIR/unused-import-issue-163294.rs:5:9 + | +LL | pub use core as _; + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-import-issue-163294.rs:3:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. From 4b538231e35e6edbc13ed012dd788a8f432d73fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Sep 2026 09:32:43 +0200 Subject: [PATCH 7/7] ty::CoroutineClosure is more a closure than a coroutine --- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 01549c3e3fd53..243ad73e3dfb8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2190,7 +2190,7 @@ impl<'tcx> Ty<'tcx> { def.flags().contains(AdtFlags::IS_MAYBE_DANGLING) || def.flags().contains(AdtFlags::IS_MANUALLY_DROP) } - ty::Coroutine(..) | ty::CoroutineClosure(..) => true, + ty::Coroutine(..) => true, _ => false, } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 68a1b479830e2..35f8897afd4c4 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -259,7 +259,9 @@ pub enum TyKind { /// `ClosureArgs` for more details. Closure(I::ClosureId, I::GenericArgs), - /// The anonymous type of a closure. Used to represent the type of `async |a| a`. + /// The anonymous type of an async closure. Used to represent the type of `async |a| a`. + /// + /// This type itself is not a coroutine, it just represents a closure that returns one. /// /// Coroutine-closure args contain both the - potentially instantiated - generic /// parameters of its parent and some synthetic parameters. See the documentation