Auto merge of #117712 - lcnr:expand-coroutine, r=jackh726
generator layout: ignore fake borrows
fixes #117059
We emit fake shallow borrows in case the scrutinee place uses a `Deref` and there is a match guard. This is necessary to prevent the match guard from mutating the scrutinee: fab1054e17/compiler/rustc_mir_build/src/build/matches/mod.rs (L1250-L1265)
These fake borrows end up impacting the generator witness computation in `mir_generator_witnesses`, which causes the issue in #117059. This PR now completely ignores fake borrows during this computation. This is sound as thse are always removed after analysis and the actual computation of the generator layout happens afterwards.
Only the second commit impacts behavior, and could be backported by itself.
r? types
This commit is contained in:
commit
b7583d38b7
40 changed files with 140 additions and 91 deletions
|
@ -71,7 +71,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||||
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let kind = match self.kind {
|
let kind = match self.kind {
|
||||||
mir::BorrowKind::Shared => "",
|
mir::BorrowKind::Shared => "",
|
||||||
mir::BorrowKind::Shallow => "shallow ",
|
mir::BorrowKind::Fake => "fake ",
|
||||||
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
||||||
// FIXME: differentiate `TwoPhaseBorrow`
|
// FIXME: differentiate `TwoPhaseBorrow`
|
||||||
mir::BorrowKind::Mut {
|
mir::BorrowKind::Mut {
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||||
// cross suspension points so this behavior is unproblematic.
|
// cross suspension points so this behavior is unproblematic.
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
|
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) |
|
||||||
|
|
||||||
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
|
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
|
||||||
// contain dangling references.
|
// contain dangling references.
|
||||||
|
|
|
@ -1022,7 +1022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
|
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
(BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
|
(BorrowKind::Mut { .. }, BorrowKind::Fake) => {
|
||||||
if let Some(immutable_section_description) =
|
if let Some(immutable_section_description) =
|
||||||
self.classify_immutable_section(issued_borrow.assigned_place)
|
self.classify_immutable_section(issued_borrow.assigned_place)
|
||||||
{
|
{
|
||||||
|
@ -1114,11 +1114,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
|
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
|
||||||
| (
|
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
|
||||||
BorrowKind::Shallow,
|
unreachable!()
|
||||||
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
|
}
|
||||||
) => unreachable!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if issued_spans == borrow_spans {
|
if issued_spans == borrow_spans {
|
||||||
|
@ -2806,7 +2805,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let loan_span = loan_spans.args_or_use();
|
let loan_span = loan_spans.args_or_use();
|
||||||
|
|
||||||
let descr_place = self.describe_any_place(place.as_ref());
|
let descr_place = self.describe_any_place(place.as_ref());
|
||||||
if loan.kind == BorrowKind::Shallow {
|
if loan.kind == BorrowKind::Fake {
|
||||||
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
||||||
let mut err = self.cannot_mutate_in_immutable_section(
|
let mut err = self.cannot_mutate_in_immutable_section(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -634,7 +634,7 @@ impl UseSpans<'_> {
|
||||||
err.subdiagnostic(match kind {
|
err.subdiagnostic(match kind {
|
||||||
Some(kd) => match kd {
|
Some(kd) => match kd {
|
||||||
rustc_middle::mir::BorrowKind::Shared
|
rustc_middle::mir::BorrowKind::Shared
|
||||||
| rustc_middle::mir::BorrowKind::Shallow => {
|
| rustc_middle::mir::BorrowKind::Fake => {
|
||||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,8 +253,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||||
let access_kind = match bk {
|
let access_kind = match bk {
|
||||||
BorrowKind::Shallow => {
|
BorrowKind::Fake => {
|
||||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||||
}
|
}
|
||||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
|
@ -376,8 +376,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
// have already taken the reservation
|
// have already taken the reservation
|
||||||
}
|
}
|
||||||
|
|
||||||
(Read(_), BorrowKind::Shallow | BorrowKind::Shared)
|
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
|
||||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||||
// Reads don't invalidate shared or shallow borrows
|
// Reads don't invalidate shared or shallow borrows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
|
|
||||||
// only mutable borrows should be 2-phase
|
// only mutable borrows should be 2-phase
|
||||||
assert!(match borrow.kind {
|
assert!(match borrow.kind {
|
||||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||||
BorrowKind::Mut { .. } => true,
|
BorrowKind::Mut { .. } => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -846,7 +846,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
enum ArtificialField {
|
enum ArtificialField {
|
||||||
ArrayLength,
|
ArrayLength,
|
||||||
ShallowBorrow,
|
FakeBorrow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -1085,18 +1085,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
(Read(_), BorrowKind::Shared | BorrowKind::Shallow)
|
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
|
||||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
(Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
|
(Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
|
||||||
// This used to be a future compatibility warning (to be
|
// This used to be a future compatibility warning (to be
|
||||||
// disallowed on NLL). See rust-lang/rust#56254
|
// disallowed on NLL). See rust-lang/rust#56254
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
(Write(WriteKind::Move), BorrowKind::Shallow) => {
|
(Write(WriteKind::Move), BorrowKind::Fake) => {
|
||||||
// Handled by initialization checks.
|
// Handled by initialization checks.
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
|
@ -1204,8 +1204,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||||
let access_kind = match bk {
|
let access_kind = match bk {
|
||||||
BorrowKind::Shallow => {
|
BorrowKind::Fake => {
|
||||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||||
}
|
}
|
||||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
|
@ -1226,7 +1226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
let action = if bk == BorrowKind::Shallow {
|
let action = if bk == BorrowKind::Fake {
|
||||||
InitializationRequiringAction::MatchOn
|
InitializationRequiringAction::MatchOn
|
||||||
} else {
|
} else {
|
||||||
InitializationRequiringAction::Borrow
|
InitializationRequiringAction::Borrow
|
||||||
|
@ -1583,7 +1583,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
// only mutable borrows should be 2-phase
|
// only mutable borrows should be 2-phase
|
||||||
assert!(match borrow.kind {
|
assert!(match borrow.kind {
|
||||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||||
BorrowKind::Mut { .. } => true,
|
BorrowKind::Mut { .. } => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2142,14 +2142,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
| WriteKind::Replace
|
| WriteKind::Replace
|
||||||
| WriteKind::StorageDeadOrDrop
|
| WriteKind::StorageDeadOrDrop
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shallow),
|
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||||
)
|
)
|
||||||
| Write(
|
| Write(
|
||||||
WriteKind::Move
|
WriteKind::Move
|
||||||
| WriteKind::Replace
|
| WriteKind::Replace
|
||||||
| WriteKind::StorageDeadOrDrop
|
| WriteKind::StorageDeadOrDrop
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||||
| WriteKind::MutableBorrow(BorrowKind::Shallow),
|
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||||
) => {
|
) => {
|
||||||
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
||||||
&& !self.has_buffered_errors()
|
&& !self.has_buffered_errors()
|
||||||
|
@ -2173,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Read(
|
Read(
|
||||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow)
|
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
|
||||||
| ReadKind::Copy,
|
| ReadKind::Copy,
|
||||||
) => {
|
) => {
|
||||||
// Access authorized
|
// Access authorized
|
||||||
|
|
|
@ -204,7 +204,7 @@ fn place_components_conflict<'tcx>(
|
||||||
|
|
||||||
match (elem, &base_ty.kind(), access) {
|
match (elem, &base_ty.kind(), access) {
|
||||||
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||||
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
|
||||||
// The array length is like additional fields on the
|
// The array length is like additional fields on the
|
||||||
// type; it does not overlap any existing data there.
|
// type; it does not overlap any existing data there.
|
||||||
// Furthermore, if cannot actually be a prefix of any
|
// Furthermore, if cannot actually be a prefix of any
|
||||||
|
@ -273,10 +273,10 @@ fn place_components_conflict<'tcx>(
|
||||||
// If the second example, where we did, then we still know
|
// If the second example, where we did, then we still know
|
||||||
// that the borrow can access a *part* of our place that
|
// that the borrow can access a *part* of our place that
|
||||||
// our access cares about, so we still have a conflict.
|
// our access cares about, so we still have a conflict.
|
||||||
if borrow_kind == BorrowKind::Shallow
|
if borrow_kind == BorrowKind::Fake
|
||||||
&& borrow_place.projection.len() < access_place.projection.len()
|
&& borrow_place.projection.len() < access_place.projection.len()
|
||||||
{
|
{
|
||||||
debug!("borrow_conflicts_with_place: shallow borrow");
|
debug!("borrow_conflicts_with_place: fake borrow");
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
||||||
|
|
|
@ -751,7 +751,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
PlaceContext::MutatingUse(_) => ty::Invariant,
|
PlaceContext::MutatingUse(_) => ty::Invariant,
|
||||||
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
|
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
|
||||||
PlaceContext::NonMutatingUse(
|
PlaceContext::NonMutatingUse(
|
||||||
Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf
|
Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | AddressOf
|
||||||
| Projection,
|
| Projection,
|
||||||
) => ty::Covariant,
|
) => ty::Covariant,
|
||||||
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
|
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
|
||||||
|
|
|
@ -219,7 +219,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
||||||
| PlaceContext::NonMutatingUse(
|
| PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::Inspect
|
NonMutatingUseContext::Inspect
|
||||||
| NonMutatingUseContext::SharedBorrow
|
| NonMutatingUseContext::SharedBorrow
|
||||||
| NonMutatingUseContext::ShallowBorrow
|
| NonMutatingUseContext::FakeBorrow
|
||||||
| NonMutatingUseContext::AddressOf
|
| NonMutatingUseContext::AddressOf
|
||||||
| NonMutatingUseContext::Projection,
|
| NonMutatingUseContext::Projection,
|
||||||
) => {
|
) => {
|
||||||
|
|
|
@ -423,8 +423,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
BorrowKind::Shared => {
|
BorrowKind::Shared => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||||
}
|
}
|
||||||
BorrowKind::Shallow => {
|
BorrowKind::Fake => {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||||
}
|
}
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||||
|
@ -500,7 +500,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
|
self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, place)
|
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
|
||||||
| Rvalue::AddressOf(Mutability::Not, place) => {
|
| Rvalue::AddressOf(Mutability::Not, place) => {
|
||||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||||
&self.ccx,
|
&self.ccx,
|
||||||
|
|
|
@ -105,7 +105,7 @@ where
|
||||||
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
mir::BorrowKind::Mut { .. } => true,
|
mir::BorrowKind::Mut { .. } => true,
|
||||||
mir::BorrowKind::Shared | mir::BorrowKind::Shallow => {
|
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
|
||||||
self.shared_borrow_allows_mutation(place)
|
self.shared_borrow_allows_mutation(place)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,7 +456,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
match kind {
|
match kind {
|
||||||
// Reject these borrow types just to be safe.
|
// Reject these borrow types just to be safe.
|
||||||
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
||||||
BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||||
return Err(Unpromotable);
|
return Err(Unpromotable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -848,11 +848,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
|
Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
|
||||||
Rvalue::Ref(_, BorrowKind::Shallow, _) => {
|
Rvalue::Ref(_, BorrowKind::Fake, _) => {
|
||||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||||
self.fail(
|
self.fail(
|
||||||
location,
|
location,
|
||||||
"`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR",
|
"`Assign` statement with a `Fake` borrow should have been removed in runtime MIR",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -942,7 +942,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
Ref(region, borrow_kind, ref place) => {
|
Ref(region, borrow_kind, ref place) => {
|
||||||
let kind_str = match borrow_kind {
|
let kind_str = match borrow_kind {
|
||||||
BorrowKind::Shared => "",
|
BorrowKind::Shared => "",
|
||||||
BorrowKind::Shallow => "shallow ",
|
BorrowKind::Fake => "fake ",
|
||||||
BorrowKind::Mut { .. } => "mut ",
|
BorrowKind::Mut { .. } => "mut ",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -446,7 +446,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
impl BorrowKind {
|
impl BorrowKind {
|
||||||
pub fn mutability(&self) -> Mutability {
|
pub fn mutability(&self) -> Mutability {
|
||||||
match *self {
|
match *self {
|
||||||
BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not,
|
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
|
||||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ impl BorrowKind {
|
||||||
pub fn allows_two_phase_borrow(&self) -> bool {
|
pub fn allows_two_phase_borrow(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
BorrowKind::Shared
|
BorrowKind::Shared
|
||||||
| BorrowKind::Shallow
|
| BorrowKind::Fake
|
||||||
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ pub enum AnalysisPhase {
|
||||||
/// * [`TerminatorKind::FalseEdge`]
|
/// * [`TerminatorKind::FalseEdge`]
|
||||||
/// * [`StatementKind::FakeRead`]
|
/// * [`StatementKind::FakeRead`]
|
||||||
/// * [`StatementKind::AscribeUserType`]
|
/// * [`StatementKind::AscribeUserType`]
|
||||||
/// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
|
/// * [`Rvalue::Ref`] with `BorrowKind::Fake`
|
||||||
///
|
///
|
||||||
/// Furthermore, `Deref` projections must be the first projection within any place (if they
|
/// Furthermore, `Deref` projections must be the first projection within any place (if they
|
||||||
/// appear at all)
|
/// appear at all)
|
||||||
|
@ -182,7 +182,7 @@ pub enum BorrowKind {
|
||||||
/// should not prevent `if let None = x { ... }`, for example, because the
|
/// should not prevent `if let None = x { ... }`, for example, because the
|
||||||
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
|
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
|
||||||
/// We can also report errors with this kind of borrow differently.
|
/// We can also report errors with this kind of borrow differently.
|
||||||
Shallow,
|
Fake,
|
||||||
|
|
||||||
/// Data is mutable and not aliasable.
|
/// Data is mutable and not aliasable.
|
||||||
Mut { kind: MutBorrowKind },
|
Mut { kind: MutBorrowKind },
|
||||||
|
|
|
@ -278,7 +278,7 @@ impl BorrowKind {
|
||||||
|
|
||||||
// We have no type corresponding to a shallow borrow, so use
|
// We have no type corresponding to a shallow borrow, so use
|
||||||
// `&` as an approximation.
|
// `&` as an approximation.
|
||||||
BorrowKind::Shallow => hir::Mutability::Not,
|
BorrowKind::Fake => hir::Mutability::Not,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -649,8 +649,8 @@ macro_rules! make_mir_visitor {
|
||||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::SharedBorrow
|
NonMutatingUseContext::SharedBorrow
|
||||||
),
|
),
|
||||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
BorrowKind::Fake => PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::ShallowBorrow
|
NonMutatingUseContext::FakeBorrow
|
||||||
),
|
),
|
||||||
BorrowKind::Mut { .. } =>
|
BorrowKind::Mut { .. } =>
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
|
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
|
||||||
|
@ -1261,8 +1261,8 @@ pub enum NonMutatingUseContext {
|
||||||
Move,
|
Move,
|
||||||
/// Shared borrow.
|
/// Shared borrow.
|
||||||
SharedBorrow,
|
SharedBorrow,
|
||||||
/// Shallow borrow.
|
/// A fake borrow.
|
||||||
ShallowBorrow,
|
FakeBorrow,
|
||||||
/// AddressOf for *const pointer.
|
/// AddressOf for *const pointer.
|
||||||
AddressOf,
|
AddressOf,
|
||||||
/// PlaceMention statement.
|
/// PlaceMention statement.
|
||||||
|
@ -1341,7 +1341,7 @@ impl PlaceContext {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
PlaceContext::NonMutatingUse(
|
PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
|
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
|
||||||
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -690,7 +690,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fake_borrow_temp.into(),
|
fake_borrow_temp.into(),
|
||||||
Rvalue::Ref(
|
Rvalue::Ref(
|
||||||
tcx.lifetimes.re_erased,
|
tcx.lifetimes.re_erased,
|
||||||
BorrowKind::Shallow,
|
BorrowKind::Fake,
|
||||||
Place { local: base_place.local, projection },
|
Place { local: base_place.local, projection },
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2021,7 +2021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let re_erased = tcx.lifetimes.re_erased;
|
let re_erased = tcx.lifetimes.re_erased;
|
||||||
let scrutinee_source_info = self.source_info(scrutinee_span);
|
let scrutinee_source_info = self.source_info(scrutinee_span);
|
||||||
for &(place, temp) in fake_borrows {
|
for &(place, temp) in fake_borrows {
|
||||||
let borrow = Rvalue::Ref(re_erased, BorrowKind::Shallow, place);
|
let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake, place);
|
||||||
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -288,7 +288,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
match borrow_kind {
|
match borrow_kind {
|
||||||
BorrowKind::Shallow | BorrowKind::Shared => {
|
BorrowKind::Fake | BorrowKind::Shared => {
|
||||||
if !ty.is_freeze(self.tcx, self.param_env) {
|
if !ty.is_freeze(self.tcx, self.param_env) {
|
||||||
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
|
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
visit::walk_expr(&mut visitor, expr);
|
visit::walk_expr(&mut visitor, expr);
|
||||||
if visitor.found {
|
if visitor.found {
|
||||||
match borrow_kind {
|
match borrow_kind {
|
||||||
BorrowKind::Shallow | BorrowKind::Shared
|
BorrowKind::Fake | BorrowKind::Shared
|
||||||
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
||||||
{
|
{
|
||||||
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
||||||
|
@ -491,7 +491,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
BorrowKind::Mut { .. } => {
|
BorrowKind::Mut { .. } => {
|
||||||
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
|
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
|
||||||
}
|
}
|
||||||
BorrowKind::Shallow | BorrowKind::Shared => {}
|
BorrowKind::Fake | BorrowKind::Shared => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ use rustc_middle::mir::*;
|
||||||
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
|
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
|
||||||
|
|
||||||
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
|
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
|
||||||
/// to a given local.
|
/// to a given local. This analysis ignores fake borrows, so it should not be used by
|
||||||
|
/// borrowck.
|
||||||
///
|
///
|
||||||
/// At present, this is used as a very limited form of alias analysis. For example,
|
/// At present, this is used as a very limited form of alias analysis. For example,
|
||||||
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
|
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
|
||||||
|
@ -91,13 +92,17 @@ where
|
||||||
self.super_rvalue(rvalue, location);
|
self.super_rvalue(rvalue, location);
|
||||||
|
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
|
// We ignore fake borrows as these get removed after analysis and shouldn't effect
|
||||||
|
// the layout of generators.
|
||||||
|
Rvalue::AddressOf(_, borrowed_place)
|
||||||
|
| Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => {
|
||||||
if !borrowed_place.is_indirect() {
|
if !borrowed_place.is_indirect() {
|
||||||
self.trans.gen(borrowed_place.local);
|
self.trans.gen(borrowed_place.local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Cast(..)
|
Rvalue::Cast(..)
|
||||||
|
| Rvalue::Ref(_, BorrowKind::Fake, _)
|
||||||
| Rvalue::ShallowInitBox(..)
|
| Rvalue::ShallowInitBox(..)
|
||||||
| Rvalue::Use(..)
|
| Rvalue::Use(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
|
|
|
@ -201,7 +201,7 @@ impl DefUse {
|
||||||
| NonMutatingUseContext::Inspect
|
| NonMutatingUseContext::Inspect
|
||||||
| NonMutatingUseContext::Move
|
| NonMutatingUseContext::Move
|
||||||
| NonMutatingUseContext::PlaceMention
|
| NonMutatingUseContext::PlaceMention
|
||||||
| NonMutatingUseContext::ShallowBorrow
|
| NonMutatingUseContext::FakeBorrow
|
||||||
| NonMutatingUseContext::SharedBorrow,
|
| NonMutatingUseContext::SharedBorrow,
|
||||||
) => Some(DefUse::Use),
|
) => Some(DefUse::Use),
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
//!
|
//!
|
||||||
//! - [`AscribeUserType`]
|
//! - [`AscribeUserType`]
|
||||||
//! - [`FakeRead`]
|
//! - [`FakeRead`]
|
||||||
//! - [`Assign`] statements with a [`Shallow`] borrow
|
//! - [`Assign`] statements with a [`Fake`] borrow
|
||||||
//!
|
//!
|
||||||
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
|
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
|
||||||
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
|
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
|
||||||
//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
|
//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
|
||||||
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
|
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
|
||||||
//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
|
//! [`Fake`]: rustc_middle::mir::BorrowKind::Fake
|
||||||
|
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
|
use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
|
||||||
|
@ -24,7 +24,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
||||||
for statement in basic_block.statements.iter_mut() {
|
for statement in basic_block.statements.iter_mut() {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::AscribeUserType(..)
|
StatementKind::AscribeUserType(..)
|
||||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
||||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -668,7 +668,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
||||||
// mutation.
|
// mutation.
|
||||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||||
| NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||||
| MutatingUse(MutatingUseContext::Borrow)
|
| MutatingUse(MutatingUseContext::Borrow)
|
||||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
| MutatingUse(MutatingUseContext::AddressOf) => {
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
||||||
let observes_address = match ctxt {
|
let observes_address = match ctxt {
|
||||||
PlaceContext::NonMutatingUse(
|
PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::SharedBorrow
|
NonMutatingUseContext::SharedBorrow
|
||||||
| NonMutatingUseContext::ShallowBorrow
|
| NonMutatingUseContext::FakeBorrow
|
||||||
| NonMutatingUseContext::AddressOf,
|
| NonMutatingUseContext::AddressOf,
|
||||||
) => true,
|
) => true,
|
||||||
// For debuginfo, merging locals is ok.
|
// For debuginfo, merging locals is ok.
|
||||||
|
|
|
@ -637,6 +637,14 @@ struct LivenessInfo {
|
||||||
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
|
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes which locals have to be stored in the state-machine for the
|
||||||
|
/// given coroutine.
|
||||||
|
///
|
||||||
|
/// The basic idea is as follows:
|
||||||
|
/// - a local is live until we encounter a `StorageDead` statement. In
|
||||||
|
/// case none exist, the local is considered to be always live.
|
||||||
|
/// - a local has to be stored if it is either directly used after the
|
||||||
|
/// the suspend point, or if it is live and has been previously borrowed.
|
||||||
fn locals_live_across_suspend_points<'tcx>(
|
fn locals_live_across_suspend_points<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
@ -1449,16 +1457,15 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
|
||||||
// The first argument is the coroutine type passed by value
|
// The first argument is the coroutine type passed by value
|
||||||
let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
|
let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
|
||||||
|
|
||||||
// Get the interior types and args which typeck computed
|
|
||||||
let movable = match *coroutine_ty.kind() {
|
let movable = match *coroutine_ty.kind() {
|
||||||
ty::Coroutine(_, _, movability) => movability == hir::Movability::Movable,
|
ty::Coroutine(_, _, movability) => movability == hir::Movability::Movable,
|
||||||
ty::Error(_) => return None,
|
ty::Error(_) => return None,
|
||||||
_ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty),
|
_ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
// When first entering the coroutine, move the resume argument into its new local.
|
// The witness simply contains all locals live across suspend points.
|
||||||
let always_live_locals = always_storage_live_locals(&body);
|
|
||||||
|
|
||||||
|
let always_live_locals = always_storage_live_locals(&body);
|
||||||
let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
||||||
|
|
||||||
// Extract locals which are live across suspension point into `layout`
|
// Extract locals which are live across suspension point into `layout`
|
||||||
|
|
|
@ -234,7 +234,7 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
|
||||||
// so we have to remove them too.
|
// so we have to remove them too.
|
||||||
PlaceContext::NonMutatingUse(
|
PlaceContext::NonMutatingUse(
|
||||||
NonMutatingUseContext::SharedBorrow
|
NonMutatingUseContext::SharedBorrow
|
||||||
| NonMutatingUseContext::ShallowBorrow
|
| NonMutatingUseContext::FakeBorrow
|
||||||
| NonMutatingUseContext::AddressOf,
|
| NonMutatingUseContext::AddressOf,
|
||||||
)
|
)
|
||||||
| PlaceContext::MutatingUse(_) => {
|
| PlaceContext::MutatingUse(_) => {
|
||||||
|
|
|
@ -455,7 +455,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind {
|
||||||
use mir::BorrowKind::*;
|
use mir::BorrowKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Shared => stable_mir::mir::BorrowKind::Shared,
|
Shared => stable_mir::mir::BorrowKind::Shared,
|
||||||
Shallow => stable_mir::mir::BorrowKind::Shallow,
|
Fake => stable_mir::mir::BorrowKind::Fake,
|
||||||
Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
|
Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::solve::EvalCtxt;
|
||||||
//
|
//
|
||||||
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
||||||
// instantiate the binder with placeholders eagerly.
|
// instantiate the binder with placeholders eagerly.
|
||||||
|
#[instrument(level = "debug", skip(ecx), ret)]
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
@ -107,6 +108,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
|
||||||
ty::Binder::bind_with_vars(ty, bound_vars)
|
ty::Binder::bind_with_vars(ty, bound_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(ecx), ret)]
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
@ -152,6 +154,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(ecx), ret)]
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
|
|
@ -437,9 +437,10 @@ pub enum BorrowKind {
|
||||||
Shared,
|
Shared,
|
||||||
|
|
||||||
/// The immediately borrowed place must be immutable, but projections from
|
/// The immediately borrowed place must be immutable, but projections from
|
||||||
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
|
/// it don't need to be. This is used to prevent match guards from replacing
|
||||||
|
/// the scrutinee. For example, a fake borrow of `a.b` doesn't
|
||||||
/// conflict with a mutable borrow of `a.b.c`.
|
/// conflict with a mutable borrow of `a.b.c`.
|
||||||
Shallow,
|
Fake,
|
||||||
|
|
||||||
/// Data is mutable and not aliasable.
|
/// Data is mutable and not aliasable.
|
||||||
Mut {
|
Mut {
|
||||||
|
|
|
@ -52,7 +52,7 @@ fn full_tested_match() -> () {
|
||||||
bb5: {
|
bb5: {
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = &((_2 as Some).0: i32);
|
_6 = &((_2 as Some).0: i32);
|
||||||
_4 = &shallow _2;
|
_4 = &fake _2;
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = guard() -> [return: bb6, unwind: bb12];
|
_7 = guard() -> [return: bb6, unwind: bb12];
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ fn full_tested_match2() -> () {
|
||||||
bb5: {
|
bb5: {
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = &((_2 as Some).0: i32);
|
_6 = &((_2 as Some).0: i32);
|
||||||
_4 = &shallow _2;
|
_4 = &fake _2;
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = guard() -> [return: bb6, unwind: bb12];
|
_7 = guard() -> [return: bb6, unwind: bb12];
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ fn main() -> () {
|
||||||
bb8: {
|
bb8: {
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = &((_2 as Some).0: i32);
|
_7 = &((_2 as Some).0: i32);
|
||||||
_5 = &shallow _2;
|
_5 = &fake _2;
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = guard() -> [return: bb9, unwind: bb20];
|
_8 = guard() -> [return: bb9, unwind: bb20];
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ fn main() -> () {
|
||||||
bb14: {
|
bb14: {
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
_11 = &((_2 as Some).0: i32);
|
_11 = &((_2 as Some).0: i32);
|
||||||
_5 = &shallow _2;
|
_5 = &fake _2;
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = (*_11);
|
_13 = (*_11);
|
||||||
|
|
|
@ -80,8 +80,8 @@
|
||||||
_6 = &(_2.1: bool);
|
_6 = &(_2.1: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &shallow (_2.0: bool);
|
- _3 = &fake (_2.0: bool);
|
||||||
- _4 = &shallow (_2.1: bool);
|
- _4 = &fake (_2.1: bool);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = _1;
|
_10 = _1;
|
||||||
|
@ -137,8 +137,8 @@
|
||||||
_6 = &(_2.0: bool);
|
_6 = &(_2.0: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &shallow (_2.0: bool);
|
- _3 = &fake (_2.0: bool);
|
||||||
- _4 = &shallow (_2.1: bool);
|
- _4 = &fake (_2.1: bool);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = _1;
|
_13 = _1;
|
||||||
|
|
|
@ -80,8 +80,8 @@
|
||||||
_6 = &(_2.1: bool);
|
_6 = &(_2.1: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &shallow (_2.0: bool);
|
- _3 = &fake (_2.0: bool);
|
||||||
- _4 = &shallow (_2.1: bool);
|
- _4 = &fake (_2.1: bool);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = _1;
|
_10 = _1;
|
||||||
|
@ -137,8 +137,8 @@
|
||||||
_6 = &(_2.0: bool);
|
_6 = &(_2.0: bool);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = &(_2.2: std::string::String);
|
_8 = &(_2.2: std::string::String);
|
||||||
- _3 = &shallow (_2.0: bool);
|
- _3 = &fake (_2.0: bool);
|
||||||
- _4 = &shallow (_2.1: bool);
|
- _4 = &fake (_2.1: bool);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_13 = _1;
|
_13 = _1;
|
||||||
|
|
|
@ -68,7 +68,7 @@ fn main() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
_8 = &shallow _1;
|
_8 = &fake _1;
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
_9 = _2;
|
_9 = _2;
|
||||||
switchInt(move _9) -> [0: bb11, otherwise: bb10];
|
switchInt(move _9) -> [0: bb11, otherwise: bb10];
|
||||||
|
|
|
@ -33,10 +33,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
- _4 = &shallow _1;
|
- _4 = &fake _1;
|
||||||
- _5 = &shallow (*((_1 as Some).0: &&i32));
|
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||||
- _6 = &shallow ((_1 as Some).0: &&i32);
|
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||||
- _7 = &shallow (*(*((_1 as Some).0: &&i32)));
|
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
|
|
@ -33,10 +33,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
- _4 = &shallow _1;
|
- _4 = &fake _1;
|
||||||
- _5 = &shallow (*((_1 as Some).0: &&i32));
|
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||||
- _6 = &shallow ((_1 as Some).0: &&i32);
|
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||||
- _7 = &shallow (*(*((_1 as Some).0: &&i32)));
|
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
+ nop;
|
+ nop;
|
||||||
|
|
34
tests/ui/coroutine/witness-ignore-fake-reads.rs
Normal file
34
tests/ui/coroutine/witness-ignore-fake-reads.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// check-pass
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
// regression test for #117059
|
||||||
|
struct SendNotSync(*const ());
|
||||||
|
unsafe impl Send for SendNotSync {}
|
||||||
|
// impl !Sync for SendNotSync {} // automatically disabled
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
stream: SendNotSync,
|
||||||
|
state: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SendSync;
|
||||||
|
impl std::ops::Deref for SendSync {
|
||||||
|
type Target = Inner;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn next() {
|
||||||
|
let inner = SendSync;
|
||||||
|
match inner.state {
|
||||||
|
true if false => {}
|
||||||
|
false => async {}.await,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_send<T: Send>(_: T) {}
|
||||||
|
fn main() {
|
||||||
|
is_send(next())
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue