diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index a9d6b31e2ee2f..f53702f3fde13 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -7,7 +7,7 @@ use rustc_hir::Mutability; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Body, Local, Location, traversal}; +use rustc_middle::mir::{self, Body, Local, Location, PlaceElem, traversal}; use rustc_middle::ty::data_structures::IndexSet; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; @@ -265,6 +265,154 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { } idx } + + fn insert_borrows( + &mut self, + location: Location, + borrows: SmallVec<[BorrowData<'tcx>; 1]>, + ) -> SmallVec<[BorrowIndex; 1]> { + let mut idxs = SmallVec::<[BorrowIndex; 1]>::with_capacity(borrows.len()); + // FIXME(reborrow): why doesn't SmallVec offer reserve? + for borrow in borrows { + idxs.push(self.borrows.push(borrow)); + } + match self.location_map.entry(location) { + Entry::Occupied(entry) => { + bug!( + "Inserting borrows {idxs:?} at {location:?} attempted to override an existing list {entry:?}" + ); + } + Entry::Vacant(entry) => { + entry.insert(idxs.clone()); + } + } + idxs + } + + fn gather_reborrows( + &mut self, + v: &mut SmallVec<[BorrowData<'tcx>; 1]>, + kind: mir::BorrowKind, + location: Location, + target_adt: ty::AdtDef<'tcx>, + target_args: &'tcx ty::List>, + target_place: mir::Place<'tcx>, + source_adt: ty::AdtDef<'tcx>, + source_args: &'tcx ty::List>, + source_place: mir::Place<'tcx>, + ) { + let mut did_reborrow = false; + for (source_idx, source_field) in source_adt.all_fields().enumerate() { + let source_field_ty = source_field.ty(self.tcx, source_args).skip_norm_wip(); + match source_field_ty.kind() { + ty::Ref(source_region, _, source_mutability) if source_mutability.is_mut() => { + if source_region.is_static() { + bug!( + "Cannot implement Reborrow on a type containing a &'static mut T field" + ); + } + let Some((target_idx, target_field)) = target_adt + .all_fields() + .enumerate() + .find(|(_, f)| f.name == source_field.name) + else { + // Reborrow dropped this field. + continue; + }; + let ty::Ref(target_region, _, _) = + target_field.ty(self.tcx, target_args).skip_norm_wip().kind() + else { + bug!( + "Reborrow source field type is &mut T but target field is not a reference" + ); + }; + + did_reborrow = true; + let source_field_deref_place = source_place.project_deeper( + &[PlaceElem::Field(source_idx.into(), source_field_ty), PlaceElem::Deref], + self.tcx, + ); + let target_field_place = target_place.project_to_field( + target_idx.into(), + &self.body.local_decls, + self.tcx, + ); + v.push(BorrowData { + kind, + region: target_region.as_var(), + reserve_location: location, + activation_location: TwoPhaseActivation::NotTwoPhase, + borrowed_place: source_field_deref_place, + assigned_place: target_field_place, + }); + } + ty::Adt(source_field_adt, source_field_args) + if source_field_args.get(0).is_some_and(|f| f.as_region().is_some()) + && !self.tcx.type_is_copy_modulo_regions( + self.body.typing_env(self.tcx), + self.tcx.erase_and_anonymize_regions(source_field_ty), + ) => + { + let Some((target_idx, target_field)) = target_adt + .all_fields() + .enumerate() + .find(|(_, f)| f.name == source_field.name) + else { + // Reborrow dropped this field. + continue; + }; + let ty::Adt(target_field_adt, target_field_args) = + target_field.ty(self.tcx, target_args).skip_norm_wip().kind() + else { + bug!("Reborrow source field type is a !Copy ADT but target field is not"); + }; + + did_reborrow = true; + let source_field_place = source_place.project_to_field( + source_idx.into(), + &self.body.local_decls, + self.tcx, + ); + let target_field_place = target_place.project_to_field( + target_idx.into(), + &self.body.local_decls, + self.tcx, + ); + self.gather_reborrows( + v, + kind, + location, + *target_field_adt, + target_field_args, + target_field_place, + *source_field_adt, + source_field_args, + source_field_place, + ); + } + _ => continue, + } + } + if !did_reborrow { + // If source contained no reference, perform a phantom dereference. + let source_phantom_deref_place = + source_place.project_deeper(&[PlaceElem::PhantomDeref], self.tcx); + if target_args.regions().count() != 1 { + bug!( + "ADT containing no '&mut T' or 'T: Reborrow' fields must only have one lifetime to implement Reborrow" + ); + } + let target_region = target_args.regions().next().unwrap(); + v.push(BorrowData { + kind, + region: target_region.as_var(), + reserve_location: location, + activation_location: TwoPhaseActivation::NotTwoPhase, + borrowed_place: source_phantom_deref_place, + assigned_place: target_place, + }); + } + } } impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { @@ -323,23 +471,14 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { }; self.local_map.entry(borrowed_place.local).or_default().insert(idx); - } else if let &mir::Rvalue::Reborrow(target, mutability, borrowed_place) = rvalue { - let borrowed_place_ty = borrowed_place.ty(self.body, self.tcx).ty; - let &ty::Adt(reborrowed_adt, _reborrowed_args) = borrowed_place_ty.kind() else { - unreachable!() - }; - let &ty::Adt(target_adt, assigned_args) = target.kind() else { unreachable!() }; - let Some(ty::GenericArgKind::Lifetime(region)) = assigned_args.get(0).map(|r| r.kind()) - else { - bug!( - "hir-typeck passed but {} does not have a lifetime argument", - if mutability == Mutability::Mut { "Reborrow" } else { "CoerceShared" } - ); - }; - let region = region.as_var(); + } else if let &mir::Rvalue::Reborrow(target, mutability, source_place) = rvalue { + let source_ty = source_place.ty(self.body, self.tcx).ty; + let &ty::Adt(source_adt, source_args) = source_ty.kind() else { unreachable!() }; + let &ty::Adt(target_adt, target_args) = target.kind() else { unreachable!() }; + let kind = if mutability == Mutability::Mut { // Reborrow - if target_adt.did() != reborrowed_adt.did() { + if target_adt.did() != source_adt.did() { bug!( "hir-typeck passed but Reborrow involves mismatching types at {location:?}" ) @@ -348,24 +487,33 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default } } else { // CoerceShared - if target_adt.did() == reborrowed_adt.did() { + if target_adt.did() == source_adt.did() { bug!( "hir-typeck passed but CoerceShared involves matching types at {location:?}" ) } mir::BorrowKind::Shared }; - let borrow = BorrowData { + + let mut reborrows = smallvec![]; + self.gather_reborrows( + &mut reborrows, kind, - region, - reserve_location: location, - activation_location: TwoPhaseActivation::NotTwoPhase, - borrowed_place, - assigned_place: *assigned_place, - }; - let idx = self.insert_borrow(location, borrow); + location, + target_adt, + target_args, + *assigned_place, + source_adt, + source_args, + source_place, + ); - self.local_map.entry(borrowed_place.local).or_default().insert(idx); + let idxs = self.insert_borrows(location, reborrows); + + let locals = self.local_map.entry(source_place.local).or_default(); + for idx in idxs { + locals.insert(idx); + } } self.super_assign(assigned_place, rvalue, location) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 49307e78fbb14..6e73126d2f9be 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4213,6 +4213,13 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } StorageDeadOrDrop::Destructor(_) => kind, }, + ProjectionElem::PhantomDeref => match kind { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + StorageDeadOrDrop::BoxedStorageDead + } + StorageDeadOrDrop::Destructor(_) => kind, + }, ProjectionElem::OpaqueCast { .. } | ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index bde2529d855cf..16da957aa4bb9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -397,6 +397,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } } } + ProjectionElem::PhantomDeref => (), ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), @@ -485,6 +486,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { PlaceTy::from_ty(*ty) } ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), + ProjectionElem::PhantomDeref => unreachable!("not a field"), }, }; self.describe_field_from_ty( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 68e7e3786b33c..ad558ce4daa00 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -181,6 +181,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } } + PlaceRef { local: _, projection: [ProjectionElem::PhantomDeref] } => { + item_msg = String::new(); + reason = String::new(); + } + PlaceRef { local: _, projection: [_proj_base @ .., ProjectionElem::PhantomDeref] } => { + item_msg = String::new(); + reason = String::new(); + } + PlaceRef { local: _, projection: diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d990d72e3fb42..286fc2d632b54 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2020,7 +2020,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // So it's safe to skip these. ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) - | ProjectionElem::UnwrapUnsafeBinder(_) => (), + | ProjectionElem::UnwrapUnsafeBinder(_) + | ProjectionElem::PhantomDeref => (), } place_ty = place_ty.projection_ty(tcx, elem); @@ -2270,6 +2271,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { break; } + ProjectionElem::PhantomDeref => { + panic!("we don't allow assignments to PhantomDeref, location {location:?}"); + } + ProjectionElem::Subslice { .. } => { panic!("we don't allow assignments to subslices, location: {location:?}"); } @@ -2640,6 +2645,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { _ => bug!("Deref of unexpected type: {:?}", base_ty), } } + ProjectionElem::PhantomDeref => { + bug!("encountered PhantomDeref in is_mutable") + } // Check as the inner reference type if it is a field projection // from the `&pin` pattern ProjectionElem::Field(FieldIdx::ZERO, _) diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index e966e83435ef3..6afc03d0ecf29 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -234,6 +234,13 @@ fn place_components_conflict<'tcx>( return false; } + (ProjectionElem::PhantomDeref, _, Shallow(None)) => { + // e.g., a reborrow of `x.y` while we shallowly access `x.y` or some prefix + // thereof - the shallow access cannot invalidate the reborrowed copy. + debug!("borrow_conflicts_with_place: shallow access behind reborrow"); + return false; + } + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { // Drop can read/write arbitrary projections, so places // conflict regardless of further projections. @@ -244,6 +251,7 @@ fn place_components_conflict<'tcx>( (ProjectionElem::Deref, _, Deep) | (ProjectionElem::Deref, _, AccessDepth::Drop) + | (ProjectionElem::PhantomDeref, _, _) | (ProjectionElem::Field { .. }, _, _) | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) @@ -301,6 +309,11 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); Overlap::EqualOrDisjoint } + (ProjectionElem::PhantomDeref, ProjectionElem::PhantomDeref) => { + // phantom derefs (e.g., `x` vs. `x`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-PHANTOM-DEREF"); + Overlap::EqualOrDisjoint + } (ProjectionElem::OpaqueCast(_), ProjectionElem::OpaqueCast(_)) => { // casts to other types may always conflict irrespective of the type being cast to. debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); @@ -506,6 +519,7 @@ fn place_projection_conflict<'tcx>( } ( ProjectionElem::Deref + | ProjectionElem::PhantomDeref | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 7ac63e02e318d..7ff258de3af4f 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -65,6 +65,9 @@ impl<'tcx> Iterator for Prefixes<'tcx> { | ProjectionElem::Index(_) => { cursor = cursor_base; } + ProjectionElem::PhantomDeref => { + unreachable!("PhantomDeref should not be present in prefixes") + } ProjectionElem::Deref => { match self.kind { PrefixSet::Shallow => { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6825c28270c30..9e6045317e6bd 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1893,6 +1893,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // All these projections don't add any constraints, so there's nothing to // do here. We check their invariants in the MIR validator after all. ProjectionElem::Deref + | ProjectionElem::PhantomDeref | ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } @@ -2463,6 +2464,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), } } + ProjectionElem::PhantomDeref => { + bug!("unexpected PhantomDeref in add_reborrow_constraint") + } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) @@ -2525,6 +2529,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + // FIXME: copy in code from coercion.rs to re-check CoerceShared lifetime relations. if mutability.is_not() { // FIXME(reborrow): for CoerceShared we need to relate the types manually, field by // field. We cannot just attempt to relate `T` and `::Target` by diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index d57f662fc1938..14b2eee8089c5 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -993,6 +993,7 @@ pub(crate) fn codegen_place<'tcx>( PlaceElem::Deref => { cplace = cplace.place_deref(fx); } + PlaceElem::PhantomDeref => bug!("encountered PhantomDeref in codegen"), PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), PlaceElem::UnwrapUnsafeBinder(ty) => { cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 14a5f71fbceaa..c51f1dfdc686d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -360,6 +360,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for elem in place_ref.projection[base..].iter() { cg_base = match *elem { mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), + mir::ProjectionElem::PhantomDeref => { + bug!("encountered PhantomDeref in codegen") + } mir::ProjectionElem::Field(ref field, _) => { assert!( !cg_base.layout.ty.is_any_ptr(), diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index fa54d1ed4e562..f58cb332381b2 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -290,6 +290,7 @@ where ProjectionElem::Index(index) if in_local(index) => return true, ProjectionElem::Deref + | ProjectionElem::PhantomDeref | ProjectionElem::Field(_, _) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index be31393879fff..ba2e68208846f 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -411,6 +411,9 @@ where OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } + PhantomDeref => { + span_bug!(self.cur_span(), "PhantomDeref encountered after borrowck") + } UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 021c1c176d788..7b35d9eb48868 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1364,6 +1364,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::UnwrapUnsafeBinder(_) => { write!(fmt, "unwrap_binder!(")?; } + ProjectionElem::PhantomDeref => { + write!(fmt, "reborrow!(")?; + } } } @@ -1382,7 +1385,7 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::Downcast(None, index) => { write!(fmt, " as variant#{index:?})")?; } - ProjectionElem::Deref => { + ProjectionElem::Deref | ProjectionElem::PhantomDeref => { write!(fmt, ")")?; } ProjectionElem::Field(field, ty) => { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index f5c0b0e66bdae..060d9ba661cc4 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -223,6 +223,9 @@ impl<'tcx> PlaceTy<'tcx> { ); PlaceTy::from_ty(ty) } + ProjectionElem::PhantomDeref => { + PlaceTy::from_ty(normalize(Unnormalized::new_wip(self.ty))) + } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { PlaceTy::from_ty(normalize(Unnormalized::new_wip(self.ty)).builtin_index().unwrap()) } @@ -267,7 +270,7 @@ impl ProjectionElem { /// than the base. pub fn is_indirect(&self) -> bool { match self { - Self::Deref => true, + Self::Deref | Self::PhantomDeref => true, Self::Field(_, _) | Self::Index(_) @@ -289,7 +292,8 @@ impl ProjectionElem { | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) - | Self::UnwrapUnsafeBinder(..) => true, + | Self::UnwrapUnsafeBinder(..) + | Self::PhantomDeref => true, } } @@ -313,7 +317,8 @@ impl ProjectionElem { Self::ConstantIndex { from_end: true, .. } | Self::Index(_) | Self::OpaqueCast(_) - | Self::Subslice { .. } => false, + | Self::Subslice { .. } + | Self::PhantomDeref => false, // FIXME(unsafe_binders): Figure this out. Self::UnwrapUnsafeBinder(..) => false, @@ -333,6 +338,7 @@ impl ProjectionElem { ) -> Option> { Some(match self { ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::PhantomDeref => bug!("PhantomDeref shouldn't hopefully come here"), ProjectionElem::Downcast(name, read_variant) => { ProjectionElem::Downcast(name, read_variant) } @@ -495,7 +501,10 @@ impl<'tcx> PlaceRef<'tcx> { pub fn local_or_deref_local(&self) -> Option { match *self { PlaceRef { local, projection: [] } - | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), + | PlaceRef { + local, + projection: [ProjectionElem::Deref | ProjectionElem::PhantomDeref], + } => Some(local), _ => None, } } @@ -567,6 +576,7 @@ impl<'tcx> PlaceRef<'tcx> { std::iter::once(self.local).chain(self.projection.iter().filter_map(|proj| match proj { ProjectionElem::Index(local) => Some(*local), ProjectionElem::Deref + | ProjectionElem::PhantomDeref | ProjectionElem::Field(_, _) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b005cf0c8d10f..bfeec0d41e1fb 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1255,6 +1255,26 @@ pub enum ProjectionElem { /// A transmute from an unsafe binder to the type that it wraps. This is a projection /// of a place, so it doesn't necessarily constitute a move out of the binder. UnwrapUnsafeBinder(T), + + /// A symbolic dereference of a `Reborrow` type that does not contain any `&mut T` fields. + /// + /// If a type is `Reborrow` and contains a `&mut T` field then reborrowing it reborrows the `T`, + /// producing a borrow on an indirect place, producing a value that can be returned from the + /// function since it does not capture any local place. If no such field exists, then + /// reborrowing the type must dereference the type itself to find an indirect place, but + /// generally such types will not implements `Deref`. Therefore, in borrow checking we instead + /// perform a "phantom dereference" (named so because the type will usually contain some + /// `PhantomData<&'a ()>` or equivalent that captures the lifetime) to access an indeterminate + /// indirect place. + /// + /// FIXME(reborrow): currently this variant is not considered an indirect place for whatever + /// reason. This variant makes no sense if that cannot be fixed. + /// + /// FIXME(reborrow): if the Reborrow traits experiment is rejected, this variant can be removed: + /// see the [PR]. + /// + /// [PR]: https://github.com/rust-lang/rust/pull/159103 + PhantomDeref, } /// Alias for projections as they appear in places, where the base is a place diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 429ab7d928fc5..7a79b426715f9 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1178,6 +1178,7 @@ macro_rules! visit_place_fns { if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None } } PlaceElem::Deref + | PlaceElem::PhantomDeref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } | PlaceElem::Downcast(..) => None, @@ -1262,6 +1263,7 @@ macro_rules! visit_place_fns { ); } ProjectionElem::Deref + | ProjectionElem::PhantomDeref | ProjectionElem::Subslice { from: _, to: _, from_end: _ } | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } | ProjectionElem::Downcast(_, _) => {} diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index e92f74722626b..4c717d70c742b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -88,6 +88,7 @@ fn convert_to_hir_projections_and_truncate_for_capture( for mir_projection in mir_projections { let hir_projection = match mir_projection { ProjectionElem::Deref => HirProjectionKind::Deref, + ProjectionElem::PhantomDeref => continue, ProjectionElem::Field(field, _) => { let variant = variant.unwrap_or(FIRST_VARIANT); HirProjectionKind::Field(*field, variant) @@ -802,6 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } ProjectionElem::Field(..) + | ProjectionElem::PhantomDeref | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 83d40a5a2f284..b6565588ae3f1 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -452,6 +452,9 @@ impl MoveSubPath { let subpath = match elem { // correspond to a MoveSubPath ProjectionKind::Deref => MoveSubPath::Deref, + ProjectionKind::PhantomDeref => { + unreachable!("unexpected PhantomDeref in MoveSubPath::of") + } ProjectionKind::Field(idx, _) => MoveSubPath::Field(idx), ProjectionKind::ConstantIndex { offset, min_length: _, from_end: false } => { MoveSubPath::ConstantIndex(offset) diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index 6d9d0d35d3ed6..97a74626aea4f 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -454,7 +454,8 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { | PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } - | PlaceElem::Downcast(..) => None, + | PlaceElem::Downcast(..) + | PlaceElem::PhantomDeref => None, } } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 9d751a7cc5bd0..15e9e34159f76 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -861,6 +861,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { return None; } } + ProjectionElem::PhantomDeref => bug!("PhantomDeref in GVN"), ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index), ProjectionElem::Field(f, _) => match self.get(value) { Value::Aggregate(_, fields) => return Some((projection_ty, fields[f.as_usize()])), diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index c971769d528bb..afc2794d6edcf 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -299,7 +299,9 @@ impl<'tcx> Validator<'_, 'tcx> { | ProjectionElem::UnwrapUnsafeBinder(_) => {} // Never recurse. - ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { + ProjectionElem::PhantomDeref + | ProjectionElem::OpaqueCast(..) + | ProjectionElem::Downcast(..) => { return Err(Unpromotable); } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 124329526028d..792c5d08e3f6e 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -444,6 +444,7 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { use rustc_middle::mir::ProjectionElem::*; match self { Deref => crate::mir::ProjectionElem::Deref, + PhantomDeref => bug!("Hopefully we don't come here"), Field(idx, ty) => { crate::mir::ProjectionElem::Field(idx.stable(tables, cx), ty.stable(tables, cx)) } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index ca2cd7338d5a2..075d42191ff95 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -323,7 +323,8 @@ fn check_place<'tcx>( | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Index(_) - | ProjectionElem::UnwrapUnsafeBinder(_) => {}, + | ProjectionElem::UnwrapUnsafeBinder(_) + | ProjectionElem::PhantomDeref => {}, } } diff --git a/tests/ui/reborrow/coerce-shared-associated-type-field.rs b/tests/ui/reborrow/coerce-shared-associated-type-field.rs index df744e9442dd8..c40abe9de7b31 100644 --- a/tests/ui/reborrow/coerce-shared-associated-type-field.rs +++ b/tests/ui/reborrow/coerce-shared-associated-type-field.rs @@ -1,3 +1,6 @@ +//! Test that CoerceShared can resolve field type equivalence through GATs. +//! This should eventually pass. + #![feature(reborrow)] #![allow(dead_code)] diff --git a/tests/ui/reborrow/coerce-shared-associated-type-field.stderr b/tests/ui/reborrow/coerce-shared-associated-type-field.stderr index 31b54e7ed6c9e..7a78190595380 100644 --- a/tests/ui/reborrow/coerce-shared-associated-type-field.stderr +++ b/tests/ui/reborrow/coerce-shared-associated-type-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-associated-type-field.rs:27:1 + --> $DIR/coerce-shared-associated-type-field.rs:30:1 | LL | impl<'a> CoerceShared> for MyMut<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^---------^^^ diff --git a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs index 3b6e9e25d8bb4..59e0a8d96a33e 100644 --- a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs +++ b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs @@ -1,3 +1,7 @@ +//! Test that Reborrow and CoerceShared can be derived in macros. +//! This should eventually pass. + + #![feature(reborrow, decl_macro)] #![allow(incomplete_features)] diff --git a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr index 62a73361b5cd9..0c9d89dd009ec 100644 --- a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr +++ b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-decl-macro-hygiene.rs:20:5 + --> $DIR/coerce-shared-decl-macro-hygiene.rs:24:5 | LL | impl<'a> CoerceShared> for MyMut<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^---------^^^ diff --git a/tests/ui/reborrow/coerce-shared-extra-marker.rs b/tests/ui/reborrow/coerce-shared-extra-marker.rs index 40026d68d5dca..d32d5c3ec1fff 100644 --- a/tests/ui/reborrow/coerce-shared-extra-marker.rs +++ b/tests/ui/reborrow/coerce-shared-extra-marker.rs @@ -1,5 +1,7 @@ //@ run-pass +//! Test that CoerceShared can drop a PhantomData marker field and pass a data reference through. + #![feature(reborrow)] #![allow(dead_code)] diff --git a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs index 9d102238467e6..71caf8a7ec6bf 100644 --- a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs +++ b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared cannot be used to swap 'static and 'a lifetimes around. + #![feature(reborrow)] use std::marker::{CoerceShared, Reborrow}; diff --git a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr index b6160ad40bcce..4958640257918 100644 --- a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr +++ b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field - --> $DIR/coerce-shared-field-lifetime-swap.rs:14:5 + --> $DIR/coerce-shared-field-lifetime-swap.rs:16:5 | LL | x: &'static (), | -------------- source field `x` has type `&'static ()` diff --git a/tests/ui/reborrow/coerce-shared-field-relations.rs b/tests/ui/reborrow/coerce-shared-field-relations.rs index 3920f3eba7cb5..63c82bab9606d 100644 --- a/tests/ui/reborrow/coerce-shared-field-relations.rs +++ b/tests/ui/reborrow/coerce-shared-field-relations.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared cannot produce a field from thin air. + #![feature(reborrow)] use std::marker::{CoerceShared, Reborrow}; @@ -13,6 +15,7 @@ struct CustomRef<'a, T> { value: &'a T, } +// No error expected here: value: &'a mut T -> value: &'a T. impl<'a, T> CoerceShared> for CustomMut<'a, T> {} struct RenamedMut<'a, T> { @@ -27,6 +30,8 @@ struct RenamedRef<'a, T> { //~^ ERROR } +// Should error: source: &'a mut T -> target: &'a T attempts to drop 'source' and produce +// 'target' from thin air. impl<'a, T> CoerceShared> for RenamedMut<'a, T> {} struct BadMut<'a, T> { @@ -42,6 +47,8 @@ struct BadRef<'a, T> { _marker: std::marker::PhantomData, } +// Should error: value: &'a mut T -> &'a u32 attempts a reference transmute, and also +// '_marker' field is created from thin air. impl<'a, T> CoerceShared> for BadMut<'a, T> {} fn good(_value: CustomRef<'_, u32>) {} diff --git a/tests/ui/reborrow/coerce-shared-field-relations.stderr b/tests/ui/reborrow/coerce-shared-field-relations.stderr index 2a723f954490b..33c04d7b7f1b5 100644 --- a/tests/ui/reborrow/coerce-shared-field-relations.stderr +++ b/tests/ui/reborrow/coerce-shared-field-relations.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires every target field to have a corresponding source field - --> $DIR/coerce-shared-field-relations.rs:26:5 + --> $DIR/coerce-shared-field-relations.rs:29:5 | LL | target: &'a T, | ^^^^^^^^^^^^^ target field `target` has no corresponding source field @@ -8,7 +8,7 @@ LL | impl<'a, T> CoerceShared> for RenamedMut<'a, T> {} | ----------------- source type `RenamedMut` does not contain field `target` error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field - --> $DIR/coerce-shared-field-relations.rs:40:5 + --> $DIR/coerce-shared-field-relations.rs:45:5 | LL | value: &'a mut T, | ---------------- source field `value` has type `&'a mut T` diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-field.rs b/tests/ui/reborrow/coerce-shared-foreign-private-field.rs index 66c8ece3bd43e..fc039df249eae 100644 --- a/tests/ui/reborrow/coerce-shared-foreign-private-field.rs +++ b/tests/ui/reborrow/coerce-shared-foreign-private-field.rs @@ -1,5 +1,7 @@ //@ aux-build: reborrow_foreign_private.rs +//! Test that CoerceShared cannot be implemented targeting a foreign struct with private fields. + #![feature(reborrow)] extern crate reborrow_foreign_private; @@ -13,6 +15,7 @@ struct LocalMut<'a> { impl<'a> Reborrow for LocalMut<'a> {} +// Should error: ForeignRef has private fields. impl<'a> CoerceShared> for LocalMut<'a> {} //~^ ERROR diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-field.stderr b/tests/ui/reborrow/coerce-shared-foreign-private-field.stderr index a328084260d0d..a00a6b84ec788 100644 --- a/tests/ui/reborrow/coerce-shared-foreign-private-field.stderr +++ b/tests/ui/reborrow/coerce-shared-foreign-private-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires all target type fields to be accessible from the impl - --> $DIR/coerce-shared-foreign-private-field.rs:16:1 + --> $DIR/coerce-shared-foreign-private-field.rs:19:1 | LL | impl<'a> CoerceShared> for LocalMut<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs index a2b88af04eb50..466fe2c315263 100644 --- a/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs +++ b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs @@ -1,3 +1,6 @@ +//! Test that CoerceShared cannot be implemented targeting a foreign tuple struct with private +//! fields. + #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.stderr b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.stderr index b699e1affbc49..2ae5963bbc55b 100644 --- a/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.stderr +++ b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires all target type fields to be accessible from the impl - --> $DIR/coerce-shared-foreign-private-tuple-field.rs:18:1 + --> $DIR/coerce-shared-foreign-private-tuple-field.rs:21:1 | LL | impl<'a> CoerceShared> for LocalPtrMut<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/reborrow/coerce-shared-generics.rs b/tests/ui/reborrow/coerce-shared-generics.rs index 9edab02835761..2a609ffd1c2df 100644 --- a/tests/ui/reborrow/coerce-shared-generics.rs +++ b/tests/ui/reborrow/coerce-shared-generics.rs @@ -1,3 +1,5 @@ +//! Test that Reborrow and CoerceShared can be implemented with generics. + #![feature(reborrow)] #![allow(dead_code)] diff --git a/tests/ui/reborrow/coerce-shared-generics.stderr b/tests/ui/reborrow/coerce-shared-generics.stderr index 8e2e4e4485918..2be03590fb657 100644 --- a/tests/ui/reborrow/coerce-shared-generics.stderr +++ b/tests/ui/reborrow/coerce-shared-generics.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-generics.rs:26:1 + --> $DIR/coerce-shared-generics.rs:28:1 | LL | impl<'a, T, U: Copy, const N: usize> CoerceShared> | ^ ---------------------- target type has 2 non-ZST reborrow data fields diff --git a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs index b6b5471adb0fc..c7e3b4b12d4bc 100644 --- a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs +++ b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared cannot be implemented with spurious 'static lifetimes. + #![feature(reborrow)] // The impl is accepted, but using it to coerce a local marker into a `'static` @@ -20,5 +22,4 @@ fn method(_a: StaticMarkerRef<'static>) {} fn main() { let a = CustomMarker(PhantomData); method(a); - //~^ ERROR } diff --git a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr index 7c2e3e22b0b51..38c3d3637b566 100644 --- a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr +++ b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr @@ -1,25 +1,10 @@ error: implementing `CoerceShared` requires source and target to use the same reborrow lifetime argument - --> $DIR/coerce-shared-lifetime-mismatch.rs:15:10 + --> $DIR/coerce-shared-lifetime-mismatch.rs:17:10 | LL | impl<'a> CoerceShared> for CustomMarker<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ -- source reborrow lifetime | | | target reborrow lifetime -error[E0597]: `a` does not live long enough - --> $DIR/coerce-shared-lifetime-mismatch.rs:22:12 - | -LL | let a = CustomMarker(PhantomData); - | - binding `a` declared here -LL | method(a); - | -------^- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` -LL | -LL | } - | - `a` dropped here while still borrowed - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/reborrow/coerce-shared-missing-target-field.rs b/tests/ui/reborrow/coerce-shared-missing-target-field.rs index edd843b041fa8..dc96610d3703d 100644 --- a/tests/ui/reborrow/coerce-shared-missing-target-field.rs +++ b/tests/ui/reborrow/coerce-shared-missing-target-field.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared cannot create a field from thin air. + #![feature(reborrow)] use std::marker::{CoerceShared, Reborrow}; diff --git a/tests/ui/reborrow/coerce-shared-missing-target-field.stderr b/tests/ui/reborrow/coerce-shared-missing-target-field.stderr index 148cf8addf0f9..0884d52f41b19 100644 --- a/tests/ui/reborrow/coerce-shared-missing-target-field.stderr +++ b/tests/ui/reborrow/coerce-shared-missing-target-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires every target field to have a corresponding source field - --> $DIR/coerce-shared-missing-target-field.rs:14:5 + --> $DIR/coerce-shared-missing-target-field.rs:16:5 | LL | len: usize, | ^^^^^^^^^^ target field `len` has no corresponding source field diff --git a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs index 2a18d0dda06f0..ee7685242070e 100644 --- a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs +++ b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs @@ -1,3 +1,5 @@ +//! Test that reference shared coercing does not allow changing lifetime relations. + #![feature(reborrow)] use std::marker::{CoerceShared, Reborrow}; diff --git a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr index 98ab275b31e48..57159ff8ddd56 100644 --- a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr +++ b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field - --> $DIR/coerce-shared-mut-ref-field-validation.rs:50:5 + --> $DIR/coerce-shared-mut-ref-field-validation.rs:52:5 | LL | value: &'a mut &'a (), | --------------------- source field `value` has type `&'a mut &'a ()` diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs index 4f066079c749b..174aeabd3ebe5 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs @@ -1,3 +1,7 @@ +//! Test that CoerceShared does not capture an omitted field, and that captured fields do not stay +//! captured after the local lifetime ends. +//! This should eventually pass. + #![feature(reborrow)] #![allow(dead_code)] @@ -46,6 +50,8 @@ fn main() { read(wrapped); } - extra_value = 3; - assert_eq!(extra_value, 3); + value = 3; + assert_eq!(value, 3); + extra_value = 4; + assert_eq!(extra_value, 4); } diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr index d0f2540ccbcff..7a92db2b1323a 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-omitted-reborrow-field-after-dead.rs:31:1 + --> $DIR/coerce-shared-omitted-reborrow-field-after-dead.rs:35:1 | LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^--------------^^^^^^--------------^^^ diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs index ade1890068d76..b0985c4f974bd 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs @@ -1,3 +1,7 @@ +//! Test that CoerceShared doesn't capture an omitted field, and that the source's omitted field can +//! be used as exclusive while the captured field is still captured. +//! This should eventually pass. + #![feature(reborrow)] use std::marker::{CoerceShared, Reborrow}; @@ -47,7 +51,6 @@ fn main() { let shared = get(wrapped); *wrapped.extra.value = 3; - //~^ ERROR cannot assign to `*wrapped.extra.value` because it is borrowed let _ = shared; } diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr index ccc3054a1b0c8..a5426a3b4dc81 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-omitted-reborrow-field-locked.rs:30:1 + --> $DIR/coerce-shared-omitted-reborrow-field-locked.rs:34:1 | LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^--------------^^^^^^--------------^^^ @@ -10,18 +10,5 @@ LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} | = note: this is a temporary restriction until `CoerceShared` lowering supports non-trivially memcpy-compatible field layouts -error[E0506]: cannot assign to `*wrapped.extra.value` because it is borrowed - --> $DIR/coerce-shared-omitted-reborrow-field-locked.rs:49:5 - | -LL | let shared = get(wrapped); - | ------- `*wrapped.extra.value` is borrowed here -LL | -LL | *wrapped.extra.value = 3; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `*wrapped.extra.value` is assigned to here but it was already borrowed - | borrow later used here - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs index 55cc010c19af4..f12c29416bdba 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs @@ -1,3 +1,6 @@ +//! Test that CoerceShared can omit a reborrowed field. +//! This should eventually pass. + #![feature(reborrow)] #![allow(dead_code)] diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr index 08ddea2329405..fb8b6384143b3 100644 --- a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-omitted-reborrow-field.rs:31:1 + --> $DIR/coerce-shared-omitted-reborrow-field.rs:34:1 | LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^--------------^^^^^^--------------^^^ diff --git a/tests/ui/reborrow/coerce-shared-reordered-field.rs b/tests/ui/reborrow/coerce-shared-reordered-field.rs index f4630fe1f7d83..b182d9df26f59 100644 --- a/tests/ui/reborrow/coerce-shared-reordered-field.rs +++ b/tests/ui/reborrow/coerce-shared-reordered-field.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared can be implemented even if field order changes. + #![feature(reborrow)] #![allow(dead_code)] diff --git a/tests/ui/reborrow/coerce-shared-reordered-field.stderr b/tests/ui/reborrow/coerce-shared-reordered-field.stderr index 5469e5e3d9f49..4dbc344aa9196 100644 --- a/tests/ui/reborrow/coerce-shared-reordered-field.stderr +++ b/tests/ui/reborrow/coerce-shared-reordered-field.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` currently requires source and target to have at most one non-ZST reborrow data field - --> $DIR/coerce-shared-reordered-field.rs:19:1 + --> $DIR/coerce-shared-reordered-field.rs:21:1 | LL | impl<'a> CoerceShared> for ReorderMut<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^--------------^^^^^^--------------^^^ diff --git a/tests/ui/reborrow/coerce-shared-wrong-generic.rs b/tests/ui/reborrow/coerce-shared-wrong-generic.rs index bbd9cfebcd9e8..b3dee8e8a9eb2 100644 --- a/tests/ui/reborrow/coerce-shared-wrong-generic.rs +++ b/tests/ui/reborrow/coerce-shared-wrong-generic.rs @@ -1,3 +1,5 @@ +//! Test that CoerceShared cannot switch generic type usage around. + #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; diff --git a/tests/ui/reborrow/coerce-shared-wrong-generic.stderr b/tests/ui/reborrow/coerce-shared-wrong-generic.stderr index b037106ebb619..2a472cee46af2 100644 --- a/tests/ui/reborrow/coerce-shared-wrong-generic.stderr +++ b/tests/ui/reborrow/coerce-shared-wrong-generic.stderr @@ -1,5 +1,5 @@ error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field - --> $DIR/coerce-shared-wrong-generic.rs:14:5 + --> $DIR/coerce-shared-wrong-generic.rs:16:5 | LL | value: &'a mut T, | ---------------- source field `value` has type `&'a mut T` diff --git a/tests/ui/reborrow/custom_marker.rs b/tests/ui/reborrow/custom_marker.rs index 80689d81d0cc1..e51990a1a8f0e 100644 --- a/tests/ui/reborrow/custom_marker.rs +++ b/tests/ui/reborrow/custom_marker.rs @@ -1,5 +1,7 @@ //@ run-pass +//! Test that Reborrow on a custom ZST marker type reborrows the value automatically. + #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; diff --git a/tests/ui/reborrow/custom_marker_assign_deref.rs b/tests/ui/reborrow/custom_marker_assign_deref.rs index 79ea2a35acdaf..f46142b4878da 100644 --- a/tests/ui/reborrow/custom_marker_assign_deref.rs +++ b/tests/ui/reborrow/custom_marker_assign_deref.rs @@ -1,5 +1,7 @@ //@ run-pass +//! Test that assignment to DerefMut of a Reborrow type does not ICE. + #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; diff --git a/tests/ui/reborrow/custom_marker_coerce_shared.rs b/tests/ui/reborrow/custom_marker_coerce_shared.rs index 17c7bac98d17a..006b92054bc37 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared.rs +++ b/tests/ui/reborrow/custom_marker_coerce_shared.rs @@ -1,5 +1,7 @@ //@ run-pass +//! Test that CoerceShared of custom ZST marker type reborrows the type automatically as shared. + #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs b/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs index 56bc1f896da0f..8e86a95223946 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs +++ b/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs @@ -1,5 +1,8 @@ //@ run-pass +//! Test that CoerceShared of custom ZST marker type reborrows the type automatically as shared and +//! the original stays concurrently usable through shared references. + #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_move.rs b/tests/ui/reborrow/custom_marker_coerce_shared_move.rs index 532d13da258c8..7fa06bb55aed1 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_move.rs +++ b/tests/ui/reborrow/custom_marker_coerce_shared_move.rs @@ -1,3 +1,6 @@ +//! Test that CoerceShared of custom ZST marker type reborrows the type automatically as shared but +//! moving the original invalidates the results. + #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr b/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr index 90382af3ce30e..f0ad934cacbf3 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr +++ b/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/custom_marker_coerce_shared_move.rs:19:14 + --> $DIR/custom_marker_coerce_shared_move.rs:22:14 | LL | let a = CustomMarker(PhantomData); | - binding `a` declared here diff --git a/tests/ui/reborrow/custom_marker_deref.rs b/tests/ui/reborrow/custom_marker_deref.rs index 74b9bac22ed0e..acf989985f7f1 100644 --- a/tests/ui/reborrow/custom_marker_deref.rs +++ b/tests/ui/reborrow/custom_marker_deref.rs @@ -1,5 +1,8 @@ //@ run-pass +//! Test that CoerceShared of custom ZST marker type reborrows the type automatically from a +//! `&mut CustomMarker` deref. + #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; diff --git a/tests/ui/reborrow/custom_marker_identity.rs b/tests/ui/reborrow/custom_marker_identity.rs new file mode 100644 index 0000000000000..27038a803d86c --- /dev/null +++ b/tests/ui/reborrow/custom_marker_identity.rs @@ -0,0 +1,20 @@ +//@ check-pass + +//! Check that the result of a Reborrow retains the original lifetime and does not capture local +//! values, therefore enabling an identity function to compile. +//! This should eventually pass. + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +fn method<'a>(a: CustomMarker<'a>) -> CustomMarker<'a> { + a +} + +fn main() { + let a = CustomMarker(PhantomData); + let _ = method(a); +} diff --git a/tests/ui/reborrow/custom_marker_mut_field_borrow.rs b/tests/ui/reborrow/custom_marker_mut_field_borrow.rs new file mode 100644 index 0000000000000..41fd01ed77a59 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_mut_field_borrow.rs @@ -0,0 +1,17 @@ +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +fn method<'a>(_a: CustomMarker<'a>) -> &'a () { + &() +} + +fn main() { + let a = CustomMarker(PhantomData); + let x = &a.0; + let y = method(a); + //~^ ERROR: cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = (x, y); +} diff --git a/tests/ui/reborrow/custom_marker_mut_field_borrow.stderr b/tests/ui/reborrow/custom_marker_mut_field_borrow.stderr new file mode 100644 index 0000000000000..6601ec172228d --- /dev/null +++ b/tests/ui/reborrow/custom_marker_mut_field_borrow.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_marker_mut_field_borrow.rs:14:20 + | +LL | let x = &a.0; + | ---- immutable borrow occurs here +LL | let y = method(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = (x, y); + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_marker_place_conflict.rs b/tests/ui/reborrow/custom_marker_place_conflict.rs new file mode 100644 index 0000000000000..6abbb847b9235 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict.rs @@ -0,0 +1,17 @@ +//@ check-fail + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +fn reborrow(_: CustomMarker<'_>) {} + +fn main() { + let a = CustomMarker(PhantomData); + let b: &CustomMarker = &a; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = b; +} diff --git a/tests/ui/reborrow/custom_marker_place_conflict.stderr b/tests/ui/reborrow/custom_marker_place_conflict.stderr new file mode 100644 index 0000000000000..224562cde5884 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_marker_place_conflict.rs:14:14 + | +LL | let b: &CustomMarker = &a; + | -- immutable borrow occurs here +LL | reborrow(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = b; + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_marker_place_conflict_deref.rs b/tests/ui/reborrow/custom_marker_place_conflict_deref.rs new file mode 100644 index 0000000000000..a0c65c9753741 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_deref.rs @@ -0,0 +1,25 @@ +//@ check-fail + +#![feature(reborrow)] +use std::{marker::{Reborrow, PhantomData}, ops::Deref}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +impl<'a> Deref for CustomMarker<'a> { + type Target = (); + + fn deref(&self) -> &() { + &() + } +} + +fn reborrow(_: CustomMarker) {} + +fn main() { + let a = CustomMarker(PhantomData); + let b: &() = &a; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = b; +} diff --git a/tests/ui/reborrow/custom_marker_place_conflict_deref.stderr b/tests/ui/reborrow/custom_marker_place_conflict_deref.stderr new file mode 100644 index 0000000000000..22a8dead7fe72 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_deref.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_marker_place_conflict_deref.rs:22:14 + | +LL | let b: &() = &a; + | -- immutable borrow occurs here +LL | reborrow(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = b; + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_marker_place_conflict_field.rs b/tests/ui/reborrow/custom_marker_place_conflict_field.rs new file mode 100644 index 0000000000000..b967651179b36 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_field.rs @@ -0,0 +1,17 @@ +//@ check-fail + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +fn reborrow(_: CustomMarker) {} + +fn main() { + let a = CustomMarker(PhantomData); + let b: &PhantomData<&()> = &a.0; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = b; +} diff --git a/tests/ui/reborrow/custom_marker_place_conflict_field.stderr b/tests/ui/reborrow/custom_marker_place_conflict_field.stderr new file mode 100644 index 0000000000000..2972eff893f13 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_field.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_marker_place_conflict_field.rs:14:14 + | +LL | let b: &PhantomData<&()> = &a.0; + | ---- immutable borrow occurs here +LL | reborrow(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = b; + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.rs b/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.rs new file mode 100644 index 0000000000000..9c02f81820754 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.rs @@ -0,0 +1,21 @@ +//@ check-fail + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +impl<'a> Reborrow for CustomMarker<'a> {} + +struct CustomMarkerTwo<'a>(CustomMarker<'a>, u64); +impl<'a> Reborrow for CustomMarkerTwo<'a> {} + +fn reborrow(_: CustomMarkerTwo) {} + +fn main() { + let a = CustomMarker(PhantomData); + let a = CustomMarkerTwo(a, 0); + let b: &u64 = &a.1; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = b; +} diff --git a/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.stderr b/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.stderr new file mode 100644 index 0000000000000..e48645562f8d3 --- /dev/null +++ b/tests/ui/reborrow/custom_marker_place_conflict_parallel_field.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_marker_place_conflict_parallel_field.rs:18:14 + | +LL | let b: &u64 = &a.1; + | ---- immutable borrow occurs here +LL | reborrow(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = b; + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_mut_identity.rs b/tests/ui/reborrow/custom_mut_identity.rs new file mode 100644 index 0000000000000..6b67d5f342562 --- /dev/null +++ b/tests/ui/reborrow/custom_mut_identity.rs @@ -0,0 +1,17 @@ +//@ run-pass + +#![feature(reborrow)] +use std::marker::Reborrow; + +#[allow(unused)] +struct CustomMut<'a, T>(&'a mut T); +impl<'a, T> Reborrow for CustomMut<'a, T> {} + +fn method(a: CustomMut<()>) -> CustomMut<()> { + a +} + +fn main() { + let a = CustomMut(&mut ()); + let _ = method(a); +} diff --git a/tests/ui/reborrow/custom_mut_place_conflict.rs b/tests/ui/reborrow/custom_mut_place_conflict.rs new file mode 100644 index 0000000000000..8a57a93eb6bb7 --- /dev/null +++ b/tests/ui/reborrow/custom_mut_place_conflict.rs @@ -0,0 +1,17 @@ +//@ check-fail + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMut<'a>(&'a mut ()); +impl<'a> Reborrow for CustomMut<'a> {} + +fn reborrow(_: CustomMut) {} + +fn main() { + let a = CustomMut(&mut ()); + let b: &CustomMut = &a; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let _ = b; +} diff --git a/tests/ui/reborrow/custom_mut_place_conflict.stderr b/tests/ui/reborrow/custom_mut_place_conflict.stderr new file mode 100644 index 0000000000000..d73776b564a6a --- /dev/null +++ b/tests/ui/reborrow/custom_mut_place_conflict.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/custom_mut_place_conflict.rs:14:14 + | +LL | let b: &CustomMut = &a; + | -- immutable borrow occurs here +LL | reborrow(a); + | ^ mutable borrow occurs here +LL | +LL | let _ = b; + | - immutable borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/reborrow/custom_mut_place_conflict_field.rs b/tests/ui/reborrow/custom_mut_place_conflict_field.rs new file mode 100644 index 0000000000000..6b65d794999a0 --- /dev/null +++ b/tests/ui/reborrow/custom_mut_place_conflict_field.rs @@ -0,0 +1,17 @@ +//@ check-fail + +#![feature(reborrow)] +use std::marker::{Reborrow, PhantomData}; + +struct CustomMut<'a>(&'a mut ()); +impl<'a> Reborrow for CustomMut<'a> {} + +fn reborrow(_: CustomMut) {} + +fn main() { + let a = CustomMut(&mut ()); + let b: &mut () = a.0; + reborrow(a); + //~^ ERROR cannot borrow `a` as mutable more than once at a time + let _ = b; +} diff --git a/tests/ui/reborrow/custom_mut_place_conflict_field.stderr b/tests/ui/reborrow/custom_mut_place_conflict_field.stderr new file mode 100644 index 0000000000000..326faf598594b --- /dev/null +++ b/tests/ui/reborrow/custom_mut_place_conflict_field.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `a` as mutable more than once at a time + --> $DIR/custom_mut_place_conflict_field.rs:14:14 + | +LL | let b: &mut () = a.0; + | --- first mutable borrow occurs here +LL | reborrow(a); + | ^ second mutable borrow occurs here +LL | +LL | let _ = b; + | - first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/reborrow/reborrow-promotion-rejected.rs b/tests/ui/reborrow/reborrow-promotion-rejected.rs index 38366cd9ac2a7..7265c25da9795 100644 --- a/tests/ui/reborrow/reborrow-promotion-rejected.rs +++ b/tests/ui/reborrow/reborrow-promotion-rejected.rs @@ -1,4 +1,4 @@ -//@ check-fail +//@ check-pass #![feature(reborrow)] @@ -16,6 +16,5 @@ const fn coerce(x: MyRef<'_>) -> MyRef<'_> { } static BAD: &'static MyRef<'static> = &coerce(MyMut(&1)); -//~^ ERROR temporary value dropped while borrowed fn main() {} diff --git a/tests/ui/reborrow/reborrow-promotion-rejected.stderr b/tests/ui/reborrow/reborrow-promotion-rejected.stderr deleted file mode 100644 index f7e1560f02089..0000000000000 --- a/tests/ui/reborrow/reborrow-promotion-rejected.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/reborrow-promotion-rejected.rs:18:47 - | -LL | static BAD: &'static MyRef<'static> = &coerce(MyMut(&1)); - | --------^^^^^^^^^- - | | | | - | | | temporary value is freed at the end of this statement - | | creates a temporary value which is freed while still in use - | using this value as a static requires that borrow lasts for `'static` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0716`.