mirror of https://github.com/rust-lang/rust.git
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
|
@ -71,7 +71,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let kind = match self.kind {
|
||||
mir::BorrowKind::Shared => "",
|
||||
mir::BorrowKind::Shallow => "shallow ",
|
||||
mir::BorrowKind::Fake => "fake ",
|
||||
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
||||
// FIXME: differentiate `TwoPhaseBorrow`
|
||||
mir::BorrowKind::Mut {
|
||||
|
|
|
@ -49,7 +49,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||
// cross suspension points so this behavior is unproblematic.
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) |
|
||||
|
||||
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
|
||||
// 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)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Fake) => {
|
||||
if let Some(immutable_section_description) =
|
||||
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::Shallow,
|
||||
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
|
||||
) => unreachable!(),
|
||||
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
|
||||
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if issued_spans == borrow_spans {
|
||||
|
@ -2806,7 +2805,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let loan_span = loan_spans.args_or_use();
|
||||
|
||||
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) {
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
|
|
|
@ -634,7 +634,7 @@ impl UseSpans<'_> {
|
|||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Shallow => {
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
|
|
|
@ -253,8 +253,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
BorrowKind::Fake => {
|
||||
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
}
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Mut { .. } => {
|
||||
|
@ -376,8 +376,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
// have already taken the reservation
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shallow | BorrowKind::Shared)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
||||
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||
// 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
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
|
|
|
@ -846,7 +846,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum ArtificialField {
|
||||
ArrayLength,
|
||||
ShallowBorrow,
|
||||
FakeBorrow,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
|
@ -1085,18 +1085,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Shallow)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
|
||||
(Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
|
||||
// This used to be a future compatibility warning (to be
|
||||
// disallowed on NLL). See rust-lang/rust#56254
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Write(WriteKind::Move), BorrowKind::Shallow) => {
|
||||
(Write(WriteKind::Move), BorrowKind::Fake) => {
|
||||
// Handled by initialization checks.
|
||||
Control::Continue
|
||||
}
|
||||
|
@ -1204,8 +1204,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
BorrowKind::Fake => {
|
||||
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
}
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Mut { .. } => {
|
||||
|
@ -1226,7 +1226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
flow_state,
|
||||
);
|
||||
|
||||
let action = if bk == BorrowKind::Shallow {
|
||||
let action = if bk == BorrowKind::Fake {
|
||||
InitializationRequiringAction::MatchOn
|
||||
} else {
|
||||
InitializationRequiringAction::Borrow
|
||||
|
@ -1583,7 +1583,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
||||
BorrowKind::Shared | BorrowKind::Fake => false,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
|
@ -2142,14 +2142,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shared)
|
||||
| WriteKind::MutableBorrow(BorrowKind::Shallow),
|
||||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||
)
|
||||
| Write(
|
||||
WriteKind::Move
|
||||
| WriteKind::Replace
|
||||
| WriteKind::StorageDeadOrDrop
|
||||
| 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()
|
||||
&& !self.has_buffered_errors()
|
||||
|
@ -2173,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
Read(
|
||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow)
|
||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
|
||||
| ReadKind::Copy,
|
||||
) => {
|
||||
// Access authorized
|
||||
|
|
|
@ -204,7 +204,7 @@ fn place_components_conflict<'tcx>(
|
|||
|
||||
match (elem, &base_ty.kind(), access) {
|
||||
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
||||
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
|
||||
// The array length is like additional fields on the
|
||||
// type; it does not overlap any existing data there.
|
||||
// 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
|
||||
// that the borrow can access a *part* of our place that
|
||||
// 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()
|
||||
{
|
||||
debug!("borrow_conflicts_with_place: shallow borrow");
|
||||
debug!("borrow_conflicts_with_place: fake borrow");
|
||||
false
|
||||
} else {
|
||||
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::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
|
||||
PlaceContext::NonMutatingUse(
|
||||
Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf
|
||||
Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | AddressOf
|
||||
| Projection,
|
||||
) => ty::Covariant,
|
||||
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
|
||||
|
|
|
@ -219,7 +219,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
| PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::Inspect
|
||||
| NonMutatingUseContext::SharedBorrow
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::AddressOf
|
||||
| NonMutatingUseContext::Projection,
|
||||
) => {
|
||||
|
|
|
@ -423,8 +423,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
BorrowKind::Shared => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
}
|
||||
BorrowKind::Shallow => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
||||
BorrowKind::Fake => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
|
@ -500,7 +500,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
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) => {
|
||||
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
|
||||
&self.ccx,
|
||||
|
|
|
@ -105,7 +105,7 @@ where
|
|||
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
||||
match kind {
|
||||
mir::BorrowKind::Mut { .. } => true,
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Shallow => {
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
|
||||
self.shared_borrow_allows_mutation(place)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -456,7 +456,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
match kind {
|
||||
// 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.
|
||||
BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||
BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
|
|
|
@ -848,11 +848,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
match rvalue {
|
||||
Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
|
||||
Rvalue::Ref(_, BorrowKind::Shallow, _) => {
|
||||
Rvalue::Ref(_, BorrowKind::Fake, _) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
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) => {
|
||||
let kind_str = match borrow_kind {
|
||||
BorrowKind::Shared => "",
|
||||
BorrowKind::Shallow => "shallow ",
|
||||
BorrowKind::Fake => "fake ",
|
||||
BorrowKind::Mut { .. } => "mut ",
|
||||
};
|
||||
|
||||
|
|
|
@ -446,7 +446,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
impl BorrowKind {
|
||||
pub fn mutability(&self) -> Mutability {
|
||||
match *self {
|
||||
BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not,
|
||||
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
|
||||
BorrowKind::Mut { .. } => Mutability::Mut,
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +454,7 @@ impl BorrowKind {
|
|||
pub fn allows_two_phase_borrow(&self) -> bool {
|
||||
match *self {
|
||||
BorrowKind::Shared
|
||||
| BorrowKind::Shallow
|
||||
| BorrowKind::Fake
|
||||
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ pub enum AnalysisPhase {
|
|||
/// * [`TerminatorKind::FalseEdge`]
|
||||
/// * [`StatementKind::FakeRead`]
|
||||
/// * [`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
|
||||
/// appear at all)
|
||||
|
@ -182,7 +182,7 @@ pub enum BorrowKind {
|
|||
/// should not prevent `if let None = x { ... }`, for example, because the
|
||||
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
|
||||
/// We can also report errors with this kind of borrow differently.
|
||||
Shallow,
|
||||
Fake,
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
Mut { kind: MutBorrowKind },
|
||||
|
|
|
@ -278,7 +278,7 @@ impl BorrowKind {
|
|||
|
||||
// We have no type corresponding to a shallow borrow, so use
|
||||
// `&` 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(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow
|
||||
BorrowKind::Fake => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::FakeBorrow
|
||||
),
|
||||
BorrowKind::Mut { .. } =>
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
|
||||
|
@ -1261,8 +1261,8 @@ pub enum NonMutatingUseContext {
|
|||
Move,
|
||||
/// Shared borrow.
|
||||
SharedBorrow,
|
||||
/// Shallow borrow.
|
||||
ShallowBorrow,
|
||||
/// A fake borrow.
|
||||
FakeBorrow,
|
||||
/// AddressOf for *const pointer.
|
||||
AddressOf,
|
||||
/// PlaceMention statement.
|
||||
|
@ -1341,7 +1341,7 @@ impl PlaceContext {
|
|||
matches!(
|
||||
self,
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
|
||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
|
||||
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -690,7 +690,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fake_borrow_temp.into(),
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Shallow,
|
||||
BorrowKind::Fake,
|
||||
Place { local: base_place.local, projection },
|
||||
),
|
||||
);
|
||||
|
|
|
@ -2021,7 +2021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let scrutinee_source_info = self.source_info(scrutinee_span);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -288,7 +288,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
);
|
||||
};
|
||||
match borrow_kind {
|
||||
BorrowKind::Shallow | BorrowKind::Shared => {
|
||||
BorrowKind::Fake | BorrowKind::Shared => {
|
||||
if !ty.is_freeze(self.tcx, self.param_env) {
|
||||
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);
|
||||
if visitor.found {
|
||||
match borrow_kind {
|
||||
BorrowKind::Shallow | BorrowKind::Shared
|
||||
BorrowKind::Fake | BorrowKind::Shared
|
||||
if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
|
||||
{
|
||||
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
|
||||
|
@ -491,7 +491,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
BorrowKind::Mut { .. } => {
|
||||
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};
|
||||
|
||||
/// 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,
|
||||
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
|
||||
|
@ -91,13 +92,17 @@ where
|
|||
self.super_rvalue(rvalue, location);
|
||||
|
||||
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() {
|
||||
self.trans.gen(borrowed_place.local);
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Cast(..)
|
||||
| Rvalue::Ref(_, BorrowKind::Fake, _)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
|
|
|
@ -201,7 +201,7 @@ impl DefUse {
|
|||
| NonMutatingUseContext::Inspect
|
||||
| NonMutatingUseContext::Move
|
||||
| NonMutatingUseContext::PlaceMention
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::SharedBorrow,
|
||||
) => Some(DefUse::Use),
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
//!
|
||||
//! - [`AscribeUserType`]
|
||||
//! - [`FakeRead`]
|
||||
//! - [`Assign`] statements with a [`Shallow`] borrow
|
||||
//! - [`Assign`] statements with a [`Fake`] borrow
|
||||
//!
|
||||
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
|
||||
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
|
||||
//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
|
||||
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
|
||||
//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
|
||||
//! [`Fake`]: rustc_middle::mir::BorrowKind::Fake
|
||||
|
||||
use crate::MirPass;
|
||||
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() {
|
||||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
||||
| 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
|
||||
// mutation.
|
||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||
| MutatingUse(MutatingUseContext::Borrow)
|
||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
||||
|
|
|
@ -131,7 +131,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
|||
let observes_address = match ctxt {
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::AddressOf,
|
||||
) => true,
|
||||
// For debuginfo, merging locals is ok.
|
||||
|
|
|
@ -637,6 +637,14 @@ struct LivenessInfo {
|
|||
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>(
|
||||
tcx: TyCtxt<'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
|
||||
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() {
|
||||
ty::Coroutine(_, _, movability) => movability == hir::Movability::Movable,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty),
|
||||
};
|
||||
|
||||
// When first entering the coroutine, move the resume argument into its new local.
|
||||
let always_live_locals = always_storage_live_locals(&body);
|
||||
// The witness simply contains all locals live across suspend points.
|
||||
|
||||
let always_live_locals = always_storage_live_locals(&body);
|
||||
let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
||||
|
||||
// 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.
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::AddressOf,
|
||||
)
|
||||
| PlaceContext::MutatingUse(_) => {
|
||||
|
|
|
@ -455,7 +455,7 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind {
|
|||
use mir::BorrowKind::*;
|
||||
match *self {
|
||||
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) },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::solve::EvalCtxt;
|
|||
//
|
||||
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
||||
// instantiate the binder with placeholders eagerly.
|
||||
#[instrument(level = "debug", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, '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)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, '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>(
|
||||
ecx: &EvalCtxt<'_, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
|
@ -437,9 +437,10 @@ pub enum BorrowKind {
|
|||
Shared,
|
||||
|
||||
/// 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`.
|
||||
Shallow,
|
||||
Fake,
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
Mut {
|
||||
|
|
|
@ -52,7 +52,7 @@ fn full_tested_match() -> () {
|
|||
bb5: {
|
||||
StorageLive(_6);
|
||||
_6 = &((_2 as Some).0: i32);
|
||||
_4 = &shallow _2;
|
||||
_4 = &fake _2;
|
||||
StorageLive(_7);
|
||||
_7 = guard() -> [return: bb6, unwind: bb12];
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ fn full_tested_match2() -> () {
|
|||
bb5: {
|
||||
StorageLive(_6);
|
||||
_6 = &((_2 as Some).0: i32);
|
||||
_4 = &shallow _2;
|
||||
_4 = &fake _2;
|
||||
StorageLive(_7);
|
||||
_7 = guard() -> [return: bb6, unwind: bb12];
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ fn main() -> () {
|
|||
bb8: {
|
||||
StorageLive(_7);
|
||||
_7 = &((_2 as Some).0: i32);
|
||||
_5 = &shallow _2;
|
||||
_5 = &fake _2;
|
||||
StorageLive(_8);
|
||||
_8 = guard() -> [return: bb9, unwind: bb20];
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ fn main() -> () {
|
|||
bb14: {
|
||||
StorageLive(_11);
|
||||
_11 = &((_2 as Some).0: i32);
|
||||
_5 = &shallow _2;
|
||||
_5 = &fake _2;
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = (*_11);
|
||||
|
|
|
@ -80,8 +80,8 @@
|
|||
_6 = &(_2.1: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &shallow (_2.0: bool);
|
||||
- _4 = &shallow (_2.1: bool);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = _1;
|
||||
|
@ -137,8 +137,8 @@
|
|||
_6 = &(_2.0: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &shallow (_2.0: bool);
|
||||
- _4 = &shallow (_2.1: bool);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = _1;
|
||||
|
|
|
@ -80,8 +80,8 @@
|
|||
_6 = &(_2.1: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &shallow (_2.0: bool);
|
||||
- _4 = &shallow (_2.1: bool);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = _1;
|
||||
|
@ -137,8 +137,8 @@
|
|||
_6 = &(_2.0: bool);
|
||||
StorageLive(_8);
|
||||
_8 = &(_2.2: std::string::String);
|
||||
- _3 = &shallow (_2.0: bool);
|
||||
- _4 = &shallow (_2.1: bool);
|
||||
- _3 = &fake (_2.0: bool);
|
||||
- _4 = &fake (_2.1: bool);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = _1;
|
||||
|
|
|
@ -68,7 +68,7 @@ fn main() -> () {
|
|||
}
|
||||
|
||||
bb9: {
|
||||
_8 = &shallow _1;
|
||||
_8 = &fake _1;
|
||||
StorageLive(_9);
|
||||
_9 = _2;
|
||||
switchInt(move _9) -> [0: bb11, otherwise: bb10];
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
}
|
||||
|
||||
bb4: {
|
||||
- _4 = &shallow _1;
|
||||
- _5 = &shallow (*((_1 as Some).0: &&i32));
|
||||
- _6 = &shallow ((_1 as Some).0: &&i32);
|
||||
- _7 = &shallow (*(*((_1 as Some).0: &&i32)));
|
||||
- _4 = &fake _1;
|
||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
}
|
||||
|
||||
bb4: {
|
||||
- _4 = &shallow _1;
|
||||
- _5 = &shallow (*((_1 as Some).0: &&i32));
|
||||
- _6 = &shallow ((_1 as Some).0: &&i32);
|
||||
- _7 = &shallow (*(*((_1 as Some).0: &&i32)));
|
||||
- _4 = &fake _1;
|
||||
- _5 = &fake (*((_1 as Some).0: &&i32));
|
||||
- _6 = &fake ((_1 as Some).0: &&i32);
|
||||
- _7 = &fake (*(*((_1 as Some).0: &&i32)));
|
||||
+ nop;
|
||||
+ nop;
|
||||
+ nop;
|
||||
|
|
|
@ -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…
Reference in New Issue