From f11bed910751f8c741879f8a5604f3a30912152c 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 01/16] 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 0e5ab5c00bd76..7e840163e958c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -560,7 +560,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] { @@ -597,7 +597,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 b10570db1cdd2..2839c913ed55f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2077,15 +2077,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). // @@ -2207,32 +2225,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 7d7491dd643b0..102586aaf8ed2 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 b6565588ae3f1..93dc6956605a6 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 eb6921e438528..a52c52d85f7a9 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 104f67c6914c87b41db9c4f869a9ad58618411fa 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 02/16] 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 2839c913ed55f..8672b7cb6b6fe 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2083,13 +2083,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 102586aaf8ed2..262992e817b35 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 93dc6956605a6..5c111d722a990 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 e10aa5ee9ed97070c851bbef6101ffdb984d225c Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 10 Aug 2026 22:08:40 -0700 Subject: [PATCH 03/16] respect borrow kind in `kill_borrows_on_place` --- compiler/rustc_borrowck/src/dataflow.rs | 12 ++++--- ...nt-kill-shallow-borrows-on-child-writes.rs | 32 +++++++++++++++++++ ...ill-shallow-borrows-on-child-writes.stderr | 19 +++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs create mode 100644 tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index ea557d5321598..d10712b3b532f 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -10,7 +10,9 @@ use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice}; use tracing::debug; -use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict}; +use crate::{ + AccessDepth, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict, +}; // This analysis is different to most others. Its results aren't computed with // `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are @@ -432,7 +434,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. + // `places_conflict::borrow_conflicts_with_place` for every borrow. if place.projection.is_empty() { if !self.body.local_decls[place.local].is_ref_to_static() { state.kill_all(other_borrows_of_local); @@ -445,11 +447,13 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // will be assured that two places being compared definitely denotes the same sets of // locations. let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { - places_conflict( + places_conflict::borrow_conflicts_with_place( self.tcx, self.body, self.borrow_set[i].borrowed_place, - place, + self.borrow_set[i].kind, + place.as_ref(), + AccessDepth::Deep, PlaceConflictBias::NoOverlap, ) }); diff --git a/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs new file mode 100644 index 0000000000000..2828647348712 --- /dev/null +++ b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs @@ -0,0 +1,32 @@ +//! Regression test for . On assignment statements, +//! borrowck's dataflow analysis kills borrows that it knows conflict with the assigment: a borrow +//! of a place can't be live anymore after that place is assigned over. Previously, this didn't +//! account for fake borrows being shallow: it would kill any shallow borrows that would have +//! conflicted if they were normal borrows. This made it possible to circumvent fake borrows for +//! match guards and indexing expressions. + +fn test_match_guard() { + let mut a = (Some(&42u64), 0u8); + let mut b = (None::<&u64>, 0u8); + let mut p = &mut a; + // Writing to `(*p).1` in the match guard previously killed the fake borrow of `p` in the guard, + // making it possible to mutate `p` despite `(*p).0` being matched on. This would reach the + // `Some(r)` branch with `(*p).0` being `None`, so the `r` binding was invalid. + match p.0 { + Some(_) if { p.1 = 1; p = &mut b; false } => unreachable!(), + //~^ ERROR: cannot assign `p` in match guard + Some(r) => println!("{r}"), + None => unreachable!(), + } +} + +fn test_indexing() { + let mut x: &mut [&mut [u32]] = &mut [&mut [0]]; + let y: &mut [&mut [u32]] = &mut []; + // Writing to `x[0][0]` previously killed the fake borrow of `x` in the index expression, making + // it possible to access `y[0]` without a bounds-check. + x[0][{ x[0][0] = 1; x = y; 0 }]; + //~^ ERROR: cannot assign `x` in indexing expression +} + +fn main() {} diff --git a/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr new file mode 100644 index 0000000000000..b45a75a9c6340 --- /dev/null +++ b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr @@ -0,0 +1,19 @@ +error[E0510]: cannot assign `p` in match guard + --> $DIR/dont-kill-shallow-borrows-on-child-writes.rs:16:31 + | +LL | match p.0 { + | --- value is immutable in match guard +LL | Some(_) if { p.1 = 1; p = &mut b; false } => unreachable!(), + | ^^^^^^^^^^ cannot assign + +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/dont-kill-shallow-borrows-on-child-writes.rs:28:25 + | +LL | x[0][{ x[0][0] = 1; x = y; 0 }]; + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0510`. From b97d341337739d1079f4492e3bdcd0fdf2222425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 19 Aug 2026 15:21:39 +0200 Subject: [PATCH 04/16] Also enforce dyn compatibility in (unchecked) type aliases --- .../src/error_codes/E0224.md | 2 +- .../rustc_hir_analysis/src/check/check.rs | 21 +++++---- .../inline_cross/auxiliary/dyn_trait.rs | 2 +- .../cfg-generic-params.rs | 8 ++-- .../cfg-generic-params.stderr | 4 +- .../in-unchecked-type-alias.rs | 15 +++++++ .../in-unchecked-type-alias.stderr | 45 +++++++++++++++++++ tests/ui/hygiene/assoc_ty_bindings.rs | 8 ++-- tests/ui/resolve/issue-3907-2.rs | 6 +-- tests/ui/resolve/issue-3907-2.stderr | 15 ++++++- tests/ui/resolve/issue-3907.rs | 2 +- tests/ui/resolve/issue-3907.stderr | 18 +++++++- .../trait-alias-elaboration.rs | 2 +- .../trait-alias-elaboration.stderr | 6 +-- .../lack-of-wfcheck-gat-generic-const-args.rs | 21 --------- ...k-of-wfcheck-gat-generic-const-args.stderr | 34 -------------- ...k-of-wfcheck-generic-const-args.gca.stderr | 16 +++---- ...f-wfcheck-generic-const-args.no_gca.stderr | 19 ++++++++ .../lack-of-wfcheck-generic-const-args.rs | 26 +++++------ tests/ui/type-alias/lack-of-wfcheck.rs | 24 +++++----- 20 files changed, 173 insertions(+), 121 deletions(-) create mode 100644 tests/ui/dyn-compatibility/in-unchecked-type-alias.rs create mode 100644 tests/ui/dyn-compatibility/in-unchecked-type-alias.stderr delete mode 100644 tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.rs delete mode 100644 tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.stderr create mode 100644 tests/ui/type-alias/lack-of-wfcheck-generic-const-args.no_gca.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0224.md b/compiler/rustc_error_codes/src/error_codes/E0224.md index 628488575b2f8..a6fd0e0fd3a48 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0224.md +++ b/compiler/rustc_error_codes/src/error_codes/E0224.md @@ -11,5 +11,5 @@ Rust does not currently support this. To solve, ensure that the trait object has at least one trait: ``` -type Foo = dyn 'static + Copy; +type Foo = dyn 'static + std::fmt::Debug; ``` diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1895f586df2f0..3f88696fb2c2c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -985,6 +985,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), } else { check_type_alias_type_params_are_used(tcx, def_id); res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + // FIXME(fmease): Update comment. // HACK: We sometimes incidentally check that const arguments have the correct // type as a side effect of the anon const desugaring. To make this "consistent" // for users we explicitly check `ConstArgHasType` clauses so that const args @@ -995,15 +996,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), // // Changing this to normalized obligations is a breaking change: // `type Bar = [(); panic!()];` would become an error - if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty.skip_norm_wip()) + if let Some(obligations) = + wfcx.unnormalized_obligations(span, ty.skip_norm_wip()) { - let filtered_obligations = - unnormalized_obligations.into_iter().filter(|o| { - matches!(o.predicate.kind().skip_binder(), - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) - if matches!(ct.kind(), ty::ConstKind::Param(..))) - }); - wfcx.ocx.register_obligations(filtered_obligations) + wfcx.ocx.register_obligations(obligations.into_iter().filter(|o| { + match o.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType( + ct, + _, + )) => matches!(ct.kind(), ty::ConstKind::Param(..)), + ty::PredicateKind::DynCompatible(_) => true, + _ => false, + } + })) } Ok(()) })); diff --git a/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs index 07a95af7b54e8..35bca80ce3f34 100644 --- a/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs +++ b/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs @@ -9,7 +9,7 @@ pub type Ty2 = dyn for<'a, 'r> Container<'r, Item<'a, 'static> = ()>; pub type Ty3<'s> = &'s dyn ToString; pub trait Container<'r> { - type Item<'a, 'ctx>; + type Item<'a, 'ctx> where Self: Sized; } // Trait-object types inside of a container type that has lifetime bounds ("wrapped"). diff --git a/tests/ui/conditional-compilation/cfg-generic-params.rs b/tests/ui/conditional-compilation/cfg-generic-params.rs index 6480a0f24794c..9044fd65ac978 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.rs +++ b/tests/ui/conditional-compilation/cfg-generic-params.rs @@ -7,8 +7,8 @@ type FnGood = for<#[cfg(yes)] 'a, #[cfg(false)] T> fn(); // OK type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); //~^ ERROR only lifetime parameters can be used in this context -type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> Copy; // OK -type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> std::any::Any; // OK +type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> std::any::Any; //~^ ERROR only lifetime parameters can be used in this context struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(false)] T> u8: Copy; // OK @@ -26,8 +26,8 @@ type FnNo = for<#[cfg_attr(FALSE, unknown)] 'a> fn(); // OK type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); //~^ ERROR cannot find attribute `unknown` in this scope -type PolyNo = dyn for<#[cfg_attr(FALSE, unknown)] 'a> Copy; // OK -type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; +type PolyNo = dyn for<#[cfg_attr(FALSE, unknown)] 'a> std::any::Any; // OK +type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> std::any::Any; //~^ ERROR cannot find attribute `unknown` in this scope struct WhereNo where for<#[cfg_attr(FALSE, unknown)] 'a> u8: Copy; // OK diff --git a/tests/ui/conditional-compilation/cfg-generic-params.stderr b/tests/ui/conditional-compilation/cfg-generic-params.stderr index bae75dd0deb03..572ff815e351e 100644 --- a/tests/ui/conditional-compilation/cfg-generic-params.stderr +++ b/tests/ui/conditional-compilation/cfg-generic-params.stderr @@ -19,7 +19,7 @@ LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); error: cannot find attribute `unknown` in this scope --> $DIR/cfg-generic-params.rs:30:40 | -LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> std::any::Any; | ^^^^^^^ error: cannot find attribute `unknown` in this scope @@ -41,7 +41,7 @@ LL | type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn(); error[E0658]: only lifetime parameters can be used in this context --> $DIR/cfg-generic-params.rs:11:54 | -LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy; +LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> std::any::Any; | ^ | = note: see issue #108185 for more information diff --git a/tests/ui/dyn-compatibility/in-unchecked-type-alias.rs b/tests/ui/dyn-compatibility/in-unchecked-type-alias.rs new file mode 100644 index 0000000000000..8a83b6a4de68a --- /dev/null +++ b/tests/ui/dyn-compatibility/in-unchecked-type-alias.rs @@ -0,0 +1,15 @@ +// FIXME(fmease): Write a description. + +type DynIncompat0 = dyn Sized; //~ ERROR not dyn compatible + +// FIXME(fmease): Well, if this breakage got accepted linking to this issue +// would be moot / nonsensical. Remove the link. +// issue: +type DynIncompat1 = dyn HasAssocConst; //~ ERROR not dyn compatible + +type DynIncompat2<'a> = dyn HasGenericAssocType = ()>; //~ ERROR not dyn compatible + +trait HasAssocConst { const N: usize; } +trait HasGenericAssocType { type Type; } + +fn main() {} diff --git a/tests/ui/dyn-compatibility/in-unchecked-type-alias.stderr b/tests/ui/dyn-compatibility/in-unchecked-type-alias.stderr new file mode 100644 index 0000000000000..edcc748e0d192 --- /dev/null +++ b/tests/ui/dyn-compatibility/in-unchecked-type-alias.stderr @@ -0,0 +1,45 @@ +error[E0038]: the trait `Sized` is not dyn compatible + --> $DIR/in-unchecked-type-alias.rs:3:1 + | +LL | type DynIncompat0 = dyn Sized; + | ^^^^^^^^^^^^^^^^^ `Sized` is not dyn compatible + | + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + +error[E0038]: the trait `HasAssocConst` is not dyn compatible + --> $DIR/in-unchecked-type-alias.rs:8:1 + | +LL | type DynIncompat1 = dyn HasAssocConst; + | ^^^^^^^^^^^^^^^^^ `HasAssocConst` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/in-unchecked-type-alias.rs:12:29 + | +LL | trait HasAssocConst { const N: usize; } + | ------------- ^ ...because it contains associated const `N` + | | + | this trait is not dyn compatible... + = help: consider moving `N` to another trait + +error[E0038]: the trait `HasGenericAssocType` is not dyn compatible + --> $DIR/in-unchecked-type-alias.rs:10:1 + | +LL | type DynIncompat2<'a> = dyn HasGenericAssocType = ()>; + | ^^^^^^^^^^^^^^^^^^^^^ `HasGenericAssocType` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/in-unchecked-type-alias.rs:13:34 + | +LL | trait HasGenericAssocType { type Type; } + | ------------------- ^^^^ ...because it contains generic associated type `Type` + | | + | this trait is not dyn compatible... + = help: consider moving `Type` to another trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/hygiene/assoc_ty_bindings.rs b/tests/ui/hygiene/assoc_ty_bindings.rs index 5e42e27062fbd..f548b892a7049 100644 --- a/tests/ui/hygiene/assoc_ty_bindings.rs +++ b/tests/ui/hygiene/assoc_ty_bindings.rs @@ -4,10 +4,10 @@ trait Base { type AssocTy; - fn f(); + fn f(self); } trait Derived: Base { - fn g(); + fn g(self); } macro mac() { @@ -16,12 +16,12 @@ macro mac() { impl Base for u8 { type AssocTy = u8; - fn f() { + fn f(self) { let _: Self::AssocTy; } } impl Derived for u8 { - fn g() { + fn g(self) { let _: Self::AssocTy; } } diff --git a/tests/ui/resolve/issue-3907-2.rs b/tests/ui/resolve/issue-3907-2.rs index f261de5f4025a..33bfd03237862 100644 --- a/tests/ui/resolve/issue-3907-2.rs +++ b/tests/ui/resolve/issue-3907-2.rs @@ -2,14 +2,14 @@ extern crate issue_3907; -type Foo = dyn issue_3907::Foo + 'static; +type Foo = dyn issue_3907::Foo + 'static; //~ ERROR not dyn compatible [E0038] struct S { name: isize } fn bar(_x: Foo) {} -//~^ ERROR E0038 -//~| ERROR E0277 +//~^ ERROR not dyn compatible [E0038] +//~| ERROR cannot be known at compilation time [E0277] fn main() {} diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr index 40cdfb7a30255..64ed3d88b3fdc 100644 --- a/tests/ui/resolve/issue-3907-2.stderr +++ b/tests/ui/resolve/issue-3907-2.stderr @@ -1,3 +1,16 @@ +error[E0038]: the trait `issue_3907::Foo` is not dyn compatible + --> $DIR/issue-3907-2.rs:5:1 + | +LL | type Foo = dyn issue_3907::Foo + 'static; + | ^^^^^^^^ `issue_3907::Foo` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/auxiliary/issue-3907.rs:2:8 + | +LL | fn bar(); + | ^^^ the trait is not dyn compatible because associated function `bar` has no `self` parameter + error[E0038]: the trait `issue_3907::Foo` is not dyn compatible --> $DIR/issue-3907-2.rs:11:12 | @@ -24,7 +37,7 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn bar(_x: &Foo) {} | + -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/resolve/issue-3907.rs b/tests/ui/resolve/issue-3907.rs index fd08c360d3627..19d83515066eb 100644 --- a/tests/ui/resolve/issue-3907.rs +++ b/tests/ui/resolve/issue-3907.rs @@ -2,7 +2,7 @@ extern crate issue_3907; -type Foo = dyn issue_3907::Foo; +type Foo = dyn issue_3907::Foo; //~ ERROR not dyn compatible struct S { name: isize diff --git a/tests/ui/resolve/issue-3907.stderr b/tests/ui/resolve/issue-3907.stderr index 0dc85829160bf..7999fd0c9eddf 100644 --- a/tests/ui/resolve/issue-3907.stderr +++ b/tests/ui/resolve/issue-3907.stderr @@ -14,6 +14,20 @@ help: consider importing this trait instead LL + use issue_3907::Foo; | -error: aborting due to 1 previous error +error[E0038]: the trait `issue_3907::Foo` is not dyn compatible + --> $DIR/issue-3907.rs:5:1 + | +LL | type Foo = dyn issue_3907::Foo; + | ^^^^^^^^ `issue_3907::Foo` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/auxiliary/issue-3907.rs:2:8 + | +LL | fn bar(); + | ^^^ the trait is not dyn compatible because associated function `bar` has no `self` parameter + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0404`. +Some errors have detailed explanations: E0038, E0404. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.rs b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs index a5b4443ffddd3..0f65e80590ddd 100644 --- a/tests/ui/sized-hierarchy/trait-alias-elaboration.rs +++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs @@ -6,7 +6,7 @@ use std::marker::MetaSized; // wrote `MetaSized` in the `dyn Trait` then that should still be an error so as not to accidentally // accept this going forwards. -trait Qux = Clone; +trait Qux = std::fmt::Debug; type Foo = dyn Qux + MetaSized; //~^ ERROR: only auto traits can be used as additional traits in a trait object diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr index 394aae6f8e32f..815fd7da2771a 100644 --- a/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr +++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr @@ -1,15 +1,15 @@ error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/trait-alias-elaboration.rs:11:16 | -LL | trait Qux = Clone; - | ------------------ additional non-auto trait +LL | trait Qux = std::fmt::Debug; + | ---------------------------- additional non-auto trait LL | LL | type Foo = dyn Qux + MetaSized; | ^^^ --------- first non-auto trait | | | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: MetaSized + MetaSized + Clone {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: MetaSized + MetaSized + Debug {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 1 previous error diff --git a/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.rs b/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.rs deleted file mode 100644 index 58bc4daedfcc1..0000000000000 --- a/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Demonstrate that generic const arguments in GAT constraints are rejected at -// the definition site of an eager type alias. - -//@ compile-flags: -Znext-solver=globally - -#![feature(generic_const_args, min_generic_const_args)] -#![expect(incomplete_features)] - -// * dyn incompatible due to GAT -// * `'a: 'static`, `String: Copy` and `[u8]: Sized` unsatisfied, `loop {}` diverging -type Several<'a> = dyn HasGenericAssocType = [u8]>; -//~^ ERROR - -trait HasGenericAssocType { - type Type<'a: 'static, T: Copy, const N: usize>; -} - -fn main() { - let _: &Several<'_>; - //~^ ERROR the trait `HasGenericAssocType` is not dyn compatible -} diff --git a/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.stderr b/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.stderr deleted file mode 100644 index 6b06ba9cb14fe..0000000000000 --- a/tests/ui/type-alias/lack-of-wfcheck-gat-generic-const-args.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: constant evaluation is taking a long time - --> $DIR/lack-of-wfcheck-gat-generic-const-args.rs:11:63 - | -LL | type Several<'a> = dyn HasGenericAssocType = [u8]>; - | ^^^^^^^ - | - = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. - If your compilation actually takes a long time, you can safely allow the lint -help: the constant being evaluated - --> $DIR/lack-of-wfcheck-gat-generic-const-args.rs:11:61 - | -LL | type Several<'a> = dyn HasGenericAssocType = [u8]>; - | ^^^^^^^^^^^ - = note: `#[deny(long_running_const_eval)]` on by default - -error[E0038]: the trait `HasGenericAssocType` is not dyn compatible - --> $DIR/lack-of-wfcheck-gat-generic-const-args.rs:19:12 - | -LL | let _: &Several<'_>; - | ^^^^^^^^^^^^ `HasGenericAssocType` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/lack-of-wfcheck-gat-generic-const-args.rs:15:10 - | -LL | trait HasGenericAssocType { - | ------------------- this trait is not dyn compatible... -LL | type Type<'a: 'static, T: Copy, const N: usize>; - | ^^^^ ...because it contains generic associated type `Type` - = help: consider moving `Type` to another trait - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.gca.stderr b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.gca.stderr index 52edd50aaaaad..4f1b284821041 100644 --- a/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.gca.stderr +++ b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.gca.stderr @@ -1,16 +1,16 @@ -error[E0191]: the value of the associated constant `N` in `HasAssocConst` must be specified - --> $DIR/lack-of-wfcheck-generic-const-args.rs:19:25 +error[E0191]: the value of the associated constant `N` in `HasNonTypeAssocConst` must be specified + --> $DIR/lack-of-wfcheck-generic-const-args.rs:13:20 | -LL | type DynIncompat1 = dyn HasAssocConst; - | ^^^^^^^^^^^^^ +LL | type TyAlias = dyn HasNonTypeAssocConst; + | ^^^^^^^^^^^^^^^^^^^^ ... -LL | const N: usize; - | -------------- `N` defined here +LL | /*non-type */const N: usize; + | -------------- `N` defined here | help: specify the associated constant | -LL | type DynIncompat1 = dyn HasAssocConst; - | +++++++++++++++++ +LL | type TyAlias = dyn HasNonTypeAssocConst; + | +++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.no_gca.stderr b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.no_gca.stderr new file mode 100644 index 0000000000000..c41a2f91763b0 --- /dev/null +++ b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.no_gca.stderr @@ -0,0 +1,19 @@ +error[E0038]: the trait `HasNonTypeAssocConst` is not dyn compatible + --> $DIR/lack-of-wfcheck-generic-const-args.rs:13:1 + | +LL | type TyAlias = dyn HasNonTypeAssocConst; + | ^^^^^^^^^^^^ `HasNonTypeAssocConst` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/lack-of-wfcheck-generic-const-args.rs:17:24 + | +LL | trait HasNonTypeAssocConst { + | -------------------- this trait is not dyn compatible... +LL | /*non-type */const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.rs b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.rs index afca550944ffc..d995cb7989ab8 100644 --- a/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.rs +++ b/tests/ui/type-alias/lack-of-wfcheck-generic-const-args.rs @@ -1,26 +1,20 @@ -// Demonstrate that generic_const_args changes the behavior for dyn trait aliases -// with non-type associated consts: the associated const must be specified. +// FIXME(fmease): Re-audit this test! Rewrite its description! Probably rename the entire file, too! + +// Demonstrate that enabling `generic_const_args` changes the behavior for trait object types in +// (unchecked) type aliases where the corresponding trait has non-type associated consts: +// The associated const must be specified. //@ revisions: no_gca gca //@ compile-flags: -Znext-solver=globally -//@ [no_gca] check-pass #![cfg_attr(gca, feature(generic_const_args, min_generic_const_args))] -#![cfg_attr(gca, expect(incomplete_features))] - -type UnsatTraitBound0 = [str]; // `str: Sized` unsatisfied -type UnsatTraitBound1> = T; // `str: Sized` unsatisfied -type UnsatOutlivesBound<'a> = &'static &'a (); // `'a: 'static` unsatisfied - -type Diverging = [(); panic!()]; // `panic!()` diverging -type DynIncompat0 = dyn Sized; // `Sized` axiomatically dyn incompatible -// issue: -type DynIncompat1 = dyn HasAssocConst; -//[gca]~^ ERROR the value of the associated constant `N` in `HasAssocConst` must be specified +//[no_gca]~v ERROR not dyn compatible +type TyAlias = dyn HasNonTypeAssocConst; +//[gca]~^ ERROR the value of the associated constant `N` in `HasNonTypeAssocConst` must be specified -trait HasAssocConst { - const N: usize; +trait HasNonTypeAssocConst { + /*non-type */const N: usize; } fn main() {} diff --git a/tests/ui/type-alias/lack-of-wfcheck.rs b/tests/ui/type-alias/lack-of-wfcheck.rs index 91fbee8d3f198..4935eff8b2dfe 100644 --- a/tests/ui/type-alias/lack-of-wfcheck.rs +++ b/tests/ui/type-alias/lack-of-wfcheck.rs @@ -1,11 +1,14 @@ -// Demonstrate that we don't check the definition site of (eager) type aliases for well-formedness. +// Demonstrate that we don't check the def site of (unchecked) type aliases for well-formedness. // // Listed below are ill-formed type system entities which we don't reject since they appear inside -// the definition of (eager) type aliases. These type aliases are intentionally not referenced from -// anywhere to prevent the eagerly expanded / instantiated aliased types from getting wfchecked +// the definition of (unchecked) type aliases. These type aliases are intentionally not referenced +// from anywhere to prevent the eagerly expanded / instantiated aliased types from getting wfchecked // since that's not what we're testing here. //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver type UnsatTraitBound0 = [str]; // `str: Sized` unsatisfied type UnsatTraitBound1> = T; // `str: Sized` unsatisfied @@ -13,15 +16,14 @@ type UnsatOutlivesBound<'a> = &'static &'a (); // `'a: 'static` unsatisfied type Diverging = [(); panic!()]; // `panic!()` diverging -type DynIncompat0 = dyn Sized; // `Sized` axiomatically dyn incompatible -// issue: -type DynIncompat1 = dyn HasAssocConst; // dyn incompatible due to (non-type-level) assoc const - -// * dyn incompatible due to GAT // * `'a: 'static`, `String: Copy` and `[u8]: Sized` unsatisfied, `loop {}` diverging -type Several<'a> = dyn HasGenericAssocType = [u8]>; +#[expect(unused_associated_type_bounds)] +type Several<'a> = dyn Trait = [u8]>; -trait HasAssocConst { const N: usize; } -trait HasGenericAssocType { type Type<'a: 'static, T: Copy, const N: usize>; } +trait Trait { + type Type<'a: 'static, T: Copy, const N: usize> + where + Self: Sized; +} fn main() {} From 7aa38c1c381bbbb729a83cc9147b0f121f912dfb Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Mon, 17 Aug 2026 10:42:55 -0700 Subject: [PATCH 05/16] Implement `AsMut` and `AsRef` for `!`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow e.g. `&[!]` to satisfy `&[T] where T: AsRef`. It follows the recommendation from the never documentation: > When writing your own traits, `!` should have an `impl` whenever > there is an obvious `impl` which doesn’t `panic!`. -- The test tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs had to be updated because it depended on this impl not existing. I’ve confirmed that the modified test still functions as a regression test by compiling it in nightly-2022-08-28 and seeing it ICE. --- library/core/src/convert/mod.rs | 14 ++++++++++++++ ...c-with-implicit-hrtb-without-dyn.pre2021.stderr | 13 ++++--------- .../generic-with-implicit-hrtb-without-dyn.rs | 4 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index a57f3d58e3998..c2d0a740495cd 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -863,6 +863,20 @@ const impl AsMut for str { } } +#[stable(feature = "never_type", since = "CURRENT_RUSTC_VERSION")] +impl AsRef for ! { + fn as_ref(&self) -> &T { + match *self {} + } +} + +#[stable(feature = "never_type", since = "CURRENT_RUSTC_VERSION")] +impl AsMut for ! { + fn as_mut(&mut self) -> &mut T { + match *self {} + } +} + //////////////////////////////////////////////////////////////////////////////// // THE NO-ERROR ERROR TYPE //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.pre2021.stderr b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.pre2021.stderr index dc566ad50153a..54ea4882c4669 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.pre2021.stderr +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.pre2021.stderr @@ -1,16 +1,11 @@ -error[E0277]: the trait bound `!: AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied +error[E0277]: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:7:13 | LL | fn ice() -> impl AsRef { - | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `!` + | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not implemented for `()` ... -LL | todo!() - | ------- return type was inferred to be `!` here - | -help: `!` can be coerced to any type; consider casting it to a concrete type that implements the trait - | -LL | todo!() as /* Type */ - | +++++++++++++ +LL | () + | -- return type was inferred to be `()` here error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs index 64311a474cade..6c538e8c8ee16 100644 --- a/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs +++ b/tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs @@ -5,10 +5,10 @@ #![allow(warnings)] fn ice() -> impl AsRef { - //[pre2021]~^ ERROR: the trait bound `!: AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] + //[pre2021]~^ ERROR: the trait bound `(): AsRef<(dyn for<'a> Fn(&'a ()) + 'static)>` is not satisfied [E0277] //[edition2021]~^^ ERROR: expected a type, found a trait [E0782] //[edition2021]~| ERROR: expected a type, found a trait [E0782] - todo!() + () } fn main() {} From e6d5195ad8d8c2e5fc970efe1aeeac82d0a1289f Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Fri, 28 Aug 2026 20:13:12 +0200 Subject: [PATCH 06/16] generalise impls on box --- library/alloc/src/boxed.rs | 2 +- library/alloc/src/io/impls.rs | 8 ++++---- library/std/src/os/fd/owned.rs | 3 ++- library/std/src/os/fd/raw.rs | 3 ++- library/std/src/os/solid/io.rs | 3 ++- library/std/src/os/windows/io/handle.rs | 3 ++- library/std/src/os/windows/io/socket.rs | 3 ++- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 473f01660bdb4..e4940551b3741 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2502,7 +2502,7 @@ impl Future for Box { } #[stable(feature = "box_error", since = "1.8.0")] -impl Error for Box { +impl Error for Box { #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) diff --git a/library/alloc/src/io/impls.rs b/library/alloc/src/io/impls.rs index 0296cada74171..b16d7b424c163 100644 --- a/library/alloc/src/io/impls.rs +++ b/library/alloc/src/io/impls.rs @@ -92,7 +92,7 @@ impl BufRead for &mut B { } #[stable(feature = "rust1", since = "1.0.0")] -impl Read for Box { +impl Read for Box { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) @@ -148,7 +148,7 @@ impl SizeHint for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for Box { +impl Write for Box { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) @@ -185,7 +185,7 @@ impl Write for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Seek for Box { +impl Seek for Box { #[inline] fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) @@ -212,7 +212,7 @@ impl Seek for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for Box { +impl BufRead for Box { #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 4ed5c43616a29..87a8e20bad0d3 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -7,6 +7,7 @@ use moto_rt::libc; use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::alloc::Allocator; #[cfg(not(target_os = "trusty"))] use crate::fs; use crate::marker::PhantomData; @@ -474,7 +475,7 @@ impl AsFd for crate::rc::UniqueRc { } #[stable(feature = "asfd_ptrs", since = "1.64.0")] -impl AsFd for Box { +impl AsFd for Box { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { (**self).as_fd() diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index a0c96e2836fc5..a8d981520efd2 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -9,6 +9,7 @@ use moto_rt::libc; #[cfg(target_os = "motor")] use super::owned::OwnedFd; +use crate::alloc::Allocator; #[cfg(not(target_os = "trusty"))] use crate::fs; use crate::io; @@ -282,7 +283,7 @@ impl AsRawFd for crate::rc::UniqueRc { } #[stable(feature = "asrawfd_ptrs", since = "1.63.0")] -impl AsRawFd for Box { +impl AsRawFd for Box { #[inline] fn as_raw_fd(&self) -> RawFd { (**self).as_raw_fd() diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index d4defb5f47fb0..ff79f192819ce 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -46,6 +46,7 @@ #![unstable(feature = "solid_ext", issue = "none")] +use crate::alloc::Allocator; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -283,7 +284,7 @@ impl AsFd for crate::rc::Rc { } } -impl AsFd for Box { +impl AsFd for Box { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { (**self).as_fd() diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 29697bbb5f8fc..01bd36155b110 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -3,6 +3,7 @@ #![stable(feature = "io_safety", since = "1.63.0")] use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use crate::alloc::Allocator; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner, cvt}; @@ -491,7 +492,7 @@ impl AsHandle for crate::rc::UniqueRc { } #[stable(feature = "as_windows_ptrs", since = "1.71.0")] -impl AsHandle for Box { +impl AsHandle for Box { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { (**self).as_handle() diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index ae1b7eaee8d12..d625a9ac52730 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -3,6 +3,7 @@ #![stable(feature = "io_safety", since = "1.63.0")] use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use crate::alloc::Allocator; use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop}; #[cfg(not(target_vendor = "uwp"))] @@ -275,7 +276,7 @@ impl AsSocket for crate::rc::UniqueRc { } #[stable(feature = "as_windows_ptrs", since = "1.71.0")] -impl AsSocket for Box { +impl AsSocket for Box { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { (**self).as_socket() From 30d8dc74469490355d7e159d32fdd63738e31de1 Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 08:30:24 +0000 Subject: [PATCH 07/16] Add #[rustc_anti_fundamental] attribute This adds a new compiler attribute that prevents non-local fundamental types from receiving implementations of marked traits. This allows addressing soundness problems with traits like DerefMut on Pin and similar wrapper types. The attribute is checked during the orphan check in coherence. --- compiler/rustc_attr_ir/src/data_structures.rs | 6 ++ .../rustc_attr_ir/src/encode_cross_crate.rs | 1 + .../src/attributes/traits.rs | 8 ++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + .../src/coherence/orphan.rs | 86 ++++++++++++----- compiler/rustc_hir_analysis/src/collect.rs | 2 + .../rustc_hir_analysis/src/diagnostics.rs | 16 +++- .../src/ty/context/impl_interner.rs | 4 + compiler/rustc_middle/src/ty/trait_def.rs | 5 + .../rustc_next_trait_solver/src/coherence.rs | 77 +++++++++++++-- compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_type_ir/src/interner.rs | 2 + .../anti-fundamental-foreign-type.rs | 85 +++++++++++++++++ .../anti-fundamental-foreign-type.stderr | 95 +++++++++++++++++++ .../anti-fundamental-generic-projection.rs | 77 +++++++++++++++ ...anti-fundamental-generic-projection.stderr | 50 ++++++++++ .../anti-fundamental-invalid-target.rs | 18 ++++ .../anti-fundamental-invalid-target.stderr | 18 ++++ .../coherence/anti-fundamental-local-trait.rs | 23 +++++ .../ui/coherence/anti-fundamental-overlap.rs | 19 ++++ .../coherence/anti-fundamental-overlap.stderr | 13 +++ .../auxiliary/anti_fundamental_trait_lib.rs | 15 +++ 24 files changed, 593 insertions(+), 31 deletions(-) create mode 100644 tests/ui/coherence/anti-fundamental-foreign-type.rs create mode 100644 tests/ui/coherence/anti-fundamental-foreign-type.stderr create mode 100644 tests/ui/coherence/anti-fundamental-generic-projection.rs create mode 100644 tests/ui/coherence/anti-fundamental-generic-projection.stderr create mode 100644 tests/ui/coherence/anti-fundamental-invalid-target.rs create mode 100644 tests/ui/coherence/anti-fundamental-invalid-target.stderr create mode 100644 tests/ui/coherence/anti-fundamental-local-trait.rs create mode 100644 tests/ui/coherence/anti-fundamental-overlap.rs create mode 100644 tests/ui/coherence/anti-fundamental-overlap.stderr create mode 100644 tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index 54d083a094883..9b621a0c35d1b 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -1140,6 +1140,12 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_lifetime_dependent_specialization]`. RustcAllowLifetimeDependentSpecialization, + /// Represents `#[rustc_anti_fundamental]`. This marks a trait so that it + /// cannot be implemented for non-local `#[fundamental]` types. This in particular + /// prevents the implementation of `Deref`, `DerefMut`, and `DispatchFromDyn` on + /// fundamental wrappers like `Pin` and `Box`. + RustcAntiFundamental, + /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). RustcAsPtr, diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 270ec0399799e..7bb75e54440b1 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -107,6 +107,7 @@ impl AttributeKind { RustcAllowConstFnUnstable(..) => No, RustcAllowIncoherentImpl(..) => No, RustcAllowLifetimeDependentSpecialization => No, + RustcAntiFundamental => No, RustcAsPtr => Yes, RustcAutodiff(..) => Yes, RustcBodyStability { .. } => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 1d0d26ea62cb3..5968efa2d815f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -123,6 +123,14 @@ impl NoArgsAttributeParser for RustcCoinductiveParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoinductive; } +pub(crate) struct RustcAntiFundamentalParser; +impl NoArgsAttributeParser for RustcAntiFundamentalParser { + const PATH: &[Symbol] = &[sym::rustc_anti_fundamental]; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const STABILITY: AttributeStability = unstable!(rustc_attrs); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAntiFundamental; +} + pub(crate) struct RustcAllowIncoherentImplParser; impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cf99311cc0cfc..7e4b0149a0c70 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -295,6 +295,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f79a8e9ffc79c..e4b4e3296803f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -346,6 +346,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_never_returns_null_ptr, sym::rustc_no_implicit_autorefs, sym::rustc_coherence_is_core, + sym::rustc_anti_fundamental, sym::rustc_coinductive, sym::rustc_comptime, sym::rustc_allow_incoherent_impl, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c970799d318fe..b7730551ae03a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -28,31 +28,41 @@ pub(crate) fn orphan_check_impl( match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) { Ok(()) => {} - Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) { - Ok(()) => match err { - OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => { - let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); - - for param_def_id in uncovered_ty_params.uncovered { - let ident = tcx.item_ident(param_def_id); - - tcx.emit_node_span_lint( - UNCOVERED_PARAM_IN_PROJECTION, - hir_id, - ident.span, - diagnostics::UncoveredTyParam { - param: ident, - local_ty: uncovered_ty_params.local_ty, - }, - ); + Err(err) => { + if tcx.trait_def(trait_ref.def_id).is_anti_fundamental { + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } + + match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) { + Ok(()) => match err { + OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => { + let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); + + for param_def_id in uncovered_ty_params.uncovered { + let ident = tcx.item_ident(param_def_id); + + tcx.emit_node_span_lint( + UNCOVERED_PARAM_IN_PROJECTION, + hir_id, + ident.span, + diagnostics::UncoveredTyParam { + param: ident, + local_ty: uncovered_ty_params.local_ty, + }, + ); + } } - } - OrphanCheckErr::NonLocalInputType(_) => { - bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") - } - }, - Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), - }, + OrphanCheckErr::NonLocalInputType(_) => { + bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") + } + OrphanCheckErr::AntiFundamentalForeignType { .. } => { + // An anti-fundamental trait should return early above and never enter compat mode. + bug!("anti-fundamental traits never enter compat mode") + } + }, + Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), + } + } } let trait_def_id = trait_ref.def_id; @@ -381,6 +391,24 @@ fn orphan_check<'tcx>( }); OrphanCheckErr::NonLocalInputType(tys) } + OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => { + let (self_ty, fundamental_ty) = infcx.probe(|_| { + for (arg, id_arg) in + std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id)) + { + let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::No, + arg, + id_arg, + ); + } + ( + infcx.resolve_vars_if_possible(self_ty), + infcx.resolve_vars_if_possible(fundamental_ty), + ) + }); + OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } + } }) } @@ -499,6 +527,16 @@ fn emit_orphan_check_error<'tcx>( } guar.unwrap() } + traits::OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => { + let item = tcx.hir_expect_item(impl_def_id); + let impl_ = item.expect_impl(); + tcx.dcx().emit_err(diagnostics::AntiFundamentalForeignImpl { + span: impl_.self_ty.span, + trait_name: tcx.def_path_str(trait_ref.def_id), + self_ty, + fundamental_ty, + }) + } } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 65fd562a4ebf6..775200988c1c6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1122,6 +1122,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let deny_explicit_impl = find_attr!(attrs, RustcDenyExplicitImpl); let force_dyn_incompatible = find_attr!(attrs, RustcDynIncompatibleTrait(span) => *span); + let is_anti_fundamental = find_attr!(attrs, RustcAntiFundamental); ty::TraitDef { def_id: def_id.to_def_id(), @@ -1139,6 +1140,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { must_implement_one_of, force_dyn_incompatible, deny_explicit_impl, + is_anti_fundamental, } } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index a50aefd016059..f7b05dafc3bed 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -2144,7 +2144,6 @@ pub(crate) struct OnlyStructsCanBeViewedAdt<'tcx> { pub article: &'static str, pub kind: &'static str, } - #[derive(Diagnostic)] #[diag("the type of const parameters must not depend on other generic parameters", code = E0770)] pub(crate) struct ParamInTyOfConstParam<'tcx> { @@ -2153,3 +2152,18 @@ pub(crate) struct ParamInTyOfConstParam<'tcx> { pub(crate) span: Span, pub(crate) ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag("cannot implement `{$trait_name}` for the fundamental type `{$fundamental_ty}`")] +#[note( + "`{$trait_name}` is `#[rustc_anti_fundamental]` and \ + cannot be implemented for `#[fundamental]` types from another crate" +)] +pub(crate) struct AntiFundamentalForeignImpl<'tcx> { + #[primary_span] + #[label("impl of `{$trait_name}` not allowed for `{$self_ty}`")] + pub(crate) span: Span, + pub(crate) trait_name: String, + pub(crate) self_ty: Ty<'tcx>, + pub(crate) fundamental_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 74327278dbca6..fdc02a8482010 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -638,6 +638,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(def_id).is_fundamental } + fn trait_is_anti_fundamental(self, def_id: DefId) -> bool { + self.trait_def(def_id).is_anti_fundamental + } + fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool { self.trait_def(trait_def_id).safety.is_unsafe() } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 5309e35b1073c..eb0c293938f66 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -80,6 +80,11 @@ pub struct TraitDef { /// This only applies to built-in traits, and is marked via /// `#[rustc_deny_explicit_impl]`. pub deny_explicit_impl: bool, + + /// If `true`, then this trait has the `#[rustc_anti_fundamental]` attribute + /// and cannot be implemented for `#[fundamental]` types from another crate. + /// Used for `Deref`, `DerefMut`, `DispatchFromDyn`, `CoerceUnsized`, etc. + pub is_anti_fundamental: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index e37e69a617bbd..d64eef889a251 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -17,6 +17,12 @@ pub enum InCrate { Remote, } +impl InCrate { + pub fn def_id_is_local(self, def_id: impl DefId) -> bool { + matches!(self, InCrate::Local { .. }) && def_id.is_local() + } +} + #[derive(Copy, Clone, Debug)] pub enum OrphanCheckMode { /// Proper orphan check. @@ -118,6 +124,7 @@ impl From for IsFirstInputType { pub enum OrphanCheckErr { NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), + AntiFundamentalForeignType { self_ty: I::Ty, fundamental_ty: I::Ty }, } #[derive_where(Debug; I: Interner, T: Debug)] @@ -160,6 +167,13 @@ pub struct UncoveredTyParams { /// - however, `LocalType>` is OK, because `T` is a subtree of /// `LocalType>`, which is local and has no types between it and /// the type parameter. +/// 5. If the trait is marked `#[rustc_anti_fundamental]`, the `Self` type +/// must not have a non-local `#[fundamental]` type at its head (even if +/// it wraps a local type as in (2)). +/// - e.g., `Box` or `&Pin` is rejected if the trait +/// is `#[rustc_anti_fundamental]`. +/// - This lets the standard library reserve control over traits like `Deref` +/// and `DispatchFromDyn` on fundamental wrappers such as `Box` and `Pin`. /// /// The orphan rules actually serve several different purposes: /// @@ -223,7 +237,7 @@ pub fn orphan_check_trait_ref( infcx: &Infcx, trait_ref: ty::TraitRef, in_crate: InCrate, - lazily_normalize_ty: impl FnMut(I::Ty) -> Result, + mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result, ) -> Result>, E> where Infcx: InferCtxtLike, @@ -234,6 +248,20 @@ where panic!("orphan check only expects inference variables: {trait_ref:?}"); } + // Anti-fundamental check: if the trait is marked `#[rustc_anti_fundamental]`, + // we do not allow impls where the head of the Self type is a non-local fundamental + // type. This prevents downstream crates from implementing traits like `Deref` on + // fundamental wrappers like `Box` or `Pin`. + let cx = infcx.cx(); + if cx.trait_is_anti_fundamental(trait_ref.def_id) { + let self_ty = trait_ref.self_ty(); + if let Some(fundamental_ty) = + check_anti_fundamental_head(infcx, in_crate, &mut lazily_normalize_ty, self_ty)? + { + return Ok(Err(OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty })); + } + } + let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty); Ok(match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), @@ -256,6 +284,46 @@ where }) } +/// Checks the head of the Self type for a non-local fundamental type. +/// +/// If the head is a reference (`&` / `&mut`), we unwrap it and inspect the pointee type. +/// This ensures that wrapping a fundamental type in a reference (such as `&Pin`) +/// cannot be used to bypass the anti-fundamental restriction. +/// +/// Returns `Some(ty)` with the offending fundamental type if the check fails. +fn check_anti_fundamental_head( + infcx: &Infcx, + in_crate: InCrate, + mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result, + mut ty: I::Ty, +) -> Result, E> +where + Infcx: InferCtxtLike, + I: Interner, +{ + loop { + ty = infcx.shallow_resolve(ty); + let norm_ty = match lazily_normalize_ty(ty)? { + norm if norm.is_ty_var() => ty, + norm => norm, + }; + + if let ty::Ref(_, inner, _) = norm_ty.kind() { + ty = inner; + continue; + } + + ty = norm_ty; + break; + } + + Ok(matches!( + ty.kind(), + ty::Adt(def, _) if def.is_fundamental() && !in_crate.def_id_is_local(def.def_id()) + ) + .then_some(ty)) +} + struct OrphanChecker<'a, Infcx, I: Interner, F> { infcx: &'a Infcx, in_crate: InCrate, @@ -296,11 +364,8 @@ where ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty)) } - fn def_id_is_local(&mut self, def_id: impl DefId) -> bool { - match self.in_crate { - InCrate::Local { .. } => def_id.is_local(), - InCrate::Remote => false, - } + fn def_id_is_local(&self, def_id: impl DefId) -> bool { + self.in_crate.def_id_is_local(def_id) } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cd7f422fb72f3..663c286141f85 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -316,6 +316,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllocatorZeroedVariant { .. } => (), AttributeKind::RustcAllowIncoherentImpl(..) => (), AttributeKind::RustcAllowLifetimeDependentSpecialization => (), + AttributeKind::RustcAntiFundamental => (), AttributeKind::RustcAsPtr => (), AttributeKind::RustcAutodiff(..) => (), AttributeKind::RustcBodyStability { .. } => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3fcb59ea2d701..2d0b52c3a8c18 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1764,6 +1764,7 @@ symbols! { rustc_allow_incoherent_impl, rustc_allow_lifetime_dependent_specialization, rustc_allowed_through_unstable_modules, + rustc_anti_fundamental, rustc_as_ptr, rustc_attrs, rustc_autodiff, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1dfb34d94c0fc..18e61db5b6955 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -485,6 +485,8 @@ pub trait Interner: fn trait_is_fundamental(self, def_id: Self::TraitId) -> bool; + fn trait_is_anti_fundamental(self, def_id: Self::TraitId) -> bool; + /// Returns `true` if this is an `unsafe trait`. fn trait_is_unsafe(self, trait_def_id: Self::TraitId) -> bool; diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.rs b/tests/ui/coherence/anti-fundamental-foreign-type.rs new file mode 100644 index 0000000000000..bd9ca9542f939 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.rs @@ -0,0 +1,85 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that `#[rustc_anti_fundamental]` prevents implementing the trait +// on non-local `#[fundamental]` types. + +#![feature(fundamental)] + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, AntiFundamentalWithParam, FundamentalWrapper, NonFundamentalWrapper, +}; + +struct LocalType; + +#[fundamental] +struct LocalFundamental(T); + +// OK: implementing on a local type. +impl AntiFundamentalTrait for LocalType {} + +// ERROR: implementing on a non-fundamental foreign type wrapping a local type +impl AntiFundamentalTrait for NonFundamentalWrapper {} +//~^ ERROR only traits defined in the current crate + +// ERROR: implementing on a foreign fundamental type. +impl AntiFundamentalTrait for FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: implementing on a reference to a foreign fundamental type. +impl AntiFundamentalTrait for &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: implementing on a mutable double-reference to a foreign fundamental type. +impl AntiFundamentalTrait for &mut &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// OK: outer type is local fundamental, so the Self type is local. +impl AntiFundamentalTrait for LocalFundamental> {} + +// ERROR: outer type is foreign fundamental. +impl AntiFundamentalTrait for FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// OK: Self is a local type, even if the trait parameter is a foreign fundamental type. +impl AntiFundamentalWithParam> for LocalType {} + +// ERROR: Self is a foreign fundamental type. +impl AntiFundamentalWithParam for FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalWithParam` for the fundamental type + +// ERROR: projection normalizes to a foreign fundamental type. +struct LocalType2; +trait AssocHelper { + type Assoc; +} + +impl AssocHelper for LocalType2 { + type Assoc = FundamentalWrapper; +} + +impl AntiFundamentalTrait for ::Assoc {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: foreign fundamental type wrapping a generic local type. +struct LocalGeneric(T); + +impl AntiFundamentalTrait for FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: reference to a foreign fundamental type wrapping a generic local type. +impl AntiFundamentalTrait for &FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: single mutable reference to a foreign fundamental type. +impl AntiFundamentalTrait for &mut FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: type alias expanding to a foreign fundamental type. +struct LocalType3; +type LocalAlias = FundamentalWrapper; +impl AntiFundamentalTrait for LocalAlias {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.stderr b/tests/ui/coherence/anti-fundamental-foreign-type.stderr new file mode 100644 index 0000000000000..f61788390510b --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.stderr @@ -0,0 +1,95 @@ +error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate + --> $DIR/anti-fundamental-foreign-type.rs:23:1 + | +LL | impl AntiFundamentalTrait for NonFundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------- + | | + | `NonFundamentalWrapper` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:27:31 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:31:31 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:35:31 + | +LL | impl AntiFundamentalTrait for &mut &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&mut &FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:42:31 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:62:31 + | +LL | impl AntiFundamentalTrait for ::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `::Assoc` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:68:34 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:72:34 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:76:31 + | +LL | impl AntiFundamentalTrait for &mut FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&mut FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:82:31 + | +LL | impl AntiFundamentalTrait for LocalAlias {} + | ^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalWithParam` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:49:46 + | +LL | impl AntiFundamentalWithParam for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalWithParam` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalWithParam` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/anti-fundamental-generic-projection.rs b/tests/ui/coherence/anti-fundamental-generic-projection.rs new file mode 100644 index 0000000000000..26e22f771d3e4 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-generic-projection.rs @@ -0,0 +1,77 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that generic projections cannot bypass #[rustc_anti_fundamental] +// due to normalization failure or compat mode. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, AntiFundamentalWithParam, FundamentalWrapper, +}; + +struct LocalGeneric(T); +struct LocalGeneric2(T); + +trait GenericAssocHelper { + type Assoc; +} + +impl GenericAssocHelper for LocalGeneric { + type Assoc = FundamentalWrapper>; +} + +// ERROR: Generic projections normalize at coherence time, but +// we reject as a hard error because Compat mode is disallowed for anti-fundamental traits. +impl AntiFundamentalWithParam> +//~^ ERROR type parameter `T` must be covered by another type + for as GenericAssocHelper>::Assoc +{ +} + +// ERROR: Generic projection with bounds is similarly hard rejected. +trait BoundedHelper { + type Assoc; +} + +impl BoundedHelper for LocalGeneric2 { + type Assoc = FundamentalWrapper>; +} + +impl AntiFundamentalWithParam> +//~^ ERROR type parameter `T` must be covered by another type + for as BoundedHelper>::Assoc +{ +} + +// Blanket implementation attempting to implement an anti-fundamental trait +// on a projection where the type parameter is constrained by the trait: +// rejected by the orphan rule (E0210) because T is not behind a local type. +trait Helper2 { + type T; +} + +impl AntiFundamentalWithParam for ::T { + //~^ ERROR type parameter `T` must be used as an argument to some local type +} + +impl Helper2 for FundamentalWrapper { + type T = T; +} + +// Blanket implementation of a parameterless anti-fundamental trait (like `Deref`) +// on an associated type projection: rejected both by the orphan rule (E0210) +// and because T is unconstrained (E0207). +trait Helper3 { + type T; +} + +impl AntiFundamentalTrait for ::T { + //~^ ERROR type parameter `T` must be used as an argument to some local type + //~| ERROR the type parameter `T` is not constrained +} + +impl Helper3 for FundamentalWrapper { + type T = T; +} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-generic-projection.stderr b/tests/ui/coherence/anti-fundamental-generic-projection.stderr new file mode 100644 index 0000000000000..b91ae4307149c --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-generic-projection.stderr @@ -0,0 +1,50 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalGeneric<_>`) + --> $DIR/anti-fundamental-generic-projection.rs:25:6 + | +LL | impl AntiFundamentalWithParam> + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, + and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, + where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalGeneric2<_>`) + --> $DIR/anti-fundamental-generic-projection.rs:40:6 + | +LL | impl AntiFundamentalWithParam> + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, + and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, + where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be used as an argument to some local type (e.g., `MyStruct`) + --> $DIR/anti-fundamental-generic-projection.rs:53:6 + | +LL | impl AntiFundamentalWithParam for ::T { + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as an argument to some local type (e.g., `MyStruct`) + --> $DIR/anti-fundamental-generic-projection.rs:68:6 + | +LL | impl AntiFundamentalTrait for ::T { + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/anti-fundamental-generic-projection.rs:68:6 + | +LL | impl AntiFundamentalTrait for ::T { + | ^ unconstrained type parameter + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0207, E0210. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.rs b/tests/ui/coherence/anti-fundamental-invalid-target.rs new file mode 100644 index 0000000000000..49f7f7508ac7d --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.rs @@ -0,0 +1,18 @@ +// Test that `#[rustc_anti_fundamental]` can only be applied to traits. +// The target restriction is enforced declaratively by `ALLOWED_TARGETS` +// in the attribute parser, so applying it to a non-trait is an error. + +#![feature(rustc_attrs)] + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +struct NotATrait; + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +fn also_not_a_trait() {} + +#[rustc_anti_fundamental] +trait Ok {} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.stderr b/tests/ui/coherence/anti-fundamental-invalid-target.stderr new file mode 100644 index 0000000000000..26438d465a81a --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.stderr @@ -0,0 +1,18 @@ +error: the `rustc_anti_fundamental` attribute cannot be used on structs + --> $DIR/anti-fundamental-invalid-target.rs:7:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: the `rustc_anti_fundamental` attribute cannot be used on functions + --> $DIR/anti-fundamental-invalid-target.rs:11:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: aborting due to 2 previous errors + diff --git a/tests/ui/coherence/anti-fundamental-local-trait.rs b/tests/ui/coherence/anti-fundamental-local-trait.rs new file mode 100644 index 0000000000000..33c81e50494f8 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-local-trait.rs @@ -0,0 +1,23 @@ +//@ check-pass + +// Test that `#[rustc_anti_fundamental]` does NOT block local traits. +// If the trait itself is local, orphan rules pass even on fundamental types. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +struct LocalFundamental(T); + +#[rustc_anti_fundamental] +trait AntiFundamentalTrait {} + +struct LocalType; + +// OK: both trait and fundamental type are local. +impl AntiFundamentalTrait for LocalFundamental {} + +// OK: implementing on a local non-fundamental type. +impl AntiFundamentalTrait for LocalType {} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-overlap.rs b/tests/ui/coherence/anti-fundamental-overlap.rs new file mode 100644 index 0000000000000..08e983fba9802 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-overlap.rs @@ -0,0 +1,19 @@ +//@ aux-build: anti_fundamental_trait_lib.rs +//@ dont-require-annotations: NOTE + +// Test that `#[rustc_anti_fundamental]` prevents reporting +// "downstream crates may implement trait" ambiguity notes, +// and instead reports that only upstream crates can add such an impl. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{AntiFundamentalTrait, FundamentalWrapper}; + +trait Trait1 {} +impl Trait1 for T {} +impl Trait1 for FundamentalWrapper { + //~^ ERROR conflicting implementations of trait `Trait1` for type `FundamentalWrapper<_>` + //~| NOTE upstream crates may add a new impl of trait `anti_fundamental_trait_lib::AntiFundamentalTrait` for type `anti_fundamental_trait_lib::FundamentalWrapper<_>` in future versions +} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-overlap.stderr b/tests/ui/coherence/anti-fundamental-overlap.stderr new file mode 100644 index 0000000000000..8d35e7a17d932 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-overlap.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait1` for type `FundamentalWrapper<_>` + --> $DIR/anti-fundamental-overlap.rs:14:1 + | +LL | impl Trait1 for T {} + | ------------------------------------------ first implementation here +LL | impl Trait1 for FundamentalWrapper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FundamentalWrapper<_>` + | + = note: upstream crates may add a new impl of trait `anti_fundamental_trait_lib::AntiFundamentalTrait` for type `anti_fundamental_trait_lib::FundamentalWrapper<_>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs new file mode 100644 index 0000000000000..177874d30432b --- /dev/null +++ b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs @@ -0,0 +1,15 @@ +// Auxiliary crate for anti-fundamental coherence tests. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +pub struct FundamentalWrapper(pub T); + +pub struct NonFundamentalWrapper(pub T); + +#[rustc_anti_fundamental] +pub trait AntiFundamentalTrait {} + +#[rustc_anti_fundamental] +pub trait AntiFundamentalWithParam {} From 269e4c620cb4c8432a2a57cacfad77c11714503e Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 08:49:23 +0000 Subject: [PATCH 08/16] Annotate std traits with #[rustc_anti_fundamental] Mark Deref, DerefMut, DispatchFromDyn, CoerceUnsized, and Receiver with #[rustc_anti_fundamental] to prevent downstream crates from implementing these traits on #[fundamental] types like Box and Pin. --- library/core/src/ops/deref.rs | 3 + library/core/src/ops/unsize.rs | 2 + .../coherence/anti-fundamental-std-traits.rs | 81 +++++++++++++++++ .../anti-fundamental-std-traits.stderr | 87 +++++++++++++++++++ .../pin-unsound-issue-85099-derefmut.rs | 2 +- .../pin-unsound-issue-85099-derefmut.stderr | 12 +-- 6 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 tests/ui/coherence/anti-fundamental-std-traits.rs create mode 100644 tests/ui/coherence/anti-fundamental-std-traits.stderr diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 58bf0e2d73b97..fffbf1210103d 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -136,6 +136,7 @@ use crate::marker::PointeeSized; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[rustc_anti_fundamental] pub const trait Deref: PointeeSized { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -267,6 +268,7 @@ const impl Deref for &mut T { #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[rustc_anti_fundamental] pub const trait DerefMut: [const] Deref + PointeeSized { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] @@ -367,6 +369,7 @@ unsafe impl DerefPure for &mut T {} /// ``` #[lang = "receiver"] #[unstable(feature = "arbitrary_self_types", issue = "44874")] +#[rustc_anti_fundamental] pub trait Receiver: PointeeSized { /// The target type on which the method may be called. #[rustc_diagnostic_item = "receiver_target"] diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index aade68df2b6ce..9179c1761215d 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -33,6 +33,7 @@ use crate::marker::{PointeeSized, Unsize}; /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "coerce_unsized", issue = "18598")] #[lang = "coerce_unsized"] +#[rustc_anti_fundamental] pub trait CoerceUnsized: Sized { // Empty. } @@ -119,6 +120,7 @@ impl, U: PointeeSized> CoerceUnsized<*const U> for * /// [^1]: Formerly known as *object safety*. #[unstable(feature = "dispatch_from_dyn", issue = "none")] #[lang = "dispatch_from_dyn"] +#[rustc_anti_fundamental] pub trait DispatchFromDyn: Sized { // Empty. } diff --git a/tests/ui/coherence/anti-fundamental-std-traits.rs b/tests/ui/coherence/anti-fundamental-std-traits.rs new file mode 100644 index 0000000000000..20d0c0b219b9e --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-std-traits.rs @@ -0,0 +1,81 @@ +//@ check-fail + +// Test that `#[rustc_anti_fundamental]` on std traits (Deref, Receiver, +// CoerceUnsized, DispatchFromDyn) prevents implementing them for foreign +// fundamental types like `Pin`. + +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn)] + +use std::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; +use std::pin::Pin; + +struct LocalType; +struct LocalType2; + +// ERROR: cannot implement Deref for Pin +impl Deref for Pin { + type Target = LocalType; + fn deref(&self) -> &LocalType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement DerefMut for Pin +impl DerefMut for Pin { + fn deref_mut(&mut self) -> &mut LocalType { + unimplemented!() + } +} +//~^^^^^ ERROR cannot implement `DerefMut` for the fundamental type + +// ERROR: cannot implement Receiver for Pin +impl Receiver for Pin { + type Target = LocalType; +} +//~^^^ ERROR cannot implement `std::ops::Receiver` for the fundamental type + +// ERROR: cannot implement CoerceUnsized for Pin +impl CoerceUnsized> for Pin {} +//~^ ERROR cannot implement `CoerceUnsized` for the fundamental type +//~| ERROR the trait bound `LocalType: CoerceUnsized` is not satisfied + +// ERROR: cannot implement DispatchFromDyn for Pin +impl DispatchFromDyn> for Pin {} +//~^ ERROR cannot implement `DispatchFromDyn` for the fundamental type + +struct LocalBoxType; + +// ERROR: cannot implement Deref for Box +impl Deref for Box { + type Target = LocalBoxType; + fn deref(&self) -> &LocalBoxType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement DerefMut for Box +impl DerefMut for Box { + fn deref_mut(&mut self) -> &mut LocalBoxType { + unimplemented!() + } +} +//~^^^^^ ERROR cannot implement `DerefMut` for the fundamental type + +// ERROR: cannot implement Deref for &Pin +impl Deref for &Pin { + type Target = LocalType; + fn deref(&self) -> &LocalType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement Receiver for Box +impl Receiver for Box { + type Target = LocalBoxType; +} +//~^^^ ERROR cannot implement `std::ops::Receiver` for the fundamental type + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-std-traits.stderr b/tests/ui/coherence/anti-fundamental-std-traits.stderr new file mode 100644 index 0000000000000..3aa6ad742b7bc --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-std-traits.stderr @@ -0,0 +1,87 @@ +error: cannot implement `Deref` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:50:16 + | +LL | impl Deref for Box { + | ^^^^^^^^^^^^^^^^^ impl of `Deref` not allowed for `Box` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `Deref` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:67:16 + | +LL | impl Deref for &Pin { + | ^^^^^^^^^^^^^^^ impl of `Deref` not allowed for `&Pin` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `Deref` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:16:16 + | +LL | impl Deref for Pin { + | ^^^^^^^^^^^^^^ impl of `Deref` not allowed for `Pin` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `DerefMut` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:59:19 + | +LL | impl DerefMut for Box { + | ^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Box` + | + = note: `DerefMut` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `DerefMut` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:25:19 + | +LL | impl DerefMut for Pin { + | ^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Pin` + | + = note: `DerefMut` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `std::ops::Receiver` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:33:19 + | +LL | impl Receiver for Pin { + | ^^^^^^^^^^^^^^ impl of `std::ops::Receiver` not allowed for `Pin` + | + = note: `std::ops::Receiver` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `std::ops::Receiver` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:76:19 + | +LL | impl Receiver for Box { + | ^^^^^^^^^^^^^^^^^ impl of `std::ops::Receiver` not allowed for `Box` + | + = note: `std::ops::Receiver` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `CoerceUnsized` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:39:41 + | +LL | impl CoerceUnsized> for Pin {} + | ^^^^^^^^^^^^^^ impl of `CoerceUnsized` not allowed for `Pin` + | + = note: `CoerceUnsized` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error[E0277]: the trait bound `LocalType: CoerceUnsized` is not satisfied + --> $DIR/anti-fundamental-std-traits.rs:39:1 + | +LL | impl CoerceUnsized> for Pin {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the nightly-only, unstable trait `CoerceUnsized` is not implemented for `LocalType` + --> $DIR/anti-fundamental-std-traits.rs:12:1 + | +LL | struct LocalType; + | ^^^^^^^^^^^^^^^^ + +error: cannot implement `DispatchFromDyn` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:44:43 + | +LL | impl DispatchFromDyn> for Pin {} + | ^^^^^^^^^^^^^^ impl of `DispatchFromDyn` not allowed for `Pin` + | + = note: `DispatchFromDyn` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index e8c3bbba1e458..a32a61b767d4e 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -42,7 +42,7 @@ impl<'a, Fut: Future> SomeTrait<'a, Fut> for Fut { } impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { -//~^ ERROR: conflicting implementations of trait `DerefMut` +//~^ ERROR: cannot implement `DerefMut` for the fundamental type fn deref_mut<'c>( self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr index 2bcd92b76a09d..3e413d9ef9e1b 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -1,14 +1,10 @@ -error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>` - --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1 +error: cannot implement `DerefMut` for the fundamental type `Pin<&dyn SomeTrait<'_, Fut>>` + --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:32 | LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Pin<&dyn SomeTrait<'_, Fut>>` | - = note: conflicting implementation in crate `core`: - - impl DerefMut for Pin - where as pin::helper::PinDerefMutHelper>::Target == as Deref>::Target, Ptr: Deref, pin::helper::PinHelper: pin::helper::PinDerefMutHelper, pin::helper::PinHelper: ?Sized; - = note: upstream crates may add a new impl of trait `std::pin::helper::PinDerefMutHelper` for type `std::pin::helper::PinHelper<&dyn SomeTrait<'_, _>>` in future versions + = note: `DerefMut` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0119`. From 8df29814a0463c3b4b67d31900f727a08c0d34a3 Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 09:32:12 +0000 Subject: [PATCH 09/16] Remove PinDerefMutHelper We marked DerefMut anti-fundamental, so the PinHelper indirection is no longer needed to prevent downstream users from implementing DerefMut on Pin. --- compiler/rustc_span/src/symbol.rs | 1 - .../src/error_reporting/traits/suggestions.rs | 16 ---- library/core/src/pin.rs | 80 ++----------------- ...y.run2-{closure#0}.Inline.panic-abort.diff | 68 ++++++++-------- ....run2-{closure#0}.Inline.panic-unwind.diff | 68 ++++++++-------- tests/ui/deref/pin-impl-deref.rs | 4 +- tests/ui/deref/pin-impl-deref.stderr | 18 +++-- 7 files changed, 85 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2d0b52c3a8c18..2c538d809936f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -271,7 +271,6 @@ symbols! { PartialEq, PartialOrd, Pending, - PinDerefMutHelper, PinMacroHelper, Pointer, Poll, 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 7921250a85a9e..9ffb043934274 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4432,23 +4432,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // can do about it. As far as they are concerned, `?` is compiler magic. return; } - if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) { - let parent_predicate = - self.resolve_vars_if_possible(data.derived.parent_trait_pred); - // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. - - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.derived.parent_code, - obligated_types, - seen_requirements, - ); - return; - } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = tcx.short_string( diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 58e63ff04af15..bb5b0fd50c2dc 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1691,89 +1691,23 @@ const impl Deref for Pin { } } -mod helper { - /// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`. - /// - /// The `Pin` type implements the unsafe trait `PinSafePointer`, which essentially requires - /// that the type does not have a malicious `Deref` or `DerefMut` impl. However, without this - /// helper module, downstream crates are able to write `impl DerefMut for Pin` as - /// long as it does not overlap with the impl provided by stdlib. This is because `Pin` is - /// `#[fundamental]`, so stdlib promises to never implement traits for `Pin` that it does not - /// implement today. - /// - /// However, this is problematic. Downstream crates could implement `DerefMut` for - /// `Pin<&LocalType>`, and they could do so maliciously. To prevent this, the implementation for - /// `Pin` delegates to this helper module. Since `helper::Pin` is not `#[fundamental]`, the - /// orphan rules assume that stdlib might implement `helper::DerefMut` for `helper::Pin<&_>` in - /// the future. Because of this, downstream crates can no longer provide an implementation of - /// `DerefMut` for `Pin<&_>`, as it might overlap with a trait impl that, according to the - /// orphan rules, the stdlib could introduce without a breaking change in a future release. - /// - /// See for the issue this fixes. - #[repr(transparent)] - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[allow(missing_debug_implementations)] - pub struct PinHelper { - pointer: Ptr, - } - - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - #[rustc_diagnostic_item = "PinDerefMutHelper"] - pub const trait PinDerefMutHelper { - type Target: ?Sized; - fn deref_mut(&mut self) -> &mut Self::Target; - } - - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - const impl PinDerefMutHelper for PinHelper - where - Ptr::Target: crate::marker::Unpin, - { - type Target = Ptr::Target; - - #[inline(always)] - fn deref_mut(&mut self) -> &mut Ptr::Target { - &mut self.pointer - } - } -} - -#[stable(feature = "pin", since = "1.33.0")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[cfg(not(doc))] -const impl DerefMut for Pin -where - Ptr: [const] Deref, - helper::PinHelper: [const] helper::PinDerefMutHelper, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Ptr::Target { - // SAFETY: Pin and PinHelper have the same layout, so this is equivalent to - // `&mut self.pointer` which is safe because `Target: Unpin`. - helper::PinDerefMutHelper::deref_mut(unsafe { - &mut *(self as *mut Pin as *mut helper::PinHelper) - }) - } -} - /// The `Target` type is restricted to `Unpin` types as it's not safe to obtain a mutable reference /// to a pinned value. /// /// For soundness reasons, implementations of `DerefMut` for `Pin` are rejected even when `T` is /// a local type not covered by this impl block. (Since `Pin` is [fundamental], such implementations -/// would normally be possible.) +/// would normally be possible.) This is enforced by the `#[rustc_anti_fundamental]` attribute on +/// the `DerefMut` trait. /// /// [fundamental]: ../../reference/items/implementations.html#r-items.impl.trait.fundamental #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[cfg(doc)] const impl DerefMut for Pin where Ptr: [const] DerefMut, - ::Target: Unpin, + Ptr::Target: Unpin, { + #[inline] fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } @@ -1953,9 +1887,9 @@ unsafe impl<'a, T: ?Sized> PinSafePointer for &'a mut T {} // The `Pin

` type only implements `DerefMut` when `P: DerefMut` and // `P::Target: Unpin`, so normally downstream crates would be able to provide // an implementation of `DerefMut` for `Pin` when `LocalType` does -// not satisfy those conditions. However, a special hack is used to prevent -// such downstream implementations, so this is not a problem. See -// [#145608](https://github.com/rust-lang/rust/pull/145608) for details. +// not satisfy those conditions. However, `#[rustc_anti_fundamental]` is used to +// prevent such downstream implementations, so this is not a problem. See +// [#160391](https://github.com/rust-lang/rust/pull/160391) for details. // // Conversely, downstream crates are able to implement `Clone`, `Debug` and // `Display` for `Pin` as long as `LocalType` does not implement diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 4b117a453c326..4ad4946c00099 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -179,23 +181,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb11, 1: bb12, otherwise: bb4]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb11, 1: bb12, otherwise: bb4]; + } + bb4: { @@ -262,10 +259,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -274,17 +271,16 @@ + } + + bb11: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index c365aee05f4ec..09c6199fff29e 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -190,23 +192,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb16, 1: bb17, otherwise: bb6]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb16, 1: bb17, otherwise: bb6]; } - bb5 (cleanup): { @@ -295,10 +292,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -307,17 +304,16 @@ + } + + bb16: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> bb10; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> bb10; + } + + bb17: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/ui/deref/pin-impl-deref.rs b/tests/ui/deref/pin-impl-deref.rs index ccd8d0dfc72ae..b1dc8dea3f248 100644 --- a/tests/ui/deref/pin-impl-deref.rs +++ b/tests/ui/deref/pin-impl-deref.rs @@ -22,7 +22,7 @@ impl MyPinType { fn impl_deref_mut(_: impl DerefMut) {} fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) { impl_deref_mut(r_unpin) - //~^ ERROR: the trait bound `&MyUnpinType: DerefMut` is not satisfied + //~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied } fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { impl_deref_mut(r_unpin) @@ -30,7 +30,7 @@ fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { fn pin_impl_ref(r_pin: Pin<&MyPinType>) { impl_deref_mut(r_pin) //~^ ERROR: `PhantomPinned` cannot be unpinned - //~| ERROR: the trait bound `&MyPinType: DerefMut` is not satisfied + //~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied } fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) { impl_deref_mut(r_pin) diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr index 4143d66f42723..106654641a117 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -1,34 +1,40 @@ -error[E0277]: the trait bound `&MyUnpinType: DerefMut` is not satisfied +error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied --> $DIR/pin-impl-deref.rs:24:20 | LL | impl_deref_mut(r_unpin) - | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `&MyUnpinType` + | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>` | | | required by a bound introduced by this call | - = note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType` = note: required for `Pin<&MyUnpinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 | LL | fn impl_deref_mut(_: impl DerefMut) {} | ^^^^^^^^ required by this bound in `impl_deref_mut` +help: consider mutably borrowing here + | +LL | impl_deref_mut(&mut r_unpin) + | ++++ -error[E0277]: the trait bound `&MyPinType: DerefMut` is not satisfied +error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied --> $DIR/pin-impl-deref.rs:31:20 | LL | impl_deref_mut(r_pin) - | -------------- ^^^^^ the trait `DerefMut` is not implemented for `&MyPinType` + | -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>` | | | required by a bound introduced by this call | - = note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType` = note: required for `Pin<&MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 | LL | fn impl_deref_mut(_: impl DerefMut) {} | ^^^^^^^^ required by this bound in `impl_deref_mut` +help: consider mutably borrowing here + | +LL | impl_deref_mut(&mut r_pin) + | ++++ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/pin-impl-deref.rs:31:20 From ca9f874f260a0216f1c3a8bc8dc3f8898ff5ff9e Mon Sep 17 00:00:00 2001 From: lumi Date: Tue, 18 Aug 2026 19:31:36 +0200 Subject: [PATCH 10/16] rustc_hir_analysis: register all clauses of DefKind::Fn as obligations --- compiler/rustc_hir_analysis/src/check/check.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3f88696fb2c2c..936b44019c62c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -818,6 +818,23 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().clauses_of(def_id); tcx.ensure_ok().fn_sig(def_id); tcx.ensure_ok().codegen_fn_attrs(def_id); + let clauses = tcx.clauses_of(def_id); + let param_env = tcx.param_env(def_id); + res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + for (clause, span) in clauses.clauses { + wfcx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + *span, + def_id, + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))), + ), + param_env, + *clause, + )); + } + Ok(()) + })); if let Some(i) = tcx.intrinsic(def_id) { intrinsic::check_intrinsic_type( tcx, From 11258a60790b01d688d4bcae2cda3484af71ca8f Mon Sep 17 00:00:00 2001 From: lumi Date: Wed, 19 Aug 2026 22:30:02 +0200 Subject: [PATCH 11/16] rustc_hir_analysis: move function clause checks into its own function --- .../rustc_hir_analysis/src/check/check.rs | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 936b44019c62c..bed605f1a44c7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -756,6 +756,26 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } +fn check_function_clauses(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let clauses = tcx.clauses_of(def_id); + let param_env = tcx.param_env(def_id); + enter_wf_checking_ctxt(tcx, def_id, |wfcx| { + for (clause, span) in clauses.clauses { + wfcx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + *span, + def_id, + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))), + ), + param_env, + *clause, + )); + } + Ok(()) + }) +} + pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); let generics = tcx.generics_of(def_id); @@ -815,26 +835,9 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), DefKind::Fn => { tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); - tcx.ensure_ok().clauses_of(def_id); tcx.ensure_ok().fn_sig(def_id); tcx.ensure_ok().codegen_fn_attrs(def_id); - let clauses = tcx.clauses_of(def_id); - let param_env = tcx.param_env(def_id); - res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| { - for (clause, span) in clauses.clauses { - wfcx.register_obligation(Obligation::new( - tcx, - ObligationCause::new( - *span, - def_id, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))), - ), - param_env, - *clause, - )); - } - Ok(()) - })); + res = res.and(check_function_clauses(tcx, def_id)); if let Some(i) = tcx.intrinsic(def_id) { intrinsic::check_intrinsic_type( tcx, From 17a596dbaa3b6167a6654c506f1c8e04559763e3 Mon Sep 17 00:00:00 2001 From: lumi Date: Wed, 19 Aug 2026 23:47:18 +0200 Subject: [PATCH 12/16] tests: add test for rust-lang/rust#151319 --- tests/ui/trait-bounds/issue-151319.rs | 9 +++++++++ tests/ui/trait-bounds/issue-151319.stderr | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/ui/trait-bounds/issue-151319.rs create mode 100644 tests/ui/trait-bounds/issue-151319.stderr diff --git a/tests/ui/trait-bounds/issue-151319.rs b/tests/ui/trait-bounds/issue-151319.rs new file mode 100644 index 0000000000000..d2ad7e38fb29a --- /dev/null +++ b/tests/ui/trait-bounds/issue-151319.rs @@ -0,0 +1,9 @@ +//@compile-flags: -Znext-solver=globally --crate-type=lib +pub trait Trait { + type Assoc; +} + +pub fn foo + Trait>() { + //~^ ERROR type annotations needed: cannot satisfy `::Assoc == u32` [E0284] + const {} +} diff --git a/tests/ui/trait-bounds/issue-151319.stderr b/tests/ui/trait-bounds/issue-151319.stderr new file mode 100644 index 0000000000000..ecb48d60b9b7c --- /dev/null +++ b/tests/ui/trait-bounds/issue-151319.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `::Assoc == u32` + --> $DIR/issue-151319.rs:6:21 + | +LL | pub fn foo + Trait>() { + | ^^^^^^^^^^^ cannot satisfy `::Assoc == u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. From d02ad6b9270c429387dbc1f274ee54bdd31bfe93 Mon Sep 17 00:00:00 2001 From: lumi Date: Thu, 20 Aug 2026 00:22:17 +0200 Subject: [PATCH 13/16] tests: rename issue-151319 to check-fn-clauses-issue-151319 --- .../{issue-151319.rs => check-fn-clauses-issue-151319.rs} | 0 ...issue-151319.stderr => check-fn-clauses-issue-151319.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/trait-bounds/{issue-151319.rs => check-fn-clauses-issue-151319.rs} (100%) rename tests/ui/trait-bounds/{issue-151319.stderr => check-fn-clauses-issue-151319.stderr} (87%) diff --git a/tests/ui/trait-bounds/issue-151319.rs b/tests/ui/trait-bounds/check-fn-clauses-issue-151319.rs similarity index 100% rename from tests/ui/trait-bounds/issue-151319.rs rename to tests/ui/trait-bounds/check-fn-clauses-issue-151319.rs diff --git a/tests/ui/trait-bounds/issue-151319.stderr b/tests/ui/trait-bounds/check-fn-clauses-issue-151319.stderr similarity index 87% rename from tests/ui/trait-bounds/issue-151319.stderr rename to tests/ui/trait-bounds/check-fn-clauses-issue-151319.stderr index ecb48d60b9b7c..f201eae959ec6 100644 --- a/tests/ui/trait-bounds/issue-151319.stderr +++ b/tests/ui/trait-bounds/check-fn-clauses-issue-151319.stderr @@ -1,5 +1,5 @@ error[E0284]: type annotations needed: cannot satisfy `::Assoc == u32` - --> $DIR/issue-151319.rs:6:21 + --> $DIR/check-fn-clauses-issue-151319.rs:6:21 | LL | pub fn foo + Trait>() { | ^^^^^^^^^^^ cannot satisfy `::Assoc == u32` From 9a29c7911bf0162251a29240abecc880ef78ab1a Mon Sep 17 00:00:00 2001 From: lumi Date: Thu, 27 Aug 2026 19:55:22 +0200 Subject: [PATCH 14/16] rustc_hir_analysis: change ObligationCauseCode for check_function_clauses --- compiler/rustc_hir_analysis/src/check/check.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index bed605f1a44c7..33e5992e1eda3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -763,11 +763,7 @@ fn check_function_clauses(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err for (clause, span) in clauses.clauses { wfcx.register_obligation(Obligation::new( tcx, - ObligationCause::new( - *span, - def_id, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))), - ), + ObligationCause::new(*span, def_id, ObligationCauseCode::WellFormed(None)), param_env, *clause, )); From 2fd2aba67f6646ce16cb4bb72e4bb6866d3c54aa Mon Sep 17 00:00:00 2001 From: lumi Date: Thu, 27 Aug 2026 20:23:53 +0200 Subject: [PATCH 15/16] tests: fix a few of the ui tests that were broken by check_function_clauses --- .../associated-inherent-types/issue-109789.rs | 1 + .../issue-109789.stderr | 12 ++- .../issue-111404-1.rs | 1 + .../issue-111404-1.stderr | 12 ++- .../associated-inherent-types/regionck-2.rs | 6 +- .../regionck-2.stderr | 18 +++- .../duplicate-bound-err.rs | 13 +-- .../duplicate-bound-err.stderr | 100 ++++++++++-------- .../assoc-type-unsatisfied-bound.rs | 1 + .../assoc-type-unsatisfied-bound.stderr | 19 +++- tests/ui/associated-types/issue-59324.rs | 1 + tests/ui/associated-types/issue-59324.stderr | 15 ++- .../projection-dyn-associated-type.rs | 1 + .../projection-dyn-associated-type.stderr | 17 ++- 14 files changed, 155 insertions(+), 62 deletions(-) diff --git a/tests/ui/associated-inherent-types/issue-109789.rs b/tests/ui/associated-inherent-types/issue-109789.rs index e3c490b2dc842..d24e7dbd35ecc 100644 --- a/tests/ui/associated-inherent-types/issue-109789.rs +++ b/tests/ui/associated-inherent-types/issue-109789.rs @@ -18,6 +18,7 @@ impl Other for u32 {} fn bar(_: Foo fn(&'a ())>::Assoc) {} //~^ ERROR mismatched types //~| ERROR mismatched types +//~| ERROR mismatched types //~| ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error diff --git a/tests/ui/associated-inherent-types/issue-109789.stderr b/tests/ui/associated-inherent-types/issue-109789.stderr index db860a64826d6..b9d851d0cc4aa 100644 --- a/tests/ui/associated-inherent-types/issue-109789.stderr +++ b/tests/ui/associated-inherent-types/issue-109789.stderr @@ -17,6 +17,16 @@ LL | fn bar(_: Foo fn(&'a ())>::Assoc) {} found struct `Foo fn(&'a ())>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0308]: mismatched types + --> $DIR/issue-109789.rs:18:11 + | +LL | fn bar(_: Foo fn(&'a ())>::Assoc) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected struct `Foo` + found struct `Foo fn(&'a ())>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: higher-ranked subtype error --> $DIR/issue-109789.rs:18:1 | @@ -39,6 +49,6 @@ LL | fn bar(_: Foo fn(&'a ())>::Assoc) {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-inherent-types/issue-111404-1.rs b/tests/ui/associated-inherent-types/issue-111404-1.rs index cad6d48b1c5af..0c20cd443aa2d 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.rs +++ b/tests/ui/associated-inherent-types/issue-111404-1.rs @@ -10,6 +10,7 @@ impl<'a> Foo { fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} //~^ ERROR mismatched types [E0308] //~| ERROR mismatched types [E0308] +//~| ERROR mismatched types [E0308] //~| ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr index 9a5b69497c0cf..b2a64fac26030 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr @@ -17,6 +17,16 @@ LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} found struct `Foo fn(&'b ())>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0308]: mismatched types + --> $DIR/issue-111404-1.rs:10:11 + | +LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected struct `Foo` + found struct `Foo fn(&'b ())>` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: higher-ranked subtype error --> $DIR/issue-111404-1.rs:10:1 | @@ -37,6 +47,6 @@ error: higher-ranked subtype error LL | fn bar(_: fn(Foo fn(Foo::Assoc)>::Assoc)) {} | ^ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-inherent-types/regionck-2.rs b/tests/ui/associated-inherent-types/regionck-2.rs index 573dd359bf2b0..dcbc7139656d8 100644 --- a/tests/ui/associated-inherent-types/regionck-2.rs +++ b/tests/ui/associated-inherent-types/regionck-2.rs @@ -9,7 +9,9 @@ impl Lexer<'static> { type Cursor = (); } -fn test(_: Lexer::Cursor) {} //~ ERROR mismatched types -//~^ ERROR: lifetime may not live long enough +fn test(_: Lexer::Cursor) {} +//~^ ERROR: mismatched types +//~| ERROR: mismatched types +//~| ERROR: lifetime may not live long enough fn main() {} diff --git a/tests/ui/associated-inherent-types/regionck-2.stderr b/tests/ui/associated-inherent-types/regionck-2.stderr index 82f5c6a72c008..9beb34f822666 100644 --- a/tests/ui/associated-inherent-types/regionck-2.stderr +++ b/tests/ui/associated-inherent-types/regionck-2.stderr @@ -13,6 +13,22 @@ LL | fn test(_: Lexer::Cursor) {} | ^^^^^ = note: ...does not necessarily outlive the static lifetime +error[E0308]: mismatched types + --> $DIR/regionck-2.rs:12:12 + | +LL | fn test(_: Lexer::Cursor) {} + | ^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected struct `Lexer<'static>` + found struct `Lexer<'_>` +note: the anonymous lifetime defined here... + --> $DIR/regionck-2.rs:12:12 + | +LL | fn test(_: Lexer::Cursor) {} + | ^^^^^ + = note: ...does not necessarily outlive the static lifetime + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: lifetime may not live long enough --> $DIR/regionck-2.rs:12:1 | @@ -22,6 +38,6 @@ LL | fn test(_: Lexer::Cursor) {} | | has type `Lexer<'1>::Cursor` | requires that `'1` must outlive `'static` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 56403fdf6630c..b0e9387ea227b 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,10 +1,6 @@ //@ edition: 2024 -#![feature( - min_generic_const_args, - type_alias_impl_trait, - return_type_notation -)] +#![feature(min_generic_const_args, type_alias_impl_trait, return_type_notation)] #![expect(incomplete_features)] #![allow(refining_impl_trait_internal)] @@ -74,12 +70,13 @@ impl Trait for u32 { } fn uncallable(_: impl Iterator) {} +//~^ ERROR type annotations needed fn uncallable_const(_: impl Trait) {} +//~^ ERROR type annotations needed -fn uncallable_rtn( - _: impl Trait, foo(..): Trait> -) {} +fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +//~^ ERROR type annotations needed type MustFail = dyn Iterator; //~^ ERROR [E0719] diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index f685b01cd8cc3..0b138adfd9103 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:14:5 + --> $DIR/duplicate-bound-err.rs:10:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | ++++++++++++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:18:5 + --> $DIR/duplicate-bound-err.rs:14:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | ++++++++++++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:22:5 + --> $DIR/duplicate-bound-err.rs:18:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | ++++++++++++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:26:51 + --> $DIR/duplicate-bound-err.rs:22:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:28:51 + --> $DIR/duplicate-bound-err.rs:24:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:30:57 + --> $DIR/duplicate-bound-err.rs:26:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:33:14 + --> $DIR/duplicate-bound-err.rs:29:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:35:14 + --> $DIR/duplicate-bound-err.rs:31:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:37:14 + --> $DIR/duplicate-bound-err.rs:33:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:40:18 + --> $DIR/duplicate-bound-err.rs:36:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:45:20 + --> $DIR/duplicate-bound-err.rs:41:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:107:17 + --> $DIR/duplicate-bound-err.rs:104:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here | note: the method call chain might not have had the expected associated types - --> $DIR/duplicate-bound-err.rs:110:16 + --> $DIR/duplicate-bound-err.rs:107:16 | LL | [2u32].into_iter() | ------ ^^^^^^^^^^^ `Iterator::Item` is `u32` here @@ -117,19 +117,37 @@ LL | [2u32].into_iter() | this expression has type `[u32; 1]` error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:107:17 + --> $DIR/duplicate-bound-err.rs:104:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:103:31 + --> $DIR/duplicate-bound-err.rs:100:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` +error[E0284]: type annotations needed: cannot satisfy ` as Iterator>::Item == i32` + --> $DIR/duplicate-bound-err.rs:72:32 + | +LL | fn uncallable(_: impl Iterator) {} + | ^^^^^^^^^^ cannot satisfy ` as Iterator>::Item == i32` + +error[E0284]: type annotations needed: cannot satisfy ` as Trait>::ASSOC == 3` + --> $DIR/duplicate-bound-err.rs:75:35 + | +LL | fn uncallable_const(_: impl Trait) {} + | ^^^^^^^^^ cannot satisfy ` as Trait>::ASSOC == 3` + +error[E0284]: type annotations needed: cannot satisfy `, foo(..) : Trait> as Trait>::foo(..) } as Trait>::ASSOC == 3` + --> $DIR/duplicate-bound-err.rs:78:48 + | +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ cannot satisfy `, foo(..) : Trait> as Trait>::foo(..) } as Trait>::ASSOC == 3` + error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:84:42 + --> $DIR/duplicate-bound-err.rs:81:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -137,7 +155,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bindings for `Item` - --> $DIR/duplicate-bound-err.rs:84:17 + --> $DIR/duplicate-bound-err.rs:81:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -146,7 +164,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:92:43 + --> $DIR/duplicate-bound-err.rs:89:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -154,7 +172,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated constant bindings for `ASSOC` - --> $DIR/duplicate-bound-err.rs:92:18 + --> $DIR/duplicate-bound-err.rs:89:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -163,7 +181,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:96:43 + --> $DIR/duplicate-bound-err.rs:93:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -171,7 +189,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:99:43 + --> $DIR/duplicate-bound-err.rs:96:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -179,7 +197,7 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:115:16 + --> $DIR/duplicate-bound-err.rs:112:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -187,13 +205,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:76:32 + --> $DIR/duplicate-bound-err.rs:72:32 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:116:16 + --> $DIR/duplicate-bound-err.rs:113:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -201,13 +219,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:76:44 + --> $DIR/duplicate-bound-err.rs:72:44 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:117:22 + --> $DIR/duplicate-bound-err.rs:114:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -217,13 +235,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:78:46 + --> $DIR/duplicate-bound-err.rs:75:46 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:118:22 + --> $DIR/duplicate-bound-err.rs:115:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -233,13 +251,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:78:35 + --> $DIR/duplicate-bound-err.rs:75:35 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:119:20 + --> $DIR/duplicate-bound-err.rs:116:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -249,15 +267,13 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:81:61 + --> $DIR/duplicate-bound-err.rs:78:75 | -LL | fn uncallable_rtn( - | -------------- required by a bound in this function -LL | _: impl Trait, foo(..): Trait> - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:120:20 + --> $DIR/duplicate-bound-err.rs:117:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -267,14 +283,12 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:81:34 + --> $DIR/duplicate-bound-err.rs:78:48 | -LL | fn uncallable_rtn( - | -------------- required by a bound in this function -LL | _: impl Trait, foo(..): Trait> - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` -error: aborting due to 25 previous errors +error: aborting due to 28 previous errors -Some errors have detailed explanations: E0271, E0277, E0282, E0719. +Some errors have detailed explanations: E0271, E0277, E0282, E0284, E0719. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-types/assoc-type-unsatisfied-bound.rs b/tests/ui/associated-types/assoc-type-unsatisfied-bound.rs index 76a93eed7b663..85b7c194e24bb 100644 --- a/tests/ui/associated-types/assoc-type-unsatisfied-bound.rs +++ b/tests/ui/associated-types/assoc-type-unsatisfied-bound.rs @@ -3,6 +3,7 @@ fn add_state(op: ::State) { //~^ ERROR `isize: HasState` is not satisfied //~| ERROR `isize: HasState` is not satisfied +//~| ERROR `isize: HasState` is not satisfied } trait HasState { diff --git a/tests/ui/associated-types/assoc-type-unsatisfied-bound.stderr b/tests/ui/associated-types/assoc-type-unsatisfied-bound.stderr index 3e318fcac503a..b79fdab9cd869 100644 --- a/tests/ui/associated-types/assoc-type-unsatisfied-bound.stderr +++ b/tests/ui/associated-types/assoc-type-unsatisfied-bound.stderr @@ -5,7 +5,7 @@ LL | fn add_state(op: ::State) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` | help: this trait has no implementations, consider adding one - --> $DIR/assoc-type-unsatisfied-bound.rs:8:1 + --> $DIR/assoc-type-unsatisfied-bound.rs:9:1 | LL | trait HasState { | ^^^^^^^^^^^^^^ @@ -17,12 +17,25 @@ LL | fn add_state(op: ::State) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` | help: this trait has no implementations, consider adding one - --> $DIR/assoc-type-unsatisfied-bound.rs:8:1 + --> $DIR/assoc-type-unsatisfied-bound.rs:9:1 | LL | trait HasState { | ^^^^^^^^^^^^^^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error[E0277]: the trait bound `isize: HasState` is not satisfied + --> $DIR/assoc-type-unsatisfied-bound.rs:3:18 + | +LL | fn add_state(op: ::State) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` + | +help: this trait has no implementations, consider adding one + --> $DIR/assoc-type-unsatisfied-bound.rs:9:1 + | +LL | trait HasState { + | ^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-59324.rs b/tests/ui/associated-types/issue-59324.rs index f9b310f6f9b31..b8acd633427b7 100644 --- a/tests/ui/associated-types/issue-59324.rs +++ b/tests/ui/associated-types/issue-59324.rs @@ -22,6 +22,7 @@ pub trait ThriftService: fn with_factory(factory: dyn ThriftService<()>) {} //~^ ERROR the trait bound `(): Foo` is not satisfied //~| ERROR the trait bound `(): Foo` is not satisfied +//~| ERROR the trait bound `(): Foo` is not satisfied //~| ERROR cannot be known at compilation time fn main() {} diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr index 929238dc29b15..7c92def535901 100644 --- a/tests/ui/associated-types/issue-59324.stderr +++ b/tests/ui/associated-types/issue-59324.stderr @@ -11,6 +11,18 @@ help: consider further restricting type parameter `Bug` with trait `Foo` LL | pub trait ThriftService: | +++++ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/issue-59324.rs:22:29 + | +LL | fn with_factory(factory: dyn ThriftService<()>) {} + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-59324.rs:3:1 + | +LL | pub trait Foo: NotFoo { + | ^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `Bug: Foo` is not satisfied --> $DIR/issue-59324.rs:15:5 | @@ -32,6 +44,7 @@ help: this trait has no implementations, consider adding one | LL | pub trait Foo: NotFoo { | ^^^^^^^^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `Bug: Foo` is not satisfied --> $DIR/issue-59324.rs:15:5 @@ -79,6 +92,6 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn with_factory(factory: &dyn ThriftService<()>) {} | + -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/projection-dyn-associated-type.rs b/tests/ui/associated-types/projection-dyn-associated-type.rs index 32328f8793c71..b446ff5b863b3 100644 --- a/tests/ui/associated-types/projection-dyn-associated-type.rs +++ b/tests/ui/associated-types/projection-dyn-associated-type.rs @@ -23,6 +23,7 @@ pub fn foo<'a>( ) -> &'a ::Assoc { //~^ ERROR the trait bound `(dyn B + 'static): Mirror` is not satisfied [E0277] //~| ERROR the trait bound `(dyn B + 'static): Mirror` is not satisfied [E0277] + //~| ERROR the trait bound `(dyn B + 'static): Mirror` is not satisfied [E0277] static } //~ ERROR expected identifier, found `}` diff --git a/tests/ui/associated-types/projection-dyn-associated-type.stderr b/tests/ui/associated-types/projection-dyn-associated-type.stderr index 58eb8cff163db..3c711c416bbc6 100644 --- a/tests/ui/associated-types/projection-dyn-associated-type.stderr +++ b/tests/ui/associated-types/projection-dyn-associated-type.stderr @@ -1,5 +1,5 @@ error: expected identifier, found `}` - --> $DIR/projection-dyn-associated-type.rs:27:1 + --> $DIR/projection-dyn-associated-type.rs:28:1 | LL | } | ^ expected identifier @@ -54,7 +54,20 @@ LL | impl Mirror for A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors; 1 warning emitted +error[E0277]: the trait bound `(dyn B + 'static): Mirror` is not satisfied + --> $DIR/projection-dyn-associated-type.rs:23:6 + | +LL | ) -> &'a ::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Mirror` is not implemented for `(dyn B + 'static)` + | +help: the trait `Mirror` is implemented for `dyn A` + --> $DIR/projection-dyn-associated-type.rs:14:1 + | +LL | impl Mirror for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors; 1 warning emitted Some errors have detailed explanations: E0207, E0277. For more information about an error, try `rustc --explain E0207`. From 09cc81270d66deb83e4abb9f0a3f1696917ad3c7 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Thu, 3 Sep 2026 19:50:22 +0700 Subject: [PATCH 16/16] fix build for crater --- compiler/rustc_borrowck/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8672b7cb6b6fe..c347e933013f2 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2097,7 +2097,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ProjectionKind::Subslice { .. } | ProjectionKind::Downcast(..) | ProjectionKind::OpaqueCast(..) - | ProjectionKind::UnwrapUnsafeBinder(..), + | ProjectionKind::UnwrapUnsafeBinder(..) + | ProjectionKind::PhantomDeref, } => maybe_uninits.contains(mpi).then_some(mpi), LookupResult::None => bug!("should have move path for every Local"),