Auto merge of #117764 - cuviper:beta-next, r=cuviper
[beta] backports - dropck_outlives check whether generator witness needs_drop #117134 - Make sure that predicates with unmentioned bound vars are still considered global in the old solver #117589 - Check binders with bound vars for global bounds that don't hold #117637 - generator layout: ignore fake borrows #117712 r? ghost
This commit is contained in:
commit
fbf0758499
57 changed files with 307 additions and 183 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,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)
|
||||
{
|
||||
|
|
@ -1117,11 +1117,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 {
|
||||
|
|
@ -2644,7 +2643,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,
|
||||
|
|
|
|||
|
|
@ -628,7 +628,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,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -837,7 +837,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)]
|
||||
|
|
@ -1076,18 +1076,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
|
||||
}
|
||||
|
|
@ -1195,8 +1195,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 { .. } => {
|
||||
|
|
@ -1217,7 +1217,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
|
||||
|
|
@ -1569,7 +1569,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,
|
||||
});
|
||||
|
||||
|
|
@ -2002,14 +2002,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()
|
||||
|
|
@ -2033,7 +2033,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
|
||||
|
|
@ -272,10 +272,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");
|
||||
|
|
|
|||
|
|
@ -745,7 +745,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,
|
||||
|
|
|
|||
|
|
@ -234,7 +234,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,
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -415,8 +415,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)
|
||||
|
|
@ -491,7 +491,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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,7 +454,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -821,11 +821,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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
|
|||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
|
||||
};
|
||||
use rustc_type_ir::TypeFlags;
|
||||
|
||||
use std::cell::LazyCell;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
|
@ -1862,7 +1863,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
// Match the existing behavior.
|
||||
if pred.is_global() && !pred.has_late_bound_vars() {
|
||||
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
|
||||
let pred = self.normalize(span, None, pred);
|
||||
let hir_node = tcx.hir().find_by_def_id(self.body_def_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -924,7 +924,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 ",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -443,7 +443,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,
|
||||
}
|
||||
}
|
||||
|
|
@ -451,7 +451,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 },
|
||||
|
|
|
|||
|
|
@ -273,7 +273,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -647,8 +647,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),
|
||||
|
|
@ -1253,8 +1253,8 @@ pub enum NonMutatingUseContext {
|
|||
Move,
|
||||
/// Shared borrow.
|
||||
SharedBorrow,
|
||||
/// Shallow borrow.
|
||||
ShallowBorrow,
|
||||
/// A fake borrow.
|
||||
FakeBorrow,
|
||||
/// AddressOf for *const pointer.
|
||||
AddressOf,
|
||||
/// PlaceMention statement.
|
||||
|
|
@ -1333,7 +1333,7 @@ impl PlaceContext {
|
|||
matches!(
|
||||
self,
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
|
||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
|
||||
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
// If there's nothing to erase avoid performing the query at all
|
||||
if !value.has_type_flags(TypeFlags::HAS_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
|
||||
// If there's nothing to erase or anonymize, avoid performing the query at all
|
||||
if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
|
||||
return value;
|
||||
}
|
||||
debug!("erase_regions({:?})", value);
|
||||
|
|
|
|||
|
|
@ -34,26 +34,6 @@ impl FlagComputation {
|
|||
result.flags
|
||||
}
|
||||
|
||||
pub fn bound_var_flags(vars: &ty::List<ty::BoundVariableKind>) -> FlagComputation {
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
for bv in vars {
|
||||
match bv {
|
||||
ty::BoundVariableKind::Ty(_) => {
|
||||
computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Region(_) => {
|
||||
computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
|
||||
}
|
||||
ty::BoundVariableKind::Const => {
|
||||
computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
computation
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
self.flags = self.flags | flags;
|
||||
}
|
||||
|
|
@ -77,7 +57,11 @@ impl FlagComputation {
|
|||
where
|
||||
F: FnOnce(&mut Self, T),
|
||||
{
|
||||
let mut computation = FlagComputation::bound_var_flags(value.bound_vars());
|
||||
let mut computation = FlagComputation::new();
|
||||
|
||||
if !value.bound_vars().is_empty() {
|
||||
computation.add_flags(TypeFlags::HAS_BINDER_VARS);
|
||||
}
|
||||
|
||||
f(&mut computation, value.skip_binder());
|
||||
|
||||
|
|
|
|||
|
|
@ -1097,8 +1097,10 @@ impl<'tcx> Ty<'tcx> {
|
|||
// This doesn't depend on regions, so try to minimize distinct
|
||||
// query keys used.
|
||||
// If normalization fails, we just use `query_ty`.
|
||||
let query_ty =
|
||||
tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
|
||||
debug_assert!(!param_env.has_infer());
|
||||
let query_ty = tcx
|
||||
.try_normalize_erasing_regions(param_env, query_ty)
|
||||
.unwrap_or_else(|_| tcx.erase_regions(query_ty));
|
||||
|
||||
tcx.needs_drop_raw(param_env.and(query_ty))
|
||||
}
|
||||
|
|
@ -1287,7 +1289,6 @@ pub fn needs_drop_components<'tcx>(
|
|||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Char
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::RawPtr(_)
|
||||
| ty::Ref(..)
|
||||
| ty::Str => Ok(SmallVec::new()),
|
||||
|
|
@ -1327,7 +1328,8 @@ pub fn needs_drop_components<'tcx>(
|
|||
| ty::Placeholder(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..) => Ok(smallvec![ty]),
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..) => Ok(smallvec![ty]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,15 +494,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
|
|||
&mut self,
|
||||
t: &Binder<'tcx, T>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
// If we're looking for any of the HAS_*_LATE_BOUND flags, we need to
|
||||
// additionally consider the bound vars on the binder itself, even if
|
||||
// the contents of a the binder (e.g. a `TraitRef`) doesn't reference
|
||||
// the bound vars.
|
||||
if self.flags.intersects(TypeFlags::HAS_LATE_BOUND) {
|
||||
let bound_var_flags = FlagComputation::bound_var_flags(t.bound_vars());
|
||||
if bound_var_flags.flags.intersects(self.flags) {
|
||||
return ControlFlow::Break(FoundFlags);
|
||||
}
|
||||
// If we're looking for the HAS_BINDER_VARS flag, check if the
|
||||
// binder has vars. This won't be present in the binder's bound
|
||||
// value, so we need to check here too.
|
||||
if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
|
||||
return ControlFlow::Break(FoundFlags);
|
||||
}
|
||||
|
||||
t.super_visit_with(self)
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2004,7 +2004,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,7 +259,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);
|
||||
}
|
||||
|
|
@ -446,7 +446,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)
|
||||
|
|
@ -454,7 +454,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(),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -683,7 +683,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.
|
||||
|
|
|
|||
|
|
@ -583,6 +583,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>,
|
||||
|
|
@ -1392,16 +1400,15 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
|
|||
// The first argument is the generator type passed by value
|
||||
let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
|
||||
|
||||
// Get the interior types and args which typeck computed
|
||||
let movable = match *gen_ty.kind() {
|
||||
ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
|
||||
};
|
||||
|
||||
// When first entering the generator, 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`
|
||||
|
|
|
|||
|
|
@ -247,7 +247,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(_) => {
|
||||
|
|
|
|||
|
|
@ -335,7 +335,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. generator 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>,
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
result.overflows.len(),
|
||||
ty_stack.len()
|
||||
);
|
||||
dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
|
||||
dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?;
|
||||
|
||||
// "outlives" represent types/regions that may be touched
|
||||
// by a destructor.
|
||||
|
|
@ -185,16 +185,15 @@ pub fn compute_dropck_outlives_inner<'tcx>(
|
|||
|
||||
/// Returns a set of constraints that needs to be satisfied in
|
||||
/// order for `ty` to be valid for destruction.
|
||||
#[instrument(level = "debug", skip(tcx, param_env, span, constraints))]
|
||||
pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
for_ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
ty: Ty<'tcx>,
|
||||
constraints: &mut DropckConstraint<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(depth) {
|
||||
constraints.overflows.push(ty);
|
||||
return Ok(());
|
||||
|
|
@ -224,13 +223,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
|||
ty::Array(ety, _) | ty::Slice(ety) => {
|
||||
// single-element containers, behave like their element
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints)
|
||||
dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
for ty in tys.iter() {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
|
||||
dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?,
|
||||
|
|
@ -249,7 +248,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
|||
|
||||
rustc_data_structures::stack::ensure_sufficient_stack(|| {
|
||||
for ty in args.as_closure().upvar_tys() {
|
||||
dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
|
||||
dtorck_constraint_for_ty_inner(
|
||||
tcx,
|
||||
param_env,
|
||||
span,
|
||||
depth + 1,
|
||||
ty,
|
||||
constraints,
|
||||
)?;
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?
|
||||
|
|
@ -278,8 +284,8 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
|||
// only take place through references with lifetimes
|
||||
// derived from lifetimes attached to the upvars and resume
|
||||
// argument, and we *do* incorporate those here.
|
||||
|
||||
if !args.as_generator().is_valid() {
|
||||
let args = args.as_generator();
|
||||
if !args.is_valid() {
|
||||
// By the time this code runs, all type variables ought to
|
||||
// be fully resolved.
|
||||
tcx.sess.delay_span_bug(
|
||||
|
|
@ -289,10 +295,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
|||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
constraints
|
||||
.outlives
|
||||
.extend(args.as_generator().upvar_tys().iter().map(ty::GenericArg::from));
|
||||
constraints.outlives.push(args.as_generator().resume_ty().into());
|
||||
// While we conservatively assume that all coroutines require drop
|
||||
// to avoid query cycles during MIR building, we can check the actual
|
||||
// witness during borrowck to avoid unnecessary liveness constraints.
|
||||
if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) {
|
||||
constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
|
||||
constraints.outlives.push(args.resume_ty().into());
|
||||
}
|
||||
}
|
||||
|
||||
ty::Adt(def, args) => {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub(crate) fn adt_dtorck_constraint(
|
|||
) -> Result<&DropckConstraint<'_>, NoSolution> {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
debug!("dtorck_constraint: {:?}", def);
|
||||
|
||||
if def.is_manually_drop() {
|
||||
|
|
@ -55,7 +56,7 @@ pub(crate) fn adt_dtorck_constraint(
|
|||
let mut result = DropckConstraint::empty();
|
||||
for field in def.all_fields() {
|
||||
let fty = tcx.type_of(field.did).instantiate_identity();
|
||||
dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?;
|
||||
dtorck_constraint_for_ty_inner(tcx, param_env, span, 0, fty, &mut result)?;
|
||||
}
|
||||
result.outlives.extend(tcx.destructor_constraints(def));
|
||||
dedup_dtorck_constraint(&mut result);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ fn has_significant_drop_raw<'tcx>(
|
|||
struct NeedsDropTypes<'tcx, F> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
// Whether to reveal coroutine witnesses, this is set
|
||||
// to `false` unless we compute `needs_drop` for a coroutine witness.
|
||||
reveal_coroutine_witnesses: bool,
|
||||
query_ty: Ty<'tcx>,
|
||||
seen_tys: FxHashSet<Ty<'tcx>>,
|
||||
/// A stack of types left to process, and the recursion depth when we
|
||||
|
|
@ -89,6 +92,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
|
|||
Self {
|
||||
tcx,
|
||||
param_env,
|
||||
reveal_coroutine_witnesses: false,
|
||||
seen_tys,
|
||||
query_ty: ty,
|
||||
unchecked_tys: vec![(ty, 0)],
|
||||
|
|
@ -133,8 +137,31 @@ where
|
|||
// The information required to determine whether a generator has drop is
|
||||
// computed on MIR, while this very method is used to build MIR.
|
||||
// To avoid cycles, we consider that generators always require drop.
|
||||
ty::Generator(..) => {
|
||||
return Some(Err(AlwaysRequiresDrop));
|
||||
//
|
||||
// HACK: Because we erase regions contained in the coroutine witness, we
|
||||
// have to conservatively assume that every region captured by the
|
||||
// coroutine has to be live when dropped. This results in a lot of
|
||||
// undesirable borrowck errors. During borrowck, we call `needs_drop`
|
||||
// for the coroutine witness and check whether any of the contained types
|
||||
// need to be dropped, and only require the captured types to be live
|
||||
// if they do.
|
||||
ty::Generator(_, args, _) => {
|
||||
if self.reveal_coroutine_witnesses {
|
||||
queue_type(self, args.as_generator().witness());
|
||||
} else {
|
||||
return Some(Err(AlwaysRequiresDrop));
|
||||
}
|
||||
}
|
||||
ty::GeneratorWitness(def_id, args) => {
|
||||
if let Some(witness) = tcx.mir_generator_witnesses(def_id) {
|
||||
self.reveal_coroutine_witnesses = true;
|
||||
for field_ty in &witness.field_tys {
|
||||
queue_type(
|
||||
self,
|
||||
EarlyBinder::bind(field_ty.ty).instantiate(tcx, args),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
|
||||
|
|
@ -191,7 +218,6 @@ where
|
|||
| ty::FnPtr(..)
|
||||
| ty::Tuple(_)
|
||||
| ty::Bound(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Never
|
||||
| ty::Infer(_)
|
||||
| ty::Error(_) => {
|
||||
|
|
|
|||
|
|
@ -299,6 +299,9 @@ bitflags! {
|
|||
|
||||
/// Does this have `Generator` or `GeneratorWitness`?
|
||||
const HAS_TY_GENERATOR = 1 << 23;
|
||||
|
||||
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
|
||||
const HAS_BINDER_VARS = 1 << 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ pub enum TyKind<I: Interner> {
|
|||
/// the type of the generator, we convert them to higher ranked
|
||||
/// lifetimes bound by the witness itself.
|
||||
///
|
||||
/// This variant is only using when `drop_tracking_mir` is set.
|
||||
/// This contains the `DefId` and the `GenericArgsRef` of the generator.
|
||||
/// The actual witness types are computed on MIR by the `mir_generator_witnesses` query.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -363,9 +363,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 {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,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];
|
||||
|
|
|
|||
|
|
@ -34,10 +34,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;
|
||||
|
|
|
|||
|
|
@ -34,10 +34,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;
|
||||
|
|
|
|||
18
tests/ui/dropck/coroutine-liveness-1.rs
Normal file
18
tests/ui/dropck/coroutine-liveness-1.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// check-pass
|
||||
// edition: 2021
|
||||
|
||||
// regression test for #116242.
|
||||
use std::future;
|
||||
|
||||
fn main() {
|
||||
let mut recv = future::ready(());
|
||||
let _combined_fut = async {
|
||||
let _ = || read(&mut recv);
|
||||
};
|
||||
|
||||
drop(recv);
|
||||
}
|
||||
|
||||
fn read<F: future::Future>(_: &mut F) -> F::Output {
|
||||
todo!()
|
||||
}
|
||||
23
tests/ui/dropck/coroutine-liveness-2.rs
Normal file
23
tests/ui/dropck/coroutine-liveness-2.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// check-pass
|
||||
// edition: 2021
|
||||
|
||||
// regression test found while working on #117134.
|
||||
use std::future;
|
||||
|
||||
fn main() {
|
||||
let mut recv = future::ready(());
|
||||
let _combined_fut = async {
|
||||
let _ = || read(&mut recv);
|
||||
};
|
||||
|
||||
let _uwu = (String::new(), _combined_fut);
|
||||
// Dropping a coroutine as part of a more complex
|
||||
// types should not add unnecessary liveness
|
||||
// constraints.
|
||||
|
||||
drop(recv);
|
||||
}
|
||||
|
||||
fn read<F: future::Future>(_: &mut F) -> F::Output {
|
||||
todo!()
|
||||
}
|
||||
|
|
@ -1,24 +1,16 @@
|
|||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/borrowing.rs:9:33
|
||||
|
|
||||
LL | let _b = {
|
||||
| -- borrow later stored here
|
||||
LL | let a = 3;
|
||||
LL | Pin::new(&mut || yield &a).resume(())
|
||||
| ----------^
|
||||
| | |
|
||||
| | borrowed value does not live long enough
|
||||
| -- ^ borrowed value does not live long enough
|
||||
| |
|
||||
| value captured here by generator
|
||||
| a temporary with access to the borrow is created here ...
|
||||
LL |
|
||||
LL | };
|
||||
| -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator
|
||||
| |
|
||||
| `a` dropped here while still borrowed
|
||||
|
|
||||
= note: the temporary is part of an expression at the end of a block;
|
||||
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
|
||||
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
||||
|
|
||||
LL | let x = Pin::new(&mut || yield &a).resume(()); x
|
||||
| +++++++ +++
|
||||
| - `a` dropped here while still borrowed
|
||||
|
||||
error[E0597]: `a` does not live long enough
|
||||
--> $DIR/borrowing.rs:16:20
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// edition:2021
|
||||
// check-pass
|
||||
#![feature(generators)]
|
||||
|
||||
fn main() {
|
||||
|
|
@ -6,6 +7,5 @@ fn main() {
|
|||
|| {
|
||||
let _c = || yield *&mut *x;
|
||||
|| _ = &mut *x;
|
||||
//~^ cannot borrow `*x` as mutable more than once at a time
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
error[E0499]: cannot borrow `*x` as mutable more than once at a time
|
||||
--> $DIR/issue-110929-generator-conflict-error-ice.rs:8:9
|
||||
|
|
||||
LL | let _c = || yield *&mut *x;
|
||||
| -- -- first borrow occurs due to use of `*x` in generator
|
||||
| |
|
||||
| first mutable borrow occurs here
|
||||
LL | || _ = &mut *x;
|
||||
| ^^ -- second borrow occurs due to use of `*x` in closure
|
||||
| |
|
||||
| second mutable borrow occurs here
|
||||
LL |
|
||||
LL | };
|
||||
| - first borrow might be used here, when `_c` is dropped and runs the destructor for generator
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
@ -4,10 +4,9 @@ error[E0499]: cannot borrow `thing` as mutable more than once at a time
|
|||
LL | gen.as_mut().resume(&mut thing);
|
||||
| ---------- first mutable borrow occurs here
|
||||
LL | gen.as_mut().resume(&mut thing);
|
||||
| ^^^^^^^^^^ second mutable borrow occurs here
|
||||
LL |
|
||||
LL | }
|
||||
| - first borrow might be used here, when `gen` is dropped and runs the destructor for generator
|
||||
| ------ ^^^^^^^^^^ second mutable borrow occurs here
|
||||
| |
|
||||
| first borrow later used by call
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
34
tests/ui/generator/witness-ignore-fake-reads.rs
Normal file
34
tests/ui/generator/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())
|
||||
}
|
||||
40
tests/ui/late-bound-lifetimes/predicate-is-global.rs
Normal file
40
tests/ui/late-bound-lifetimes/predicate-is-global.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// check-pass
|
||||
|
||||
trait Foo {
|
||||
type Assoc;
|
||||
|
||||
fn do_it(_: &Self::Assoc)
|
||||
where
|
||||
for<'a> Self: Baz<'a>;
|
||||
}
|
||||
|
||||
trait Baz<'a>: Foo {}
|
||||
|
||||
impl Foo for () {
|
||||
type Assoc = Inherent;
|
||||
|
||||
// Ensure that the `for<'a> Self: Baz<'a>` predicate, which has
|
||||
// a supertrait `for<'a> Self: Foo`, does not cause us to fail
|
||||
// to normalize `Self::Assoc`.
|
||||
fn do_it(x: &Self::Assoc)
|
||||
where
|
||||
for<'a> Self: Baz<'a>,
|
||||
{
|
||||
x.inherent();
|
||||
}
|
||||
}
|
||||
|
||||
struct Inherent;
|
||||
impl Inherent {
|
||||
fn inherent(&self) {}
|
||||
}
|
||||
|
||||
// This trivial bound doesn't hold, but the unused lifetime tripped up that check after #117589, and
|
||||
// showed up in its crater results (in `soa-derive 0.13.0`).
|
||||
fn do_it()
|
||||
where
|
||||
for<'a> Inherent: Clone,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue