1
Fork 0

Auto merge of #107421 - cjgillot:drop-tracking-mir, r=oli-obk

Enable -Zdrop-tracking-mir by default

This PR enables the `drop-tracking-mir` flag by default. This flag was initially implemented in https://github.com/rust-lang/rust/pull/101692.

This flag computes auto-traits on generators based on their analysis MIR, instead of trying to compute on the HIR body. This removes the need for HIR-based drop-tracking, as we can now reuse the same code to compute generator witness types and to compute generator interior fields.
This commit is contained in:
bors 2023-09-23 18:28:00 +00:00
commit 13e6f24b9a
321 changed files with 838 additions and 8440 deletions

View file

@ -426,7 +426,6 @@ fn push_debuginfo_type_name<'tcx>(
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Alias(..) | ty::Alias(..)
| ty::Bound(..) | ty::Bound(..)
| ty::GeneratorWitnessMIR(..)
| ty::GeneratorWitness(..) => { | ty::GeneratorWitness(..) => {
bug!( bug!(
"debuginfo: Trying to create type name for \ "debuginfo: Trying to create type name for \

View file

@ -152,7 +152,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
// FIXME(oli-obk): we can probably encode closures just like structs // FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) |ty::GeneratorWitnessMIR(..)=> Err(ValTreeCreationError::NonSupportedType), | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
} }
} }
@ -280,7 +280,6 @@ pub fn valtree_to_const_value<'tcx>(
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::RawPtr(_) | ty::RawPtr(_)
| ty::Str | ty::Str

View file

@ -963,7 +963,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| ty::Ref(..) | ty::Ref(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Array(..) | ty::Array(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never

View file

@ -100,8 +100,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(_, _)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),

View file

@ -583,7 +583,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
| ty::Bound(..) | ty::Bound(..)
| ty::Param(..) | ty::Param(..)
| ty::Alias(..) | ty::Alias(..)
| ty::GeneratorWitnessMIR(..)
| ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
} }
} }

View file

@ -64,8 +64,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"), ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), ty::GeneratorWitness(..) => bug!("type_name: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"),
} }
} }

View file

@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler.
When using generators (or async) all type variables must be bound so a When using generators (or async) all type variables must be bound so a
generator can be constructed. generator can be constructed.
Erroneous code example: Erroneous code example:
```edition2018,compile_fail,E0698 ```edition2018,compile_fail,E0282
async fn bar<T>() -> () {} async fn bar<T>() -> () {}
async fn foo() { async fn foo() {

View file

@ -1579,13 +1579,7 @@ fn opaque_type_cycle_error(
label_match(capture.place.ty(), capture.get_path_span(tcx)); label_match(capture.place.ty(), capture.get_path_span(tcx));
} }
// Label any generator locals that capture the opaque // Label any generator locals that capture the opaque
for interior_ty in if let DefKind::Generator = tcx.def_kind(closure_def_id)
typeck_results.generator_interior_types.as_ref().skip_binder()
{
label_match(interior_ty.ty, interior_ty.span);
}
if tcx.sess.opts.unstable_opts.drop_tracking_mir
&& let DefKind::Generator = tcx.def_kind(closure_def_id)
&& let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
{ {
for interior_ty in &generator_layout.field_tys { for interior_ty in &generator_layout.field_tys {
@ -1603,7 +1597,6 @@ fn opaque_type_cycle_error(
} }
pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
let typeck = tcx.typeck(def_id); let typeck = tcx.typeck(def_id);

View file

@ -157,7 +157,6 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Bound(..) | ty::Bound(..)
| ty::Placeholder(_) | ty::Placeholder(_)
| ty::Infer(_) => { | ty::Infer(_) => {

View file

@ -245,7 +245,6 @@ fn do_orphan_check_impl<'tcx>(
ty::Closure(..) ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Bound(..) | ty::Bound(..)
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Infer(..) => { | ty::Infer(..) => {

View file

@ -314,11 +314,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// types, where we use Error as the Self type // types, where we use Error as the Self type
} }
ty::Placeholder(..) ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => {
| ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Bound(..)
| ty::Infer(..) => {
bug!("unexpected type encountered in variance inference: {}", ty); bug!("unexpected type encountered in variance inference: {}", ty);
} }
} }

View file

@ -129,7 +129,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::Float(_) | ty::Float(_)
| ty::Array(..) | ty::Array(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::RawPtr(_) | ty::RawPtr(_)
| ty::Ref(..) | ty::Ref(..)
| ty::FnDef(..) | ty::FnDef(..)

View file

@ -509,28 +509,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
typeck_results.rvalue_scopes = rvalue_scopes; typeck_results.rvalue_scopes = rvalue_scopes;
} }
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
if self.tcx.sess.opts.unstable_opts.drop_tracking_mir {
self.save_generator_interior_predicates(def_id);
return;
}
self.select_obligations_where_possible(|_| {});
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (generator_def_id, body_id, interior, kind) in generators.drain(..) {
crate::generator_interior::resolve_interior(
self,
def_id,
generator_def_id,
body_id,
interior,
kind,
);
self.select_obligations_where_possible(|_| {});
}
}
/// Unify the inference variables corresponding to generator witnesses, and save all the /// Unify the inference variables corresponding to generator witnesses, and save all the
/// predicates that were stalled on those inference variables. /// predicates that were stalled on those inference variables.
/// ///
@ -540,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// We must not attempt to select obligations after this method has run, or risk query cycle /// We must not attempt to select obligations after this method has run, or risk query cycle
/// ICE. /// ICE.
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
fn save_generator_interior_predicates(&self, def_id: DefId) { pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
// Try selecting all obligations that are not blocked on inference variables. // Try selecting all obligations that are not blocked on inference variables.
// Once we start unifying generator witnesses, trying to select obligations on them will // Once we start unifying generator witnesses, trying to select obligations on them will
// trigger query cycle ICEs, as doing so requires MIR. // trigger query cycle ICEs, as doing so requires MIR.
@ -557,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx, self.tcx,
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
); );
let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), args); let witness = Ty::new_generator_witness(self.tcx, expr_def_id.to_def_id(), args);
// Unify `interior` with `witness` and collect all the resulting obligations. // Unify `interior` with `witness` and collect all the resulting obligations.
let span = self.tcx.hir().body(body_id).value.span; let span = self.tcx.hir().body(body_id).value.span;

View file

@ -1,601 +0,0 @@
use super::{
for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRangesBuilder,
NodeInfo, PostOrderId, TrackedValue, TrackedValueIndex,
};
use hir::{
intravisit::{self, Visitor},
Body, Expr, ExprKind, Guard, HirId, LoopIdError,
};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_index::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::{
hir::map::Map,
ty::{ParamEnv, TyCtxt, TypeVisitableExt, TypeckResults},
};
use std::mem::swap;
/// Traverses the body to find the control flow graph and locations for the
/// relevant places are dropped or reinitialized.
///
/// The resulting structure still needs to be iterated to a fixed point, which
/// can be done with propagate_to_fixpoint in cfg_propagate.
pub(super) fn build_control_flow_graph<'tcx>(
infcx: &InferCtxt<'tcx>,
typeck_results: &TypeckResults<'tcx>,
param_env: ParamEnv<'tcx>,
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
body: &'tcx Body<'tcx>,
num_exprs: usize,
) -> (DropRangesBuilder, UnordSet<HirId>) {
let mut drop_range_visitor = DropRangeVisitor::new(
infcx,
typeck_results,
param_env,
consumed_borrowed_places,
num_exprs,
);
intravisit::walk_body(&mut drop_range_visitor, body);
drop_range_visitor.drop_ranges.process_deferred_edges();
if let Some(filename) = &infcx.tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg {
super::cfg_visualize::write_graph_to_file(
&drop_range_visitor.drop_ranges,
filename,
infcx.tcx,
);
}
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
}
/// This struct is used to gather the information for `DropRanges` to determine the regions of the
/// HIR tree for which a value is dropped.
///
/// We are interested in points where a variables is dropped or initialized, and the control flow
/// of the code. We identify locations in code by their post-order traversal index, so it is
/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
///
/// We make several simplifying assumptions, with the goal of being more conservative than
/// necessary rather than less conservative (since being less conservative is unsound, but more
/// conservative is still safe). These assumptions are:
///
/// 1. Moving a variable `a` counts as a move of the whole variable.
/// 2. Moving a partial path like `a.b.c` is ignored.
/// 3. Reinitializing through a field (e.g. `a.b.c = 5`) counts as a reinitialization of all of
/// `a`.
///
/// Some examples:
///
/// Rule 1:
/// ```rust
/// let mut a = (vec![0], vec![0]);
/// drop(a);
/// // `a` is not considered initialized.
/// ```
///
/// Rule 2:
/// ```rust
/// let mut a = (vec![0], vec![0]);
/// drop(a.0);
/// drop(a.1);
/// // `a` is still considered initialized.
/// ```
///
/// Rule 3:
/// ```compile_fail,E0382
/// let mut a = (vec![0], vec![0]);
/// drop(a);
/// a.1 = vec![1];
/// // all of `a` is considered initialized
/// ```
struct DropRangeVisitor<'a, 'tcx> {
typeck_results: &'a TypeckResults<'tcx>,
infcx: &'a InferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
drop_ranges: DropRangesBuilder,
expr_index: PostOrderId,
label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
}
impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
fn new(
infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
num_exprs: usize,
) -> Self {
debug!("consumed_places: {:?}", places.consumed);
let drop_ranges = DropRangesBuilder::new(
places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
infcx.tcx.hir(),
num_exprs,
);
Self {
infcx,
typeck_results,
param_env,
places,
drop_ranges,
expr_index: PostOrderId::from_u32(0),
label_stack: vec![],
}
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn record_drop(&mut self, value: TrackedValue) {
if self.places.borrowed.contains(&value) {
debug!("not marking {:?} as dropped because it is borrowed at some point", value);
} else {
debug!("marking {:?} as dropped at {:?}", value, self.expr_index);
let count = self.expr_index;
self.drop_ranges.drop_at(value, count);
}
}
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
/// expressions. This method consumes a little deeper into the expression when needed.
fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
debug!("consuming expr {:?}, count={:?}", expr.kind, self.expr_index);
let places = self
.places
.consumed
.get(&expr.hir_id)
.map_or(vec![], |places| places.iter().cloned().collect());
for place in places {
trace!(?place, "consuming place");
for_each_consumable(self.tcx().hir(), place, |value| self.record_drop(value));
}
}
/// Marks an expression as being reinitialized.
///
/// Note that we always approximated on the side of things being more
/// initialized than they actually are, as opposed to less. In cases such
/// as `x.y = ...`, we would consider all of `x` as being initialized
/// instead of just the `y` field.
///
/// This is because it is always safe to consider something initialized
/// even when it is not, but the other way around will cause problems.
///
/// In the future, we will hopefully tighten up these rules to be more
/// precise.
fn reinit_expr(&mut self, expr: &hir::Expr<'_>) {
// Walk the expression to find the base. For example, in an expression
// like `*a[i].x`, we want to find the `a` and mark that as
// reinitialized.
match expr.kind {
ExprKind::Path(hir::QPath::Resolved(
_,
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) => {
// This is the base case, where we have found an actual named variable.
let location = self.expr_index;
debug!("reinitializing {:?} at {:?}", hir_id, location);
self.drop_ranges.reinit_at(TrackedValue::Variable(*hir_id), location);
}
ExprKind::Field(base, _) => self.reinit_expr(base),
// Most expressions do not refer to something where we need to track
// reinitializations.
//
// Some of these may be interesting in the future
ExprKind::Path(..)
| ExprKind::ConstBlock(..)
| ExprKind::Array(..)
| ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Tup(..)
| ExprKind::Binary(..)
| ExprKind::Unary(..)
| ExprKind::Lit(..)
| ExprKind::Cast(..)
| ExprKind::Type(..)
| ExprKind::DropTemps(..)
| ExprKind::Let(..)
| ExprKind::If(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
| ExprKind::Closure { .. }
| ExprKind::Block(..)
| ExprKind::Assign(..)
| ExprKind::AssignOp(..)
| ExprKind::Index(..)
| ExprKind::AddrOf(..)
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Become(..)
| ExprKind::InlineAsm(..)
| ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)
| ExprKind::Yield(..)
| ExprKind::Err(_) => (),
}
}
/// For an expression with an uninhabited return type (e.g. a function that returns !),
/// this adds a self edge to the CFG to model the fact that the function does not
/// return.
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.typeck_results.expr_ty(expr);
let ty = self.infcx.resolve_vars_if_possible(ty);
if ty.has_non_region_infer() {
self.tcx()
.sess
.delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
return;
}
let ty = self.tcx().erase_regions(ty);
let m = self.tcx().parent_module(expr.hir_id).to_def_id();
if !ty.is_inhabited_from(self.tcx(), m, self.param_env) {
// This function will not return. We model this fact as an infinite loop.
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
}
}
/// Map a Destination to an equivalent expression node
///
/// The destination field of a Break or Continue expression can target either an
/// expression or a block. The drop range analysis, however, only deals in
/// expression nodes, so blocks that might be the destination of a Break or Continue
/// will not have a PostOrderId.
///
/// If the destination is an expression, this function will simply return that expression's
/// hir_id. If the destination is a block, this function will return the hir_id of last
/// expression in the block.
fn find_target_expression_from_destination(
&self,
destination: hir::Destination,
) -> Result<HirId, LoopIdError> {
destination.target_id.map(|target| {
let node = self.tcx().hir().get(target);
match node {
hir::Node::Expr(_) => target,
hir::Node::Block(b) => find_last_block_expression(b),
hir::Node::Param(..)
| hir::Node::Item(..)
| hir::Node::ForeignItem(..)
| hir::Node::TraitItem(..)
| hir::Node::ImplItem(..)
| hir::Node::Variant(..)
| hir::Node::Field(..)
| hir::Node::AnonConst(..)
| hir::Node::ConstBlock(..)
| hir::Node::Stmt(..)
| hir::Node::PathSegment(..)
| hir::Node::Ty(..)
| hir::Node::TypeBinding(..)
| hir::Node::TraitRef(..)
| hir::Node::Pat(..)
| hir::Node::PatField(..)
| hir::Node::ExprField(..)
| hir::Node::Arm(..)
| hir::Node::Local(..)
| hir::Node::Ctor(..)
| hir::Node::Lifetime(..)
| hir::Node::GenericParam(..)
| hir::Node::Crate(..)
| hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
}
})
}
}
fn find_last_block_expression(block: &hir::Block<'_>) -> HirId {
block.expr.map_or_else(
// If there is no tail expression, there will be at least one statement in the
// block because the block contains a break or continue statement.
|| block.stmts.last().unwrap().hir_id,
|expr| expr.hir_id,
)
}
impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
let mut reinit = None;
match expr.kind {
ExprKind::Assign(lhs, rhs, _) => {
self.visit_expr(rhs);
self.visit_expr(lhs);
reinit = Some(lhs);
}
ExprKind::If(test, if_true, if_false) => {
self.visit_expr(test);
let fork = self.expr_index;
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
self.visit_expr(if_true);
let true_end = self.expr_index;
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
if let Some(if_false) = if_false {
self.visit_expr(if_false);
}
self.drop_ranges.add_control_edge(true_end, self.expr_index + 1);
}
ExprKind::Match(scrutinee, arms, ..) => {
// We walk through the match expression almost like a chain of if expressions.
// Here's a diagram to follow along with:
//
// ┌─┐
// match │A│ {
// ┌───┴─┘
// │
// ┌▼┌───►┌─┐ ┌─┐
// │B│ if │C│ =>│D│,
// └─┘ ├─┴──►└─┴──────┐
// ┌──┘ │
// ┌──┘ │
// │ │
// ┌▼┌───►┌─┐ ┌─┐ │
// │E│ if │F│ =>│G│, │
// └─┘ ├─┴──►└─┴┐ │
// │ │ │
// } ▼ ▼ │
// ┌─┐◄───────────────────┘
// │H│
// └─┘
//
// The order we want is that the scrutinee (A) flows into the first pattern (B),
// which flows into the guard (C). Then the guard either flows into the arm body
// (D) or into the start of the next arm (E). Finally, the body flows to the end
// of the match block (H).
//
// The subsequent arms follow the same ordering. First we go to the pattern, then
// the guard (if present, otherwise it flows straight into the body), then into
// the body and then to the end of the match expression.
//
// The comments below show which edge is being added.
self.visit_expr(scrutinee);
let (guard_exit, arm_end_ids) = arms.iter().fold(
(self.expr_index, vec![]),
|(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| {
// A -> B, or C -> E
self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1);
self.visit_pat(pat);
// B -> C and E -> F are added implicitly due to the traversal order.
match guard {
Some(Guard::If(expr)) => self.visit_expr(expr),
Some(Guard::IfLet(let_expr)) => {
self.visit_let_expr(let_expr);
}
None => (),
}
// Likewise, C -> D and F -> G are added implicitly.
// Save C, F, so we can add the other outgoing edge.
let to_next_arm = self.expr_index;
// The default edge does not get added since we also have an explicit edge,
// so we also need to add an edge to the next node as well.
//
// This adds C -> D, F -> G
self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1);
self.visit_expr(body);
// Save the end of the body so we can add the exit edge once we know where
// the exit is.
arm_end_ids.push(self.expr_index);
// Pass C to the next iteration, as well as vec![D]
//
// On the last round through, we pass F and vec![D, G] so that we can
// add all the exit edges.
(to_next_arm, arm_end_ids)
},
);
// F -> H
self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1);
arm_end_ids.into_iter().for_each(|arm_end| {
// D -> H, G -> H
self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
});
}
ExprKind::Loop(body, label, ..) => {
let loop_begin = self.expr_index + 1;
self.label_stack.push((label, loop_begin));
if body.stmts.is_empty() && body.expr.is_none() {
// For empty loops we won't have updated self.expr_index after visiting the
// body, meaning we'd get an edge from expr_index to expr_index + 1, but
// instead we want an edge from expr_index + 1 to expr_index + 1.
self.drop_ranges.add_control_edge(loop_begin, loop_begin);
} else {
self.visit_block(body);
self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
}
self.label_stack.pop();
}
// Find the loop entry by searching through the label stack for either the last entry
// (if label is none), or the first entry where the label matches this one. The Loop
// case maintains this stack mapping labels to the PostOrderId for the loop entry.
ExprKind::Continue(hir::Destination { label, .. }, ..) => self
.label_stack
.iter()
.rev()
.find(|(loop_label, _)| label.is_none() || *loop_label == label)
.map_or((), |(_, target)| {
self.drop_ranges.add_control_edge(self.expr_index, *target)
}),
ExprKind::Break(destination, value) => {
// destination either points to an expression or to a block. We use
// find_target_expression_from_destination to use the last expression of the block
// if destination points to a block.
//
// We add an edge to the hir_id of the expression/block we are breaking out of, and
// then in process_deferred_edges we will map this hir_id to its PostOrderId, which
// will refer to the end of the block due to the post order traversal.
if let Ok(target) = self.find_target_expression_from_destination(destination) {
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
}
if let Some(value) = value {
self.visit_expr(value);
}
}
ExprKind::Become(_call) => bug!("encountered a tail-call inside a generator"),
ExprKind::Call(f, args) => {
self.visit_expr(f);
for arg in args {
self.visit_expr(arg);
}
self.handle_uninhabited_return(expr);
}
ExprKind::MethodCall(_, receiver, exprs, _) => {
self.visit_expr(receiver);
for expr in exprs {
self.visit_expr(expr);
}
self.handle_uninhabited_return(expr);
}
ExprKind::AddrOf(..)
| ExprKind::Array(..)
// FIXME(eholk): We probably need special handling for AssignOps. The ScopeTree builder
// in region.rs runs both lhs then rhs and rhs then lhs and then sets all yields to be
// the latest they show up in either traversal. With the older scope-based
// approximation, this was fine, but it's probably not right now. What we probably want
// to do instead is still run both orders, but consider anything that showed up as a
// yield in either order.
| ExprKind::AssignOp(..)
| ExprKind::Binary(..)
| ExprKind::Block(..)
| ExprKind::Cast(..)
| ExprKind::Closure { .. }
| ExprKind::ConstBlock(..)
| ExprKind::DropTemps(..)
| ExprKind::Err(_)
| ExprKind::Field(..)
| ExprKind::Index(..)
| ExprKind::InlineAsm(..)
| ExprKind::OffsetOf(..)
| ExprKind::Let(..)
| ExprKind::Lit(..)
| ExprKind::Path(..)
| ExprKind::Repeat(..)
| ExprKind::Ret(..)
| ExprKind::Struct(..)
| ExprKind::Tup(..)
| ExprKind::Type(..)
| ExprKind::Unary(..)
| ExprKind::Yield(..) => intravisit::walk_expr(self, expr),
}
self.expr_index = self.expr_index + 1;
self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_index);
self.consume_expr(expr);
if let Some(expr) = reinit {
self.reinit_expr(expr);
}
}
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
intravisit::walk_pat(self, pat);
// Increment expr_count here to match what InteriorVisitor expects.
self.expr_index = self.expr_index + 1;
// Save a node mapping to get better CFG visualization
self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index);
}
}
impl DropRangesBuilder {
fn new(
tracked_values: impl Iterator<Item = TrackedValue>,
hir: Map<'_>,
num_exprs: usize,
) -> Self {
let mut tracked_value_map = UnordMap::<_, TrackedValueIndex>::default();
let mut next = <_>::from(0u32);
for value in tracked_values {
for_each_consumable(hir, value, |value| {
if let std::collections::hash_map::Entry::Vacant(e) = tracked_value_map.entry(value)
{
e.insert(next);
next = next + 1;
}
});
}
debug!("hir_id_map: {:#?}", tracked_value_map);
let num_values = tracked_value_map.len();
Self {
tracked_value_map,
nodes: IndexVec::from_fn_n(|_| NodeInfo::new(num_values), num_exprs + 1),
deferred_edges: <_>::default(),
post_order_map: <_>::default(),
}
}
fn tracked_value_index(&self, tracked_value: TrackedValue) -> TrackedValueIndex {
*self.tracked_value_map.get(&tracked_value).unwrap()
}
/// Adds an entry in the mapping from HirIds to PostOrderIds
///
/// Needed so that `add_control_edge_hir_id` can work.
fn add_node_mapping(&mut self, node_hir_id: HirId, post_order_id: PostOrderId) {
self.post_order_map.insert(node_hir_id, post_order_id);
}
/// Like add_control_edge, but uses a hir_id as the target.
///
/// This can be used for branches where we do not know the PostOrderId of the target yet,
/// such as when handling `break` or `continue`.
fn add_control_edge_hir_id(&mut self, from: PostOrderId, to: HirId) {
self.deferred_edges.push((from, to));
}
fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) {
let value = self.tracked_value_index(value);
self.node_mut(location).drops.push(value);
}
fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
let value = match self.tracked_value_map.get(&value) {
Some(value) => *value,
// If there's no value, this is never consumed and therefore is never dropped. We can
// ignore this.
None => return,
};
self.node_mut(location).reinits.push(value);
}
/// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
///
/// Should be called after visiting the HIR but before solving the control flow, otherwise some
/// edges will be missed.
fn process_deferred_edges(&mut self) {
trace!("processing deferred edges. post_order_map={:#?}", self.post_order_map);
let mut edges = vec![];
swap(&mut edges, &mut self.deferred_edges);
edges.into_iter().for_each(|(from, to)| {
trace!("Adding deferred edge from {:?} to {:?}", from, to);
let to = *self.post_order_map.get(&to).expect("Expression ID not found");
trace!("target edge PostOrderId={:?}", to);
self.add_control_edge(from, to)
});
}
}

View file

@ -1,92 +0,0 @@
use super::{DropRangesBuilder, PostOrderId};
use rustc_index::{bit_set::BitSet, IndexVec};
use std::collections::BTreeMap;
impl DropRangesBuilder {
pub fn propagate_to_fixpoint(&mut self) {
trace!("before fixpoint: {:#?}", self);
let preds = self.compute_predecessors();
trace!("predecessors: {:#?}", preds.iter_enumerated().collect::<BTreeMap<_, _>>());
let mut new_state = BitSet::new_empty(self.num_values());
let mut changed_nodes = BitSet::new_empty(self.nodes.len());
let mut unchanged_mask = BitSet::new_filled(self.nodes.len());
changed_nodes.insert(0u32.into());
let mut propagate = || {
let mut changed = false;
unchanged_mask.insert_all();
for id in self.nodes.indices() {
trace!("processing {:?}, changed_nodes: {:?}", id, changed_nodes);
// Check if any predecessor has changed, and if not then short-circuit.
//
// We handle the start node specially, since it doesn't have any predecessors,
// but we need to start somewhere.
if match id.index() {
0 => !changed_nodes.contains(id),
_ => !preds[id].iter().any(|pred| changed_nodes.contains(*pred)),
} {
trace!("short-circuiting because none of {:?} have changed", preds[id]);
unchanged_mask.remove(id);
continue;
}
if id.index() == 0 {
new_state.clear();
} else {
// If we are not the start node and we have no predecessors, treat
// everything as dropped because there's no way to get here anyway.
new_state.insert_all();
};
for pred in &preds[id] {
new_state.intersect(&self.nodes[*pred].drop_state);
}
for drop in &self.nodes[id].drops {
new_state.insert(*drop);
}
for reinit in &self.nodes[id].reinits {
new_state.remove(*reinit);
}
if self.nodes[id].drop_state.intersect(&new_state) {
changed_nodes.insert(id);
changed = true;
} else {
unchanged_mask.remove(id);
}
}
changed_nodes.intersect(&unchanged_mask);
changed
};
while propagate() {
trace!("drop_state changed, re-running propagation");
}
trace!("after fixpoint: {:#?}", self);
}
fn compute_predecessors(&self) -> IndexVec<PostOrderId, Vec<PostOrderId>> {
let mut preds = IndexVec::from_fn_n(|_| vec![], self.nodes.len());
for (id, node) in self.nodes.iter_enumerated() {
// If the node has no explicit successors, we assume that control
// will from this node into the next one.
//
// If there are successors listed, then we assume that all
// possible successors are given and we do not include the default.
if node.successors.len() == 0 && id.index() != self.nodes.len() - 1 {
preds[id + 1].push(id);
} else {
for succ in &node.successors {
preds[*succ].push(id);
}
}
}
preds
}
}

View file

@ -1,96 +0,0 @@
//! Implementation of GraphWalk for DropRanges so we can visualize the control
//! flow graph when needed for debugging.
use rustc_graphviz as dot;
use rustc_hir::{Expr, ExprKind, Node};
use rustc_middle::ty::TyCtxt;
use super::{DropRangesBuilder, PostOrderId};
/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
///
/// It is not normally called, but is kept around to easily add debugging
/// code when needed.
pub(super) fn write_graph_to_file(
drop_ranges: &DropRangesBuilder,
filename: &str,
tcx: TyCtxt<'_>,
) {
dot::render(
&DropRangesGraph { drop_ranges, tcx },
&mut std::fs::File::create(filename).unwrap(),
)
.unwrap();
}
struct DropRangesGraph<'a, 'tcx> {
drop_ranges: &'a DropRangesBuilder,
tcx: TyCtxt<'tcx>,
}
impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> {
type Node = PostOrderId;
type Edge = (PostOrderId, PostOrderId);
fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect()
}
fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
self.drop_ranges
.nodes
.iter_enumerated()
.flat_map(|(i, node)| {
if node.successors.len() == 0 {
vec![(i, i + 1)]
} else {
node.successors.iter().map(move |&s| (i, s)).collect()
}
})
.collect()
}
fn source(&'a self, edge: &Self::Edge) -> Self::Node {
edge.0
}
fn target(&'a self, edge: &Self::Edge) -> Self::Node {
edge.1
}
}
impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
type Node = PostOrderId;
type Edge = (PostOrderId, PostOrderId);
fn graph_id(&'a self) -> dot::Id<'a> {
dot::Id::new("drop_ranges").unwrap()
}
fn node_id(&'a self, n: &Self::Node) -> dot::Id<'a> {
dot::Id::new(format!("id{}", n.index())).unwrap()
}
fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
dot::LabelText::LabelStr(
format!(
"{n:?}: {}",
self.drop_ranges
.post_order_map
.iter()
.find(|(_hir_id, &post_order_id)| post_order_id == *n)
.map_or("<unknown>".into(), |(hir_id, _)| format!(
"{}{}",
self.tcx.hir().node_to_string(*hir_id),
match self.tcx.hir().find(*hir_id) {
Some(Node::Expr(Expr { kind: ExprKind::Yield(..), .. })) => " (yield)",
_ => "",
}
))
)
.into(),
)
}
}

View file

@ -1,306 +0,0 @@
//! Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
//! (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
//! generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
//!
//! There are three phases to this analysis:
//! 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
//! 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
//! and also build a control flow graph.
//! 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
//! the CFG and find the exact points where we know a value is definitely dropped.
//!
//! The end result is a data structure that maps the post-order index of each node in the HIR tree
//! to a set of values that are known to be dropped at that location.
use self::cfg_build::build_control_flow_graph;
use self::record_consumed_borrow::find_consumed_and_borrowed;
use crate::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
use rustc_middle::hir::map::Map;
use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
use rustc_middle::ty;
use std::collections::BTreeMap;
use std::fmt::Debug;
mod cfg_build;
mod cfg_propagate;
mod cfg_visualize;
mod record_consumed_borrow;
pub fn compute_drop_ranges<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
def_id: DefId,
body: &'tcx Body<'tcx>,
) -> DropRanges {
if fcx.sess().opts.unstable_opts.drop_tracking {
let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
let typeck_results = &fcx.typeck_results.borrow();
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
&fcx,
typeck_results,
fcx.param_env,
consumed_borrowed_places,
body,
num_exprs,
);
drop_ranges.propagate_to_fixpoint();
debug!("borrowed_temporaries = {borrowed_temporaries:?}");
DropRanges {
tracked_value_map: drop_ranges.tracked_value_map,
nodes: drop_ranges.nodes,
borrowed_temporaries: Some(borrowed_temporaries),
}
} else {
// If drop range tracking is not enabled, skip all the analysis and produce an
// empty set of DropRanges.
DropRanges {
tracked_value_map: UnordMap::default(),
nodes: IndexVec::new(),
borrowed_temporaries: None,
}
}
}
/// Applies `f` to consumable node in the HIR subtree pointed to by `place`.
///
/// This includes the place itself, and if the place is a reference to a local
/// variable then `f` is also called on the HIR node for that variable as well.
///
/// For example, if `place` points to `foo()`, then `f` is called once for the
/// result of `foo`. On the other hand, if `place` points to `x` then `f` will
/// be called both on the `ExprKind::Path` node that represents the expression
/// as well as the HirId of the local `x` itself.
fn for_each_consumable(hir: Map<'_>, place: TrackedValue, mut f: impl FnMut(TrackedValue)) {
f(place);
let node = hir.find(place.hir_id());
if let Some(Node::Expr(expr)) = node {
match expr.kind {
hir::ExprKind::Path(hir::QPath::Resolved(
_,
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) => {
f(TrackedValue::Variable(*hir_id));
}
_ => (),
}
}
}
rustc_index::newtype_index! {
#[debug_format = "id({})"]
pub struct PostOrderId {}
}
rustc_index::newtype_index! {
#[debug_format = "hidx({})"]
pub struct TrackedValueIndex {}
}
/// Identifies a value whose drop state we need to track.
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
enum TrackedValue {
/// Represents a named variable, such as a let binding, parameter, or upvar.
///
/// The HirId points to the variable's definition site.
Variable(HirId),
/// A value produced as a result of an expression.
///
/// The HirId points to the expression that returns this value.
Temporary(HirId),
}
impl Debug for TrackedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ty::tls::with_opt(|opt_tcx| {
if let Some(tcx) = opt_tcx {
write!(f, "{}", tcx.hir().node_to_string(self.hir_id()))
} else {
match self {
Self::Variable(hir_id) => write!(f, "Variable({hir_id:?})"),
Self::Temporary(hir_id) => write!(f, "Temporary({hir_id:?})"),
}
}
})
}
}
impl TrackedValue {
fn hir_id(&self) -> HirId {
match self {
TrackedValue::Variable(hir_id) | TrackedValue::Temporary(hir_id) => *hir_id,
}
}
fn from_place_with_projections_allowed(place_with_id: &PlaceWithHirId<'_>) -> Self {
match place_with_id.place.base {
PlaceBase::Rvalue | PlaceBase::StaticItem => {
TrackedValue::Temporary(place_with_id.hir_id)
}
PlaceBase::Local(hir_id)
| PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
TrackedValue::Variable(hir_id)
}
}
}
}
/// Represents a reason why we might not be able to convert a HirId or Place
/// into a tracked value.
#[derive(Debug)]
enum TrackedValueConversionError {
/// Place projects are not currently supported.
///
/// The reasoning around these is kind of subtle, so we choose to be more
/// conservative around these for now. There is no reason in theory we
/// cannot support these, we just have not implemented it yet.
PlaceProjectionsNotSupported,
}
impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
type Error = TrackedValueConversionError;
fn try_from(place_with_id: &PlaceWithHirId<'_>) -> Result<Self, Self::Error> {
if !place_with_id.place.projections.is_empty() {
debug!(
"TrackedValue from PlaceWithHirId: {:?} has projections, which are not supported.",
place_with_id
);
return Err(TrackedValueConversionError::PlaceProjectionsNotSupported);
}
Ok(TrackedValue::from_place_with_projections_allowed(place_with_id))
}
}
pub struct DropRanges {
tracked_value_map: UnordMap<TrackedValue, TrackedValueIndex>,
nodes: IndexVec<PostOrderId, NodeInfo>,
borrowed_temporaries: Option<UnordSet<HirId>>,
}
impl DropRanges {
pub fn is_dropped_at(&self, hir_id: HirId, location: usize) -> bool {
self.tracked_value_map
.get(&TrackedValue::Temporary(hir_id))
.or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
.cloned()
.is_some_and(|tracked_value_id| {
self.expect_node(location.into()).drop_state.contains(tracked_value_id)
})
}
pub fn is_borrowed_temporary(&self, expr: &hir::Expr<'_>) -> bool {
if let Some(b) = &self.borrowed_temporaries { b.contains(&expr.hir_id) } else { true }
}
/// Returns a reference to the NodeInfo for a node, panicking if it does not exist
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
&self.nodes[id]
}
}
/// Tracks information needed to compute drop ranges.
struct DropRangesBuilder {
/// The core of DropRangesBuilder is a set of nodes, which each represent
/// one expression. We primarily refer to them by their index in a
/// post-order traversal of the HIR tree, since this is what
/// generator_interior uses to talk about yield positions.
///
/// This IndexVec keeps the relevant details for each node. See the
/// NodeInfo struct for more details, but this information includes things
/// such as the set of control-flow successors, which variables are dropped
/// or reinitialized, and whether each variable has been inferred to be
/// known-dropped or potentially reinitialized at each point.
nodes: IndexVec<PostOrderId, NodeInfo>,
/// We refer to values whose drop state we are tracking by the HirId of
/// where they are defined. Within a NodeInfo, however, we store the
/// drop-state in a bit vector indexed by a HirIdIndex
/// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
/// from HirIds to the HirIdIndex that is used to represent that value in
/// bitvector.
tracked_value_map: UnordMap<TrackedValue, TrackedValueIndex>,
/// When building the control flow graph, we don't always know the
/// post-order index of the target node at the point we encounter it.
/// For example, this happens with break and continue. In those cases,
/// we store a pair of the PostOrderId of the source and the HirId
/// of the target. Once we have gathered all of these edges, we make a
/// pass over the set of deferred edges (see process_deferred_edges in
/// cfg_build.rs), look up the PostOrderId for the target (since now the
/// post-order index for all nodes is known), and add missing control flow
/// edges.
deferred_edges: Vec<(PostOrderId, HirId)>,
/// This maps HirIds of expressions to their post-order index. It is
/// used in process_deferred_edges to correctly add back-edges.
post_order_map: HirIdMap<PostOrderId>,
}
impl Debug for DropRangesBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DropRanges")
.field("hir_id_map", &self.tracked_value_map)
.field("post_order_maps", &self.post_order_map)
.field("nodes", &self.nodes.iter_enumerated().collect::<BTreeMap<_, _>>())
.finish()
}
}
/// DropRanges keeps track of what values are definitely dropped at each point in the code.
///
/// Values of interest are defined by the hir_id of their place. Locations in code are identified
/// by their index in the post-order traversal. At its core, DropRanges maps
/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
/// dropped at the point of the node identified by post_order_id.
impl DropRangesBuilder {
/// Returns the number of values (hir_ids) that are tracked
fn num_values(&self) -> usize {
self.tracked_value_map.len()
}
fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
let size = self.num_values();
self.nodes.ensure_contains_elem(id, || NodeInfo::new(size))
}
fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
trace!("adding control edge from {:?} to {:?}", from, to);
self.node_mut(from).successors.push(to);
}
}
#[derive(Debug)]
struct NodeInfo {
/// IDs of nodes that can follow this one in the control flow
///
/// If the vec is empty, then control proceeds to the next node.
successors: Vec<PostOrderId>,
/// List of hir_ids that are dropped by this node.
drops: Vec<TrackedValueIndex>,
/// List of hir_ids that are reinitialized by this node.
reinits: Vec<TrackedValueIndex>,
/// Set of values that are definitely dropped at this point.
drop_state: BitSet<TrackedValueIndex>,
}
impl NodeInfo {
fn new(num_values: usize) -> Self {
Self {
successors: vec![],
drops: vec![],
reinits: vec![],
drop_state: BitSet::new_filled(num_values),
}
}
}

View file

@ -1,242 +0,0 @@
use super::TrackedValue;
use crate::{
expr_use_visitor::{self, ExprUseVisitor},
FnCtxt,
};
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::{fx::FxIndexSet, unord::UnordSet};
use rustc_hir as hir;
use rustc_middle::ty::{ParamEnv, TyCtxt};
use rustc_middle::{
hir::place::{PlaceBase, Projection, ProjectionKind},
ty::TypeVisitableExt,
};
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
def_id: DefId,
body: &'tcx Body<'tcx>,
) -> ConsumedAndBorrowedPlaces {
let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx, fcx.param_env);
expr_use_visitor.consume_body(fcx, def_id, body);
expr_use_visitor.places
}
pub(super) struct ConsumedAndBorrowedPlaces {
/// Records the variables/expressions that are dropped by a given expression.
///
/// The key is the hir-id of the expression, and the value is a set or hir-ids for variables
/// or values that are consumed by that expression.
///
/// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
/// not considered a drop of `x`, although it would be a drop of `x.y`.
pub(super) consumed: HirIdMap<FxIndexSet<TrackedValue>>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
pub(super) borrowed: UnordSet<TrackedValue>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
pub(super) borrowed_temporaries: UnordSet<HirId>,
}
/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
///
/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
/// record the parent expression, which is the point where the drop actually takes place.
struct ExprUseDelegate<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
}
impl<'tcx> ExprUseDelegate<'tcx> {
fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
Self {
tcx,
param_env,
places: ConsumedAndBorrowedPlaces {
consumed: <_>::default(),
borrowed: <_>::default(),
borrowed_temporaries: <_>::default(),
},
}
}
fn consume_body(&mut self, fcx: &'_ FnCtxt<'_, 'tcx>, def_id: DefId, body: &'tcx Body<'tcx>) {
// Run ExprUseVisitor to find where values are consumed.
ExprUseVisitor::new(
self,
&fcx.infcx,
def_id.expect_local(),
fcx.param_env,
&fcx.typeck_results.borrow(),
)
.consume_body(body);
}
fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
self.places.consumed.entry(consumer).or_insert_with(|| <_>::default());
debug!(?consumer, ?target, "mark_consumed");
self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
}
fn borrow_place(&mut self, place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>) {
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
// Ordinarily a value is consumed by it's parent, but in the special case of a
// borrowed RValue, we create a reference that lives as long as the temporary scope
// for that expression (typically, the innermost statement, but sometimes the enclosing
// block). We record this fact here so that later in generator_interior
// we can use the correct scope.
//
// We special case borrows through a dereference (`&*x`, `&mut *x` where `x` is
// some rvalue expression), since these are essentially a copy of a pointer.
// In other words, this borrow does not refer to the
// temporary (`*x`), but to the referent (whatever `x` is a borrow of).
//
// We were considering that we might encounter problems down the line if somehow,
// some part of the compiler were to look at this result and try to use it to
// drive a borrowck-like analysis (this does not currently happen, as of this writing).
// But even this should be fine, because the lifetime of the dereferenced reference
// found in the rvalue is only significant as an intermediate 'link' to the value we
// are producing, and we separately track whether that value is live over a yield.
// Example:
//
// ```notrust
// fn identity<T>(x: &mut T) -> &mut T { x }
// let a: A = ...;
// let y: &'y mut A = &mut *identity(&'a mut a);
// ^^^^^^^^^^^^^^^^^^^^^^^^^ the borrow we are talking about
// ```
//
// The expression `*identity(...)` is a deref of an rvalue,
// where the `identity(...)` (the rvalue) produces a return type
// of `&'rv mut A`, where `'a: 'rv`. We then assign this result to
// `'y`, resulting in (transitively) `'a: 'y` (i.e., while `y` is in use,
// `a` will be considered borrowed). Other parts of the code will ensure
// that if `y` is live over a yield, `&'y mut A` appears in the generator
// state. If `'y` is live, then any sound region analysis must conclude
// that `'a` is also live. So if this causes a bug, blame some other
// part of the code!
let is_deref = place_with_id
.place
.projections
.iter()
.any(|Projection { kind, .. }| *kind == ProjectionKind::Deref);
if let (false, PlaceBase::Rvalue) = (is_deref, place_with_id.place.base) {
self.places.borrowed_temporaries.insert(place_with_id.hir_id);
}
}
}
impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
fn consume(
&mut self,
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
) {
let hir = self.tcx.hir();
let parent = match hir.opt_parent_id(place_with_id.hir_id) {
Some(parent) => parent,
None => place_with_id.hir_id,
};
debug!(
"consume {:?}; diag_expr_id={}, using parent {}",
place_with_id,
hir.node_to_string(diag_expr_id),
hir.node_to_string(parent)
);
if let Ok(tracked_value) = place_with_id.try_into() {
self.mark_consumed(parent, tracked_value)
}
}
fn borrow(
&mut self,
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
bk: rustc_middle::ty::BorrowKind,
) {
debug!(
"borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \
borrow_kind={bk:#?}"
);
self.borrow_place(place_with_id);
}
fn copy(
&mut self,
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
_diag_expr_id: HirId,
) {
debug!("copy: place_with_id = {place_with_id:?}");
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
// For copied we treat this mostly like a borrow except that we don't add the place
// to borrowed_temporaries because the copy is consumed.
}
fn mutate(
&mut self,
assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
) {
debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}");
if assignee_place.place.base == PlaceBase::Rvalue
&& assignee_place.place.projections.is_empty()
{
// Assigning to an Rvalue is illegal unless done through a dereference. We would have
// already gotten a type error, so we will just return here.
return;
}
// If the type being assigned needs dropped, then the mutation counts as a borrow
// since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
if ty.has_infer() {
self.tcx.sess.delay_span_bug(
self.tcx.hir().span(assignee_place.hir_id),
format!("inference variables in {ty}"),
);
} else if ty.needs_drop(self.tcx, self.param_env) {
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
}
}
fn bind(
&mut self,
binding_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
) {
debug!("bind {binding_place:?}; diag_expr_id={diag_expr_id:?}");
}
fn fake_read(
&mut self,
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
cause: rustc_middle::mir::FakeReadCause,
diag_expr_id: HirId,
) {
debug!(
"fake_read place_with_id={place_with_id:?}; cause={cause:?}; diag_expr_id={diag_expr_id:?}"
);
// fake reads happen in places like the scrutinee of a match expression.
// we treat those as a borrow, much like a copy: the idea is that we are
// transiently creating a `&T` ref that we can read from to observe the current
// value (this `&T` is immediately dropped afterwards).
self.borrow_place(place_with_id);
}
}

View file

@ -1,723 +0,0 @@
//! This calculates the types which has storage which lives across a suspension point in a
//! generator from the perspective of typeck. The actual types used at runtime
//! is calculated in `rustc_mir_transform::generator` and may be a subset of the
//! types computed here.
use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{pluralize, DelayDm};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::symbol::sym;
use rustc_span::Span;
use smallvec::{smallvec, SmallVec};
mod drop_ranges;
struct InteriorVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
region_scope_tree: &'a region::ScopeTree,
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
rvalue_scopes: &'a RvalueScopes,
expr_count: usize,
kind: hir::GeneratorKind,
prev_unresolved_span: Option<Span>,
linted_values: HirIdSet,
drop_ranges: DropRanges,
}
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
fn record(
&mut self,
ty: Ty<'tcx>,
hir_id: HirId,
scope: Option<region::Scope>,
expr: Option<&'tcx Expr<'tcx>>,
source_span: Span,
) {
use rustc_span::DUMMY_SP;
let ty = self.fcx.resolve_vars_if_possible(ty);
debug!(
"attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}",
ty, hir_id, scope, expr, source_span, self.expr_count,
);
let live_across_yield = scope
.map(|s| {
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
// If we are recording an expression that is the last yield
// in the scope, or that has a postorder CFG index larger
// than the one of all of the yields, then its value can't
// be storage-live (and therefore live) at any of the yields.
//
// See the mega-comment at `yield_in_scope` for a proof.
yield_data
.iter()
.find(|yield_data| {
debug!(
"comparing counts yield: {} self: {}, source_span = {:?}",
yield_data.expr_and_pat_count, self.expr_count, source_span
);
if self
.is_dropped_at_yield_location(hir_id, yield_data.expr_and_pat_count)
{
debug!("value is dropped at yield point; not recording");
return false;
}
// If it is a borrowing happening in the guard,
// it needs to be recorded regardless because they
// do live across this yield point.
yield_data.expr_and_pat_count >= self.expr_count
})
.cloned()
})
})
.unwrap_or_else(|| {
Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, source: self.kind.into() })
});
if let Some(yield_data) = live_across_yield {
debug!(
"type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
expr, scope, ty, self.expr_count, yield_data.span
);
if let Some((unresolved_term, unresolved_type_span)) =
self.fcx.first_unresolved_const_or_ty_var(&ty)
{
// If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self
.prev_unresolved_span
.unwrap_or_else(|| unresolved_type_span.unwrap_or(source_span));
// If we encounter an int/float variable, then inference fallback didn't
// finish due to some other error. Don't emit spurious additional errors.
if let Some(unresolved_ty) = unresolved_term.ty()
&& let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = unresolved_ty.kind()
{
self.fcx
.tcx
.sess
.delay_span_bug(span, format!("Encountered var {unresolved_term:?}"));
} else {
let note = format!(
"the type is part of the {} because of this {}",
self.kind.descr(),
yield_data.source
);
self.fcx
.need_type_info_err_in_generator(self.kind, span, unresolved_term)
.span_note(yield_data.span, note)
.emit();
}
} else {
// Insert the type into the ordered set.
let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
if !self.linted_values.contains(&hir_id) {
check_must_not_suspend_ty(
self.fcx,
ty,
hir_id,
SuspendCheckData {
expr,
source_span,
yield_span: yield_data.span,
plural_len: 1,
..Default::default()
},
);
self.linted_values.insert(hir_id);
}
self.types.insert(ty::GeneratorInteriorTypeCause {
span: source_span,
ty,
scope_span,
yield_span: yield_data.span,
expr: expr.map(|e| e.hir_id),
});
}
} else {
debug!(
"no type in expr = {:?}, count = {:?}, span = {:?}",
expr,
self.expr_count,
expr.map(|e| e.span)
);
if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.first_unresolved_const_or_ty_var(&ty)
{
debug!(
"remained unresolved_type = {:?}, unresolved_type_span: {:?}",
unresolved_type, unresolved_type_span
);
self.prev_unresolved_span = unresolved_type_span;
}
}
}
/// If drop tracking is enabled, consult drop_ranges to see if a value is
/// known to be dropped at a yield point and therefore can be omitted from
/// the generator witness.
fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usize) -> bool {
// short-circuit if drop tracking is not enabled.
if !self.fcx.sess().opts.unstable_opts.drop_tracking {
return false;
}
self.drop_ranges.is_dropped_at(value_hir_id, yield_location)
}
}
pub fn resolve_interior<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
def_id: DefId,
generator_def_id: LocalDefId,
body_id: hir::BodyId,
interior: Ty<'tcx>,
kind: hir::GeneratorKind,
) {
let body = fcx.tcx.hir().body(body_id);
let typeck_results = fcx.inh.typeck_results.borrow();
let mut visitor = InteriorVisitor {
fcx,
types: FxIndexSet::default(),
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
rvalue_scopes: &typeck_results.rvalue_scopes,
expr_count: 0,
kind,
prev_unresolved_span: None,
linted_values: <_>::default(),
drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
};
intravisit::walk_body(&mut visitor, body);
// Check that we visited the same amount of expressions as the RegionResolutionVisitor
let region_expr_count = fcx.tcx.region_scope_tree(def_id).body_expr_count(body_id).unwrap();
assert_eq!(region_expr_count, visitor.expr_count);
// The types are already kept in insertion order.
let types = visitor.types;
if fcx.tcx.features().unsized_locals || fcx.tcx.features().unsized_fn_params {
for interior_ty in &types {
fcx.require_type_is_sized(
interior_ty.ty,
interior_ty.span,
ObligationCauseCode::SizedGeneratorInterior(generator_def_id),
);
}
}
// The types in the generator interior contain lifetimes local to the generator itself,
// which should not be exposed outside of the generator. Therefore, we replace these
// lifetimes with existentially-bound lifetimes, which reflect the exact value of the
// lifetimes not being known by users.
//
// These lifetimes are used in auto trait impl checking (for example,
// if a Sync generator contains an &'α T, we need to check whether &'α T: Sync),
// so knowledge of the exact relationships between them isn't particularly important.
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
// We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
// So, we need to actually do two passes: first by type to anonymize (preserving information
// required for diagnostics), then a second pass over all captured types to reassign disjoint
// region indices.
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
.filter_map(|mut cause| {
// Replace all regions inside the generator interior with late bound regions.
// Note that each region slot in the types gets a new fresh late bound region,
// which means that none of the regions inside relate to any other, even if
// typeck had previously found constraints that would cause them to be related.
let mut counter = 0;
let mut mk_bound_region = |kind| {
let var = ty::BoundVar::from_u32(counter);
counter += 1;
ty::BoundRegion { var, kind }
};
let ty = fcx.normalize(cause.span, cause.ty);
let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
let br = match region.kind() {
ty::ReVar(vid) => {
let origin = fcx.region_var_origin(vid);
match origin {
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
mk_bound_region(ty::BrAnon(Some(span)))
}
_ => mk_bound_region(ty::BrAnon(None)),
}
}
ty::ReEarlyBound(region) => {
mk_bound_region(ty::BrNamed(region.def_id, region.name))
}
ty::ReLateBound(_, ty::BoundRegion { kind, .. })
| ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
ty::BoundRegionKind::BrAnon(span) => mk_bound_region(ty::BrAnon(span)),
ty::BoundRegionKind::BrNamed(def_id, sym) => {
mk_bound_region(ty::BrNamed(def_id, sym))
}
ty::BoundRegionKind::BrEnv => mk_bound_region(ty::BrAnon(None)),
},
_ => mk_bound_region(ty::BrAnon(None)),
};
let r = ty::Region::new_late_bound(fcx.tcx, current_depth, br);
r
});
captured_tys.insert(ty).then(|| {
cause.ty = ty;
cause
})
})
.collect();
let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
let mut counter = 0;
// Optimization: If there is only one captured type, then we don't actually
// need to fold and reindex (since the first type doesn't change).
let type_causes = if captured_tys.len() > 0 {
// Optimization: Use `replace_escaping_bound_vars_uncached` instead of
// `fold_regions`, since we only have late bound regions, and it skips
// types without bound regions.
fcx.tcx.replace_escaping_bound_vars_uncached(
type_causes,
FnMutDelegate {
regions: &mut |br| {
let kind = br.kind;
let var = ty::BoundVar::from_usize(bound_vars.len());
bound_vars.push(ty::BoundVariableKind::Region(kind));
counter += 1;
ty::Region::new_late_bound(
fcx.tcx,
ty::INNERMOST,
ty::BoundRegion { var, kind },
)
},
types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
},
)
} else {
type_causes
};
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty));
let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars);
let witness =
Ty::new_generator_witness(fcx.tcx, ty::Binder::bind_with_vars(type_list, bound_vars));
drop(typeck_results);
// Store the generator types and spans into the typeck results for this generator.
fcx.inh.typeck_results.borrow_mut().generator_interior_types =
ty::Binder::bind_with_vars(type_causes, bound_vars);
debug!(
"types in generator after region replacement {:?}, span = {:?}",
witness, body.value.span
);
// Unify the type variable inside the generator with the new witness
match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(
DefineOpaqueTypes::No,
interior,
witness,
) {
Ok(ok) => fcx.register_infer_ok_obligations(ok),
_ => bug!("failed to relate {interior} and {witness}"),
}
}
// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
// there.
impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
let Arm { guard, pat, body, .. } = arm;
self.visit_pat(pat);
if let Some(ref g) = guard {
{
// If there is a guard, we need to count all variables bound in the pattern as
// borrowed for the entire guard body, regardless of whether they are accessed.
// We do this by walking the pattern bindings and recording `&T` for any `x: T`
// that is bound.
struct ArmPatCollector<'a, 'b, 'tcx> {
interior_visitor: &'a mut InteriorVisitor<'b, 'tcx>,
scope: Scope,
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for ArmPatCollector<'a, 'b, 'tcx> {
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
intravisit::walk_pat(self, pat);
if let PatKind::Binding(_, id, ident, ..) = pat.kind {
let ty =
self.interior_visitor.fcx.typeck_results.borrow().node_type(id);
let tcx = self.interior_visitor.fcx.tcx;
let ty = Ty::new_ref(
tcx,
// Use `ReErased` as `resolve_interior` is going to replace all the
// regions anyway.
tcx.lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
);
self.interior_visitor.record(
ty,
id,
Some(self.scope),
None,
ident.span,
);
}
}
}
ArmPatCollector {
interior_visitor: self,
scope: Scope { id: g.body().hir_id.local_id, data: ScopeData::Node },
}
.visit_pat(pat);
}
match g {
Guard::If(ref e) => {
self.visit_expr(e);
}
Guard::IfLet(ref l) => {
self.visit_let_expr(l);
}
}
}
self.visit_expr(body);
}
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
intravisit::walk_pat(self, pat);
self.expr_count += 1;
if let PatKind::Binding(..) = pat.kind {
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
self.record(ty, pat.hir_id, Some(scope), None, pat.span);
}
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
ExprKind::Call(callee, args) => match &callee.kind {
ExprKind::Path(qpath) => {
let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id);
match res {
// Direct calls never need to keep the callee `ty::FnDef`
// ZST in a temporary, so skip its type, just in case it
// can significantly complicate the generator type.
Res::Def(
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn),
_,
) => {
// NOTE(eddyb) this assumes a path expression has
// no nested expressions to keep track of.
self.expr_count += 1;
// Record the rest of the call expression normally.
for arg in *args {
self.visit_expr(arg);
}
}
_ => intravisit::walk_expr(self, expr),
}
}
_ => intravisit::walk_expr(self, expr),
},
_ => intravisit::walk_expr(self, expr),
}
self.expr_count += 1;
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
// Typically, the value produced by an expression is consumed by its parent in some way,
// so we only have to check if the parent contains a yield (note that the parent may, for
// example, store the value into a local variable, but then we already consider local
// variables to be live across their scope).
//
// However, in the case of temporary values, we are going to store the value into a
// temporary on the stack that is live for the current temporary scope and then return a
// reference to it. That value may be live across the entire temporary scope.
//
// There's another subtlety: if the type has an observable drop, it must be dropped after
// the yield, even if it's not borrowed or referenced after the yield. Ideally this would
// *only* happen for types with observable drop, not all types which wrap them, but that
// doesn't match the behavior of MIR borrowck and causes ICEs. See the FIXME comment in
// tests/ui/generator/drop-tracking-parent-expression.rs.
let scope = if self.drop_ranges.is_borrowed_temporary(expr)
|| ty.map_or(true, |ty| {
// Avoid ICEs in needs_drop.
let ty = self.fcx.resolve_vars_if_possible(ty);
let ty = self.fcx.tcx.erase_regions(ty);
if ty.has_infer() {
self.fcx
.tcx
.sess
.delay_span_bug(expr.span, format!("inference variables in {ty}"));
true
} else {
ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
}
}) {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
} else {
let parent_expr = self
.fcx
.tcx
.hir()
.parent_iter(expr.hir_id)
.find(|(_, node)| matches!(node, hir::Node::Expr(_)))
.map(|(id, _)| id);
debug!("parent_expr: {:?}", parent_expr);
match parent_expr {
Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
None => {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
}
}
};
// If there are adjustments, then record the final type --
// this is the actual value that is being produced.
if let Some(adjusted_ty) = ty {
self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span);
}
// Also record the unadjusted type (which is the only type if
// there are no adjustments). The reason for this is that the
// unadjusted value is sometimes a "temporary" that would wind
// up in a MIR temporary.
//
// As an example, consider an expression like `vec![].push(x)`.
// Here, the `vec![]` would wind up MIR stored into a
// temporary variable `t` which we can borrow to invoke
// `<Vec<_>>::push(&mut t, x)`.
//
// Note that an expression can have many adjustments, and we
// are just ignoring those intermediate types. This is because
// those intermediate values are always linearly "consumed" by
// the other adjustments, and hence would never be directly
// captured in the MIR.
//
// (Note that this partly relies on the fact that the `Deref`
// traits always return references, which means their content
// can be reborrowed without needing to spill to a temporary.
// If this were not the case, then we could conceivably have
// to create intermediate temporaries.)
//
// The type table might not have information for this expression
// if it is in a malformed scope. (#66387)
if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
self.record(ty, expr.hir_id, scope, Some(expr), expr.span);
} else {
self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
}
}
}
#[derive(Default)]
struct SuspendCheckData<'a, 'tcx> {
expr: Option<&'tcx Expr<'tcx>>,
source_span: Span,
yield_span: Span,
descr_pre: &'a str,
descr_post: &'a str,
plural_len: usize,
}
// Returns whether it emitted a diagnostic or not
// Note that this fn and the proceeding one are based on the code
// for creating must_use diagnostics
//
// Note that this technique was chosen over things like a `Suspend` marker trait
// as it is simpler and has precedent in the compiler
fn check_must_not_suspend_ty<'tcx>(
fcx: &FnCtxt<'_, 'tcx>,
ty: Ty<'tcx>,
hir_id: HirId,
data: SuspendCheckData<'_, 'tcx>,
) -> bool {
if ty.is_unit()
// FIXME: should this check `Ty::is_inhabited_from`. This query is not available in this stage
// of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
// `must_use`
// || !ty.is_inhabited_from(fcx.tcx, fcx.tcx.parent_module(hir_id).to_def_id(), fcx.param_env)
{
return false;
}
let plural_suffix = pluralize!(data.plural_len);
debug!("Checking must_not_suspend for {}", ty);
match *ty.kind() {
ty::Adt(..) if ty.is_box() => {
let boxed_ty = ty.boxed_ty();
let descr_pre = &format!("{}boxed ", data.descr_pre);
check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data })
}
ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
// FIXME: support adding the attribute to TAITs
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix);
if check_must_not_suspend_def(
fcx.tcx,
def_id,
hir_id,
SuspendCheckData { descr_pre, ..data },
) {
has_emitted = true;
break;
}
}
}
has_emitted
}
ty::Dynamic(binder, _, _) => {
let mut has_emitted = false;
for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
let def_id = trait_ref.def_id;
let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post);
if check_must_not_suspend_def(
fcx.tcx,
def_id,
hir_id,
SuspendCheckData { descr_post, ..data },
) {
has_emitted = true;
break;
}
}
}
has_emitted
}
ty::Tuple(fields) => {
let mut has_emitted = false;
let comps = match data.expr.map(|e| &e.kind) {
Some(hir::ExprKind::Tup(comps)) if comps.len() == fields.len() => Some(comps),
_ => None,
};
for (i, ty) in fields.iter().enumerate() {
let descr_post = &format!(" in tuple element {i}");
let span = comps.and_then(|c| c.get(i)).map(|e| e.span).unwrap_or(data.source_span);
if check_must_not_suspend_ty(
fcx,
ty,
hir_id,
SuspendCheckData {
descr_post,
expr: comps.and_then(|comps| comps.get(i)),
source_span: span,
..data
},
) {
has_emitted = true;
}
}
has_emitted
}
ty::Array(ty, len) => {
let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
let target_usize =
len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize;
let plural_len = target_usize.saturating_add(1);
check_must_not_suspend_ty(
fcx,
ty,
hir_id,
SuspendCheckData { descr_pre, plural_len, ..data },
)
}
// If drop tracking is enabled, we want to look through references, since the referent
// may not be considered live across the await point.
ty::Ref(_region, ty, _mutability) if fcx.sess().opts.unstable_opts.drop_tracking => {
let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
check_must_not_suspend_ty(fcx, ty, hir_id, SuspendCheckData { descr_pre, ..data })
}
_ => false,
}
}
fn check_must_not_suspend_def(
tcx: TyCtxt<'_>,
def_id: DefId,
hir_id: HirId,
data: SuspendCheckData<'_, '_>,
) -> bool {
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
DelayDm(|| {
format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
)
}),
|lint| {
// add span pointing to the offending yield/await
lint.span_label(data.yield_span, "the value is held across this suspend point");
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
lint.span_note(data.source_span, note.to_string());
}
// Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well?
lint.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
lint
},
);
true
} else {
false
}
}

View file

@ -32,7 +32,6 @@ pub mod expr_use_visitor;
mod fallback; mod fallback;
mod fn_ctxt; mod fn_ctxt;
mod gather_locals; mod gather_locals;
mod generator_interior;
mod inherited; mod inherited;
mod intrinsicck; mod intrinsicck;
mod mem_categorization; mod mem_categorization;

View file

@ -63,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.visit_coercion_casts(); wbcx.visit_coercion_casts();
wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs(); wbcx.visit_user_provided_sigs();
wbcx.visit_generator_interior_types(); wbcx.visit_generator_interior();
wbcx.visit_offset_of_container_types(); wbcx.visit_offset_of_container_types();
wbcx.typeck_results.rvalue_scopes = wbcx.typeck_results.rvalue_scopes =
@ -538,11 +538,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
); );
} }
fn visit_generator_interior_types(&mut self) { fn visit_generator_interior(&mut self) {
let fcx_typeck_results = self.fcx.typeck_results.borrow(); let fcx_typeck_results = self.fcx.typeck_results.borrow();
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
self.typeck_results.generator_interior_types =
fcx_typeck_results.generator_interior_types.clone();
self.tcx().with_stable_hashing_context(move |ref hcx| { self.tcx().with_stable_hashing_context(move |ref hcx| {
for (&expr_def_id, predicates) in for (&expr_def_id, predicates) in
fcx_typeck_results.generator_interior_predicates.to_sorted(hcx, false).into_iter() fcx_typeck_results.generator_interior_predicates.to_sorted(hcx, false).into_iter()

View file

@ -14,8 +14,7 @@ use rustc_span::{symbol::Ident, BytePos, Span};
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use crate::infer::error_reporting::{ use crate::infer::error_reporting::{
need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, need_type_info::UnderspecifiedArgKind, nice_region_error::placeholder_error::Highlighted,
nice_region_error::placeholder_error::Highlighted,
ObligationCauseAsDiagArg, ObligationCauseAsDiagArg,
}; };
@ -86,16 +85,6 @@ pub struct AmbiguousReturn<'a> {
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
} }
#[derive(Diagnostic)]
#[diag(infer_need_type_info_in_generator, code = "E0698")]
pub struct NeedTypeInfoInGenerator<'a> {
#[primary_span]
pub span: Span,
pub generator_kind: GeneratorKindAsDiagArg,
#[subdiagnostic]
pub bad_label: InferenceBadError<'a>,
}
// Used when a better one isn't available // Used when a better one isn't available
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[label(infer_label_bad)] #[label(infer_label_bad)]

View file

@ -459,7 +459,6 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
ty::Closure(..) ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Bool | ty::Bool
| ty::Char | ty::Char
| ty::Int(..) | ty::Int(..)

View file

@ -119,26 +119,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
.obligations, .obligations,
); );
} }
// Optimization of GeneratorWitness relation since we know that all
// free regions are replaced with bound regions during construction.
// This greatly speeds up equating of GeneratorWitness.
(&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
let a_types = infcx.tcx.anonymize_bound_vars(a_types);
let b_types = infcx.tcx.anonymize_bound_vars(b_types);
if a_types.bound_vars() == b_types.bound_vars() {
let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
);
for (a, b) in std::iter::zip(a_types, b_types) {
self.relate(a, b)?;
}
} else {
return Err(ty::error::TypeError::Sorts(ty::relate::expected_found(
self, a, b,
)));
}
}
_ => { _ => {
self.fields.infcx.super_combine_tys(self, a, b)?; self.fields.infcx.super_combine_tys(self, a, b)?;
} }

View file

@ -1,5 +1,5 @@
use crate::errors::{ use crate::errors::{
AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError,
SourceKindMultiSuggestion, SourceKindSubdiag, SourceKindMultiSuggestion, SourceKindSubdiag,
}; };
use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::error_reporting::TypeErrCtxt;
@ -595,39 +595,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
} }
impl<'tcx> InferCtxt<'tcx> {
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
span: Span,
ty: ty::Term<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ty = self.resolve_vars_if_possible(ty);
let data = self.extract_inference_diagnostics_data(ty.into(), None);
NeedTypeInfoInGenerator {
bad_label: data.make_bad_error(span),
span,
generator_kind: GeneratorKindAsDiagArg(kind),
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
}
}
pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind);
impl IntoDiagnosticArg for GeneratorKindAsDiagArg {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
let kind = match self.0 {
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
hir::GeneratorKind::Gen => "generator",
};
rustc_errors::DiagnosticArgValue::Str(kind.into())
}
}
#[derive(Debug)] #[derive(Debug)]
struct InferSource<'tcx> { struct InferSource<'tcx> {
span: Span, span: Span,

View file

@ -112,7 +112,7 @@ fn compute_components<'tcx>(
} }
// All regions are bound inside a witness // All regions are bound inside a witness
ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => (), ty::GeneratorWitness(..) => (),
// OutlivesTypeParameterEnv -- the actual checking that `X:'a` // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
// is implied by the environment is done in regionck. // is implied by the environment is done in regionck.

View file

@ -147,25 +147,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
); );
Ok(a) Ok(a)
} }
// Optimization of GeneratorWitness relation since we know that all
// free regions are replaced with bound regions during construction.
// This greatly speeds up subtyping of GeneratorWitness.
(&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
let a_types = infcx.tcx.anonymize_bound_vars(a_types);
let b_types = infcx.tcx.anonymize_bound_vars(b_types);
if a_types.bound_vars() == b_types.bound_vars() {
let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
);
for (a, b) in std::iter::zip(a_types, b_types) {
self.relate(a, b)?;
}
Ok(a)
} else {
Err(ty::error::TypeError::Sorts(ty::relate::expected_found(self, a, b)))
}
}
_ => { _ => {
self.fields.infcx.super_combine_tys(self, a, b)?; self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a) Ok(a)

View file

@ -798,14 +798,12 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
} }
}); });
if tcx.sess.opts.unstable_opts.drop_tracking_mir { tcx.hir().par_body_owners(|def_id| {
tcx.hir().par_body_owners(|def_id| { if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) {
if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) { tcx.ensure().mir_generator_witnesses(def_id);
tcx.ensure().mir_generator_witnesses(def_id); tcx.ensure().check_generator_obligations(def_id);
tcx.ensure().check_generator_obligations(def_id); }
} });
});
}
sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx));

View file

@ -684,7 +684,6 @@ fn test_unstable_options_tracking_hash() {
untracked!(dep_tasks, true); untracked!(dep_tasks, true);
untracked!(dont_buffer_diagnostics, true); untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true); untracked!(dump_dep_graph, true);
untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir, Some(String::from("abc")));
untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dataflow, true);
untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_dir, String::from("abc"));
@ -773,7 +772,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(debug_info_for_profiling, true); tracked!(debug_info_for_profiling, true);
tracked!(debug_macros, true); tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true); tracked!(dep_info_omit_d_target, true);
tracked!(drop_tracking, true);
tracked!(dual_proc_macros, true); tracked!(dual_proc_macros, true);
tracked!(dwarf_version, Some(5)); tracked!(dwarf_version, Some(5));
tracked!(emit_thin_lto, false); tracked!(emit_thin_lto, false);

View file

@ -1271,7 +1271,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
} }

View file

@ -306,6 +306,7 @@ declare_lint! {
/// pub async fn uhoh() { /// pub async fn uhoh() {
/// let guard = SyncThing {}; /// let guard = SyncThing {};
/// yield_now().await; /// yield_now().await;
/// let _guard = guard;
/// } /// }
/// ``` /// ```
/// ///

View file

@ -24,7 +24,6 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::GeneratorDiagnosticData;
use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility};
use rustc_serialize::opaque::MemDecoder; use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::{Decodable, Decoder}; use rustc_serialize::{Decodable, Decoder};
@ -1750,24 +1749,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.clone() .clone()
} }
fn get_generator_diagnostic_data(
self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> Option<GeneratorDiagnosticData<'tcx>> {
self.root
.tables
.generator_diagnostic_data
.get(self, id)
.map(|param| param.decode((self, tcx)))
.map(|generator_data| GeneratorDiagnosticData {
generator_interior_types: generator_data.generator_interior_types,
hir_owner: generator_data.hir_owner,
nodes_types: generator_data.nodes_types,
adjustments: generator_data.adjustments,
})
}
fn get_attr_flags(self, index: DefIndex) -> AttrFlags { fn get_attr_flags(self, index: DefIndex) -> AttrFlags {
self.root.tables.attr_flags.get(self, index) self.root.tables.attr_flags.get(self, index)
} }

View file

@ -374,7 +374,6 @@ provide! { tcx, def_id, other, cdata,
crate_extern_paths => { cdata.source().paths().cloned().collect() } crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) } is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) }
doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) } doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) }
doc_link_traits_in_scope => { doc_link_traits_in_scope => {

View file

@ -1439,7 +1439,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
} }
if let DefKind::Generator = def_kind { if let DefKind::Generator = def_kind {
self.encode_info_for_generator(local_id); let data = self.tcx.generator_kind(def_id).unwrap();
record!(self.tables.generator_kind[def_id] <- data);
} }
if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
self.encode_info_for_adt(local_id); self.encode_info_for_adt(local_id);
@ -1612,8 +1613,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()]
<- tcx.closure_saved_names_of_captured_variables(def_id)); <- tcx.closure_saved_names_of_captured_variables(def_id));
if tcx.sess.opts.unstable_opts.drop_tracking_mir if let DefKind::Generator = self.tcx.def_kind(def_id)
&& let DefKind::Generator = self.tcx.def_kind(def_id)
&& let Some(witnesses) = tcx.mir_generator_witnesses(def_id) && let Some(witnesses) = tcx.mir_generator_witnesses(def_id)
{ {
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses); record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses);
@ -1640,6 +1640,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
if let DefKind::Generator = self.tcx.def_kind(def_id)
&& let Some(witnesses) = tcx.mir_generator_witnesses(def_id)
{
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses);
}
let instance = ty::InstanceDef::Item(def_id.to_def_id()); let instance = ty::InstanceDef::Item(def_id.to_def_id());
let unused = tcx.unused_generic_params(instance); let unused = tcx.unused_generic_params(instance);
self.tables.unused_generic_params.set(def_id.local_def_index, unused); self.tables.unused_generic_params.set(def_id.local_def_index, unused);
@ -1712,15 +1718,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body);
} }
#[instrument(level = "debug", skip(self))]
fn encode_info_for_generator(&mut self, def_id: LocalDefId) {
let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
let data = self.tcx.generator_kind(def_id).unwrap();
let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data);
}
fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> { fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
empty_proc_macro!(self); empty_proc_macro!(self);
let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);

View file

@ -23,7 +23,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams}; use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_middle::ty::{DeducedParamAttrs, ParameterizedOverTcx, TyCtxt};
use rustc_middle::util::Providers; use rustc_middle::util::Providers;
use rustc_serialize::opaque::FileEncoder; use rustc_serialize::opaque::FileEncoder;
use rustc_session::config::SymbolManglingVersion; use rustc_session::config::SymbolManglingVersion;
@ -452,7 +452,6 @@ define_tables! {
// definitions from any given crate. // definitions from any given crate.
def_keys: Table<DefIndex, LazyValue<DefKey>>, def_keys: Table<DefIndex, LazyValue<DefKey>>,
proc_macro_quoted_spans: Table<usize, LazyValue<Span>>, proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
variant_data: Table<DefIndex, LazyValue<VariantData>>, variant_data: Table<DefIndex, LazyValue<VariantData>>,
assoc_container: Table<DefIndex, ty::AssocItemContainer>, assoc_container: Table<DefIndex, ty::AssocItemContainer>,
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,

View file

@ -44,7 +44,6 @@ use crate::traits::{
use crate::ty::fast_reject::SimplifiedType; use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::ValidityRequirement; use crate::ty::layout::ValidityRequirement;
use crate::ty::util::AlwaysRequiresDrop; use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::GeneratorDiagnosticData;
use crate::ty::TyCtxtFeed; use crate::ty::TyCtxtFeed;
use crate::ty::{ use crate::ty::{
self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt,
@ -2149,12 +2148,6 @@ rustc_queries! {
desc { "computing the backend features for CLI flags" } desc { "computing the backend features for CLI flags" }
} }
query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> {
arena_cache
desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
separate_provide_extern
}
query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> { query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
} }

View file

@ -566,6 +566,5 @@ impl_binder_encode_decode! {
ty::TraitPredicate<'tcx>, ty::TraitPredicate<'tcx>,
ty::ExistentialPredicate<'tcx>, ty::ExistentialPredicate<'tcx>,
ty::TraitRef<'tcx>, ty::TraitRef<'tcx>,
Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
ty::ExistentialTraitRef<'tcx>, ty::ExistentialTraitRef<'tcx>,
} }

View file

@ -1384,7 +1384,6 @@ impl<'tcx> TyCtxt<'tcx> {
Placeholder, Placeholder,
Generator, Generator,
GeneratorWitness, GeneratorWitness,
GeneratorWitnessMIR,
Dynamic, Dynamic,
Closure, Closure,
Tuple, Tuple,

View file

@ -242,8 +242,7 @@ impl<'tcx> Ty<'tcx> {
ty::Dynamic(..) => "trait object".into(), ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(), ty::Closure(..) => "closure".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) | ty::GeneratorWitness(..) => "generator witness".into(),
ty::GeneratorWitnessMIR(..) => "generator witness".into(),
ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(),
ty::Infer(ty::IntVar(_)) => "integer".into(), ty::Infer(ty::IntVar(_)) => "integer".into(),
ty::Infer(ty::FloatVar(_)) => "floating-point number".into(), ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
@ -295,7 +294,7 @@ impl<'tcx> Ty<'tcx> {
ty::Dynamic(..) => "trait object".into(), ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(), ty::Closure(..) => "closure".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(), ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(), ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(), ty::Placeholder(..) => "higher-ranked type".into(),
ty::Bound(..) => "bound type variable".into(), ty::Bound(..) => "bound type variable".into(),

View file

@ -29,8 +29,7 @@ pub enum SimplifiedType {
Trait(DefId), Trait(DefId),
Closure(DefId), Closure(DefId),
Generator(DefId), Generator(DefId),
GeneratorWitness(usize), GeneratorWitness(DefId),
GeneratorWitnessMIR(DefId),
Function(usize), Function(usize),
Placeholder, Placeholder,
} }
@ -130,10 +129,7 @@ pub fn simplify_type<'tcx>(
ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)), ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)),
ty::Generator(def_id, _, _) => Some(SimplifiedType::Generator(def_id)), ty::Generator(def_id, _, _) => Some(SimplifiedType::Generator(def_id)),
ty::GeneratorWitness(tys) => { ty::GeneratorWitness(def_id, _) => Some(SimplifiedType::GeneratorWitness(def_id)),
Some(SimplifiedType::GeneratorWitness(tys.skip_binder().len()))
}
ty::GeneratorWitnessMIR(def_id, _) => Some(SimplifiedType::GeneratorWitnessMIR(def_id)),
ty::Never => Some(SimplifiedType::Never), ty::Never => Some(SimplifiedType::Never),
ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())), ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())), ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())),
@ -169,7 +165,7 @@ impl SimplifiedType {
| SimplifiedType::Trait(d) | SimplifiedType::Trait(d)
| SimplifiedType::Closure(d) | SimplifiedType::Closure(d)
| SimplifiedType::Generator(d) | SimplifiedType::Generator(d)
| SimplifiedType::GeneratorWitnessMIR(d) => Some(d), | SimplifiedType::GeneratorWitness(d) => Some(d),
_ => None, _ => None,
} }
} }
@ -240,7 +236,6 @@ impl DeepRejectCtxt {
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Bound(..) | ty::Bound(..)
| ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
@ -342,7 +337,7 @@ impl DeepRejectCtxt {
ty::Error(_) => true, ty::Error(_) => true,
ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => { ty::GeneratorWitness(..) => {
bug!("unexpected obligation type: {:?}", obligation_ty) bug!("unexpected obligation type: {:?}", obligation_ty)
} }
} }

View file

@ -127,11 +127,7 @@ impl FlagComputation {
self.add_ty(args.tupled_upvars_ty()); self.add_ty(args.tupled_upvars_ty());
} }
&ty::GeneratorWitness(ts) => { ty::GeneratorWitness(_, args) => {
self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
}
ty::GeneratorWitnessMIR(_, args) => {
let should_remove_further_specializable = let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_args(args); self.add_args(args);

View file

@ -810,7 +810,6 @@ where
| ty::Never | ty::Never
| ty::FnDef(..) | ty::FnDef(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Foreign(..) | ty::Foreign(..)
| ty::Dynamic(_, _, ty::Dyn) => { | ty::Dynamic(_, _, ty::Dyn) => {
bug!("TyAndLayout::field({:?}): not applicable", this) bug!("TyAndLayout::field({:?}): not applicable", this)

View file

@ -106,9 +106,8 @@ pub use self::sty::{
}; };
pub use self::trait_def::TraitDef; pub use self::trait_def::TraitDef;
pub use self::typeck_results::{ pub use self::typeck_results::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType, UserType, UserTypeAnnotationIndex,
UserTypeAnnotationIndex,
}; };
pub mod _match; pub mod _match;

View file

@ -157,9 +157,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
Ty::new_generator(self.tcx, def_id, args, movability) Ty::new_generator(self.tcx, def_id, args, movability)
} }
ty::GeneratorWitnessMIR(def_id, args) => { ty::GeneratorWitness(def_id, args) => {
let args = self.fold_closure_args(def_id, args); let args = self.fold_closure_args(def_id, args);
Ty::new_generator_witness_mir(self.tcx, def_id, args) Ty::new_generator_witness(self.tcx, def_id, args)
} }
ty::Param(param) => { ty::Param(param) => {

View file

@ -132,5 +132,4 @@ parameterized_over_tcx! {
ty::Predicate, ty::Predicate,
ty::Clause, ty::Clause,
ty::ClauseKind, ty::ClauseKind,
ty::GeneratorDiagnosticData,
} }

View file

@ -271,7 +271,7 @@ fn characteristic_def_id_of_type_cached<'a>(
ty::FnDef(def_id, _) ty::FnDef(def_id, _)
| ty::Closure(def_id, _) | ty::Closure(def_id, _)
| ty::Generator(def_id, _, _) | ty::Generator(def_id, _, _)
| ty::GeneratorWitnessMIR(def_id, _) | ty::GeneratorWitness(def_id, _)
| ty::Foreign(def_id) => Some(def_id), | ty::Foreign(def_id) => Some(def_id),
ty::Bool ty::Bool
@ -286,7 +286,6 @@ fn characteristic_def_id_of_type_cached<'a>(
| ty::Infer(_) | ty::Infer(_)
| ty::Bound(..) | ty::Bound(..)
| ty::Error(_) | ty::Error(_)
| ty::GeneratorWitness(..)
| ty::Never | ty::Never
| ty::Float(_) => None, | ty::Float(_) => None,
} }

View file

@ -838,10 +838,7 @@ pub trait PrettyPrinter<'tcx>:
p!("}}") p!("}}")
} }
ty::GeneratorWitness(types) => { ty::GeneratorWitness(did, args) => {
p!(in_binder(&types));
}
ty::GeneratorWitnessMIR(did, args) => {
p!(write("{{")); p!(write("{{"));
if !self.tcx().sess.verbose() { if !self.tcx().sess.verbose() {
p!("generator witness"); p!("generator witness");

View file

@ -453,24 +453,14 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(Ty::new_generator(tcx, a_id, args, movability)) Ok(Ty::new_generator(tcx, a_id, args, movability))
} }
(&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { (&ty::GeneratorWitness(a_id, a_args), &ty::GeneratorWitness(b_id, b_args))
// Wrap our types with a temporary GeneratorWitness struct
// inside the binder so we can related them
let a_types = a_types.map_bound(GeneratorWitness);
let b_types = b_types.map_bound(GeneratorWitness);
// Then remove the GeneratorWitness for the result
let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0);
Ok(Ty::new_generator_witness(tcx, types))
}
(&ty::GeneratorWitnessMIR(a_id, a_args), &ty::GeneratorWitnessMIR(b_id, b_args))
if a_id == b_id => if a_id == b_id =>
{ {
// All GeneratorWitness types with the same id represent // All GeneratorWitness types with the same id represent
// the (anonymous) type of the same generator expression. So // the (anonymous) type of the same generator expression. So
// all of their regions should be equated. // all of their regions should be equated.
let args = relation.relate(a_args, b_args)?; let args = relation.relate(a_args, b_args)?;
Ok(Ty::new_generator_witness_mir(tcx, a_id, args)) Ok(Ty::new_generator_witness(tcx, a_id, args))
} }
(&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => { (&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => {

View file

@ -657,9 +657,8 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Generator(did, args, movability) => { ty::Generator(did, args, movability) => {
ty::Generator(did, args.try_fold_with(folder)?, movability) ty::Generator(did, args.try_fold_with(folder)?, movability)
} }
ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), ty::GeneratorWitness(did, args) => {
ty::GeneratorWitnessMIR(did, args) => { ty::GeneratorWitness(did, args.try_fold_with(folder)?)
ty::GeneratorWitnessMIR(did, args.try_fold_with(folder)?)
} }
ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?), ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?),
ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
@ -708,8 +707,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
ty.visit_with(visitor) ty.visit_with(visitor)
} }
ty::Generator(_did, ref args, _) => args.visit_with(visitor), ty::Generator(_did, ref args, _) => args.visit_with(visitor),
ty::GeneratorWitness(ref types) => types.visit_with(visitor), ty::GeneratorWitness(_did, ref args) => args.visit_with(visitor),
ty::GeneratorWitnessMIR(_did, ref args) => args.visit_with(visitor),
ty::Closure(_did, ref args) => args.visit_with(visitor), ty::Closure(_did, ref args) => args.visit_with(visitor),
ty::Alias(_, ref data) => data.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor),

View file

@ -2164,19 +2164,11 @@ impl<'tcx> Ty<'tcx> {
#[inline] #[inline]
pub fn new_generator_witness( pub fn new_generator_witness(
tcx: TyCtxt<'tcx>,
types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>,
) -> Ty<'tcx> {
Ty::new(tcx, GeneratorWitness(types))
}
#[inline]
pub fn new_generator_witness_mir(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
id: DefId, id: DefId,
args: GenericArgsRef<'tcx>, args: GenericArgsRef<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
Ty::new(tcx, GeneratorWitnessMIR(id, args)) Ty::new(tcx, GeneratorWitness(id, args))
} }
// misc // misc
@ -2706,7 +2698,6 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..) | ty::Dynamic(..)
| ty::Closure(..) | ty::Closure(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Error(_) | ty::Error(_)
@ -2742,7 +2733,6 @@ impl<'tcx> Ty<'tcx> {
| ty::Ref(..) | ty::Ref(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Array(..) | ty::Array(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never
@ -2831,7 +2821,6 @@ impl<'tcx> Ty<'tcx> {
| ty::Ref(..) | ty::Ref(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Array(..) | ty::Array(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never
@ -2894,7 +2883,7 @@ impl<'tcx> Ty<'tcx> {
// anything with custom metadata it might be more complicated. // anything with custom metadata it might be more complicated.
ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => false, ty::Generator(..) | ty::GeneratorWitness(..) => false,
// Might be, but not "trivial" so just giving the safe answer. // Might be, but not "trivial" so just giving the safe answer.
ty::Adt(..) | ty::Closure(..) => false, ty::Adt(..) | ty::Closure(..) => false,
@ -2970,8 +2959,7 @@ impl<'tcx> Ty<'tcx> {
| Dynamic(_, _, _) | Dynamic(_, _, _)
| Closure(_, _) | Closure(_, _)
| Generator(_, _, _) | Generator(_, _, _)
| GeneratorWitness(_) | GeneratorWitness(..)
| GeneratorWitnessMIR(_, _)
| Never | Never
| Tuple(_) => true, | Tuple(_) => true,
Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false, Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false,

View file

@ -189,10 +189,6 @@ pub struct TypeckResults<'tcx> {
/// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
pub rvalue_scopes: RvalueScopes, pub rvalue_scopes: RvalueScopes,
/// Stores the type, expression, span and optional scope span of all types
/// that are live across the yield of this generator (if a generator).
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
/// Stores the predicates that apply on generator witness types. /// Stores the predicates that apply on generator witness types.
/// formatting modified file tests/ui/generator/retain-resume-ref.rs /// formatting modified file tests/ui/generator/retain-resume-ref.rs
pub generator_interior_predicates: pub generator_interior_predicates:
@ -212,49 +208,6 @@ pub struct TypeckResults<'tcx> {
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>, offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
} }
/// Whenever a value may be live across a generator yield, the type of that value winds up in the
/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
/// captured types that can be useful for diagnostics. In particular, it stores the span that
/// caused a given type to be recorded, along with the scope that enclosed the value (which can
/// be used to find the await that the value is live across).
///
/// For example:
///
/// ```ignore (pseudo-Rust)
/// async move {
/// let x: T = expr;
/// foo.await
/// ...
/// }
/// ```
///
/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct GeneratorInteriorTypeCause<'tcx> {
/// Type of the captured binding.
pub ty: Ty<'tcx>,
/// Span of the binding that was captured.
pub span: Span,
/// Span of the scope of the captured binding.
pub scope_span: Option<Span>,
/// Span of `.await` or `yield` expression.
pub yield_span: Span,
/// Expr which the type evaluated from.
pub expr: Option<hir::HirId>,
}
// This type holds diagnostic information on generators and async functions across crate boundaries
// and is used to provide better error messages
#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
pub struct GeneratorDiagnosticData<'tcx> {
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
pub hir_owner: DefId,
pub nodes_types: ItemLocalMap<Ty<'tcx>>,
pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
}
impl<'tcx> TypeckResults<'tcx> { impl<'tcx> TypeckResults<'tcx> {
pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> { pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
TypeckResults { TypeckResults {
@ -278,7 +231,6 @@ impl<'tcx> TypeckResults<'tcx> {
closure_min_captures: Default::default(), closure_min_captures: Default::default(),
closure_fake_reads: Default::default(), closure_fake_reads: Default::default(),
rvalue_scopes: Default::default(), rvalue_scopes: Default::default(),
generator_interior_types: ty::Binder::dummy(Default::default()),
generator_interior_predicates: Default::default(), generator_interior_predicates: Default::default(),
treat_byte_string_as_slice: Default::default(), treat_byte_string_as_slice: Default::default(),
closure_size_eval: Default::default(), closure_size_eval: Default::default(),
@ -351,28 +303,6 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types } LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
} }
pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
vec.iter()
.map(|item| {
GeneratorInteriorTypeCause {
ty: item.ty,
span: item.span,
scope_span: item.scope_span,
yield_span: item.yield_span,
expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
}
})
.collect::<Vec<_>>()
});
GeneratorDiagnosticData {
generator_interior_types: generator_interior_type,
hir_owner: self.hir_owner.to_def_id(),
nodes_types: self.node_types.clone(),
adjustments: self.adjustments.clone(),
}
}
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
self.node_type_opt(id).unwrap_or_else(|| { self.node_type_opt(id).unwrap_or_else(|| {
bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id))) bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id)))

View file

@ -855,7 +855,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
let hidden_ty = bty.instantiate(self.tcx, args); let hidden_ty = bty.instantiate(self.tcx, args);
self.fold_ty(hidden_ty); self.fold_ty(hidden_ty);
} }
let expanded_ty = Ty::new_generator_witness_mir(self.tcx, def_id, args); let expanded_ty = Ty::new_generator_witness(self.tcx, def_id, args);
self.expanded_cache.insert((def_id, args), expanded_ty); self.expanded_cache.insert((def_id, args), expanded_ty);
expanded_ty expanded_ty
} }
@ -888,7 +888,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
t t
}; };
if self.expand_generators { if self.expand_generators {
if let ty::GeneratorWitnessMIR(def_id, args) = *t.kind() { if let ty::GeneratorWitness(def_id, args) = *t.kind() {
t = self.expand_generator(def_id, args).unwrap_or(t); t = self.expand_generator(def_id, args).unwrap_or(t);
} }
} }
@ -1025,8 +1025,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..) | ty::Dynamic(..)
| ty::Foreign(_) | ty::Foreign(_)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(_) | ty::Infer(_)
| ty::Alias(..) | ty::Alias(..)
| ty::Param(_) | ty::Param(_)
@ -1065,8 +1064,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..) | ty::Dynamic(..)
| ty::Foreign(_) | ty::Foreign(_)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(_) | ty::Infer(_)
| ty::Alias(..) | ty::Alias(..)
| ty::Param(_) | ty::Param(_)
@ -1194,10 +1192,7 @@ impl<'tcx> Ty<'tcx> {
false false
} }
ty::Foreign(_) ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
| ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Error(_) => false,
} }
} }
@ -1293,7 +1288,6 @@ pub fn needs_drop_components<'tcx>(
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::Char | ty::Char
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::RawPtr(_) | ty::RawPtr(_)
| ty::Ref(..) | ty::Ref(..)
| ty::Str => Ok(SmallVec::new()), | ty::Str => Ok(SmallVec::new()),
@ -1364,11 +1358,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
// Not trivial because they have components, and instead of looking inside, // Not trivial because they have components, and instead of looking inside,
// we'll just perform trait selection. // we'll just perform trait selection.
ty::Closure(..) ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | ty::Adt(..) => false,
| ty::Generator(..)
| ty::GeneratorWitness(_)
| ty::GeneratorWitnessMIR(..)
| ty::Adt(..) => false,
ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),

View file

@ -190,14 +190,11 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
ty::Adt(_, args) ty::Adt(_, args)
| ty::Closure(_, args) | ty::Closure(_, args)
| ty::Generator(_, args, _) | ty::Generator(_, args, _)
| ty::GeneratorWitnessMIR(_, args) | ty::GeneratorWitness(_, args)
| ty::FnDef(_, args) => { | ty::FnDef(_, args) => {
stack.extend(args.iter().rev()); stack.extend(args.iter().rev());
} }
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)), ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
ty::GeneratorWitness(ts) => {
stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into()));
}
ty::FnPtr(sig) => { ty::FnPtr(sig) => {
stack.push(sig.skip_binder().output().into()); stack.push(sig.skip_binder().output().into());
stack.extend(sig.skip_binder().inputs().iter().copied().rev().map(|ty| ty.into())); stack.extend(sig.skip_binder().inputs().iter().copied().rev().map(|ty| ty.into()));

View file

@ -144,8 +144,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(_, _)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Alias(_, _) | ty::Alias(_, _)
@ -184,8 +183,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| ty::FnDef(_, _) | ty::FnDef(_, _)
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(_, _)
| ty::Never | ty::Never
| ty::Alias(_, _) | ty::Alias(_, _)
| ty::Param(_) | ty::Param(_)

View file

@ -4,7 +4,9 @@ use rustc_errors::{
}; };
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::{self, Lint}; use rustc_session::lint::{self, Lint};
use rustc_span::def_id::DefId;
use rustc_span::Span; use rustc_span::Span;
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]
@ -237,20 +239,38 @@ pub(crate) struct FnItemRef {
pub ident: String, pub ident: String,
} }
#[derive(LintDiagnostic)] pub(crate) struct MustNotSupend<'tcx, 'a> {
#[diag(mir_transform_must_not_suspend)] pub tcx: TyCtxt<'tcx>,
pub(crate) struct MustNotSupend<'a> {
#[label]
pub yield_sp: Span, pub yield_sp: Span,
#[subdiagnostic]
pub reason: Option<MustNotSuspendReason>, pub reason: Option<MustNotSuspendReason>,
#[help]
pub src_sp: Span, pub src_sp: Span,
pub pre: &'a str, pub pre: &'a str,
pub def_path: String, pub def_id: DefId,
pub post: &'a str, pub post: &'a str,
} }
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> {
fn decorate_lint<'b>(
self,
diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
diag.span_label(self.yield_sp, crate::fluent_generated::_subdiag::label);
if let Some(reason) = self.reason {
diag.subdiagnostic(reason);
}
diag.span_help(self.src_sp, crate::fluent_generated::_subdiag::help);
diag.set_arg("pre", self.pre);
diag.set_arg("def_path", self.tcx.def_path_str(self.def_id));
diag.set_arg("post", self.post);
diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
crate::fluent_generated::mir_transform_must_not_suspend
}
}
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[note(mir_transform_note)] #[note(mir_transform_note)]
pub(crate) struct MustNotSuspendReason { pub(crate) struct MustNotSuspendReason {

View file

@ -853,60 +853,7 @@ impl StorageConflictVisitor<'_, '_, '_> {
} }
} }
/// Validates the typeck view of the generator against the actual set of types saved between
/// yield points.
fn sanitize_witness<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
witness: Ty<'tcx>,
upvars: &'tcx ty::List<Ty<'tcx>>,
layout: &GeneratorLayout<'tcx>,
) {
let did = body.source.def_id();
let param_env = tcx.param_env(did);
let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars);
let allowed = match witness.kind() {
&ty::GeneratorWitness(interior_tys) => {
tcx.normalize_erasing_late_bound_regions(param_env, interior_tys)
}
_ => {
tcx.sess.delay_span_bug(
body.span,
format!("unexpected generator witness type {:?}", witness.kind()),
);
return;
}
};
let mut mismatches = Vec::new();
for fty in &layout.field_tys {
if fty.ignore_for_traits {
continue;
}
let decl_ty = tcx.normalize_erasing_regions(param_env, fty.ty);
// Sanity check that typeck knows about the type of locals which are
// live across a suspension point
if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) {
mismatches.push(decl_ty);
}
}
if !mismatches.is_empty() {
span_bug!(
body.span,
"Broken MIR: generator contains type {:?} in MIR, \
but typeck only knows about {} and {:?}",
mismatches,
allowed,
allowed_upvars
);
}
}
fn compute_layout<'tcx>( fn compute_layout<'tcx>(
tcx: TyCtxt<'tcx>,
liveness: LivenessInfo, liveness: LivenessInfo,
body: &Body<'tcx>, body: &Body<'tcx>,
) -> ( ) -> (
@ -932,27 +879,20 @@ fn compute_layout<'tcx>(
let decl = &body.local_decls[local]; let decl = &body.local_decls[local];
debug!(?decl); debug!(?decl);
let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir { // Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared
// Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared // the information. This is alright, since `ignore_for_traits` is only relevant when
// the information. This is alright, since `ignore_for_traits` is only relevant when // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
// this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer // default.
// default. let ignore_for_traits = match decl.local_info {
match decl.local_info { // Do not include raw pointers created from accessing `static` items, as those could
// Do not include raw pointers created from accessing `static` items, as those could // well be re-created by another access to the same static.
// well be re-created by another access to the same static. ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => {
ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => { !is_thread_local
!is_thread_local
}
// Fake borrows are only read by fake reads, so do not have any reality in
// post-analysis MIR.
ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true,
_ => false,
} }
} else { // Fake borrows are only read by fake reads, so do not have any reality in
// FIXME(#105084) HIR-based drop tracking does not account for all the temporaries that // post-analysis MIR.
// MIR building may introduce. This leads to wrongly ignored types, but this is ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true,
// necessary for internal consistency and to avoid ICEs. _ => false,
decl.internal
}; };
let decl = let decl =
GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits }; GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits };
@ -1445,8 +1385,6 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId, def_id: LocalDefId,
) -> Option<GeneratorLayout<'tcx>> { ) -> Option<GeneratorLayout<'tcx>> {
assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
let (body, _) = tcx.mir_promoted(def_id); let (body, _) = tcx.mir_promoted(def_id);
let body = body.borrow(); let body = body.borrow();
let body = &*body; let body = &*body;
@ -1469,7 +1407,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
// Extract locals which are live across suspension point into `layout` // Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices // `remap` gives a mapping from local indices onto generator struct indices
// `storage_liveness` tells us which locals have live storage at suspension points // `storage_liveness` tells us which locals have live storage at suspension points
let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body); let (_, generator_layout, _) = compute_layout(liveness_info, body);
check_suspend_tys(tcx, &generator_layout, &body); check_suspend_tys(tcx, &generator_layout, &body);
@ -1489,15 +1427,10 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
let gen_ty = body.local_decls.raw[1].ty; let gen_ty = body.local_decls.raw[1].ty;
// Get the discriminant type and args which typeck computed // Get the discriminant type and args which typeck computed
let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() { let (discr_ty, movable) = match *gen_ty.kind() {
ty::Generator(_, args, movability) => { ty::Generator(_, args, movability) => {
let args = args.as_generator(); let args = args.as_generator();
( (args.discr_ty(tcx), movability == hir::Movability::Movable)
args.discr_ty(tcx),
args.upvar_tys(),
args.witness(),
movability == hir::Movability::Movable,
)
} }
_ => { _ => {
tcx.sess.delay_span_bug(body.span, format!("unexpected generator type {gen_ty}")); tcx.sess.delay_span_bug(body.span, format!("unexpected generator type {gen_ty}"));
@ -1574,13 +1507,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
// Extract locals which are live across suspension point into `layout` // Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices // `remap` gives a mapping from local indices onto generator struct indices
// `storage_liveness` tells us which locals have live storage at suspension points // `storage_liveness` tells us which locals have live storage at suspension points
let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body); let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
if tcx.sess.opts.unstable_opts.validate_mir
&& !tcx.sess.opts.unstable_opts.drop_tracking_mir
{
sanitize_witness(tcx, body, interior, upvars, &layout);
}
let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
@ -1954,11 +1881,12 @@ fn check_must_not_suspend_def(
hir_id, hir_id,
data.source_span, data.source_span,
errors::MustNotSupend { errors::MustNotSupend {
tcx,
yield_sp: data.yield_span, yield_sp: data.yield_span,
reason, reason,
src_sp: data.source_span, src_sp: data.source_span,
pre: data.descr_pre, pre: data.descr_pre,
def_path: tcx.def_path_str(def_id), def_id,
post: data.descr_post, post: data.descr_post,
}, },
); );

View file

@ -358,9 +358,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't /// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
/// end up missing the source MIR due to stealing happening. /// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
if tcx.sess.opts.unstable_opts.drop_tracking_mir if let DefKind::Generator = tcx.def_kind(def) {
&& let DefKind::Generator = tcx.def_kind(def)
{
tcx.ensure_with_value().mir_generator_witnesses(def); tcx.ensure_with_value().mir_generator_witnesses(def);
} }
let mir_borrowck = tcx.mir_borrowck(def); let mir_borrowck = tcx.mir_borrowck(def);

View file

@ -291,8 +291,7 @@ where
| ty::Param(..) | ty::Param(..)
| ty::Bound(..) | ty::Bound(..)
| ty::Error(_) | ty::Error(_)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..) => {}
| ty::GeneratorWitnessMIR(..) => {}
ty::Placeholder(..) | ty::Infer(..) => { ty::Placeholder(..) | ty::Infer(..) => {
bug!("unexpected type: {:?}", ty) bug!("unexpected type: {:?}", ty)
} }

View file

@ -1458,17 +1458,11 @@ options! {
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \ "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
(default: no)"), (default: no)"),
drop_tracking: bool = (false, parse_bool, [TRACKED],
"enables drop tracking in generators (default: no)"),
drop_tracking_mir: bool = (false, parse_bool, [TRACKED],
"enables drop tracking on MIR in generators (default: no)"),
dual_proc_macros: bool = (false, parse_bool, [TRACKED], dual_proc_macros: bool = (false, parse_bool, [TRACKED],
"load proc macros for both target and host, but only link to the target (default: no)"), "load proc macros for both target and host, but only link to the target (default: no)"),
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \ "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
(default: no)"), (default: no)"),
dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump drop-tracking control-flow graph as a `.dot` file (default: no)"),
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED], dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump MIR state to file. "dump MIR state to file.
`val` is used to select which passes and functions to dump. For example: `val` is used to select which passes and functions to dump. For example:

View file

@ -1128,11 +1128,7 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
ty::Bound(debruijn_idx, bound_ty) => { ty::Bound(debruijn_idx, bound_ty) => {
TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables)) TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables))
} }
ty::Placeholder(..) ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) | ty::Error(_) => {
| ty::GeneratorWitness(_)
| ty::GeneratorWitnessMIR(_, _)
| ty::Infer(_)
| ty::Error(_) => {
unreachable!(); unreachable!();
} }
} }

View file

@ -720,7 +720,6 @@ fn encode_ty<'tcx>(
| ty::Bound(..) | ty::Bound(..)
| ty::Error(..) | ty::Error(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(..) | ty::Infer(..)
| ty::Placeholder(..) => { | ty::Placeholder(..) => {
bug!("encode_ty: unexpected `{:?}`", ty.kind()); bug!("encode_ty: unexpected `{:?}`", ty.kind());
@ -973,12 +972,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
); );
} }
ty::Bound(..) ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
| ty::Error(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(..)
| ty::Param(..)
| ty::Placeholder(..) => {
bug!("transform_ty: unexpected `{:?}`", ty.kind()); bug!("transform_ty: unexpected `{:?}`", ty.kind());
} }
} }

View file

@ -484,8 +484,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"), ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"),
ty::Alias(ty::Weak, _) => bug!("symbol_names: unexpected weak projection"), ty::Alias(ty::Weak, _) => bug!("symbol_names: unexpected weak projection"),
ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), ty::GeneratorWitness(..) => bug!("symbol_names: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
} }
// Only cache types that do not refer to an enclosing // Only cache types that do not refer to an enclosing

View file

@ -469,7 +469,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// FIXME: These should ideally not exist as a self type. It would be nice for // FIXME: These should ideally not exist as a self type. It would be nice for
// the builtin auto trait impls of generators to instead directly recurse // the builtin auto trait impls of generators to instead directly recurse
// into the witness. // into the witness.
ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (), ty::GeneratorWitness(..) => (),
// These variants should not exist as a self type. // These variants should not exist as a self type.
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
@ -621,8 +621,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Dynamic(..) | ty::Dynamic(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Param(_) | ty::Param(_)
@ -778,8 +777,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Alias(..) | ty::Alias(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Param(_) | ty::Param(_)

View file

@ -61,9 +61,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
Ok(vec![generator_args.tupled_upvars_ty(), generator_args.witness()]) Ok(vec![generator_args.tupled_upvars_ty(), generator_args.witness()])
} }
ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), ty::GeneratorWitness(def_id, args) => Ok(ecx
ty::GeneratorWitnessMIR(def_id, args) => Ok(ecx
.tcx() .tcx()
.generator_hidden_types(def_id) .generator_hidden_types(def_id)
.map(|bty| { .map(|bty| {
@ -127,7 +125,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
| ty::Ref(..) | ty::Ref(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Array(..) | ty::Array(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never
@ -204,9 +201,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
} }
} }
ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), ty::GeneratorWitness(def_id, args) => Ok(ecx
ty::GeneratorWitnessMIR(def_id, args) => Ok(ecx
.tcx() .tcx()
.generator_hidden_types(def_id) .generator_hidden_types(def_id)
.map(|bty| { .map(|bty| {
@ -282,8 +277,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
| ty::Ref(_, _, _) | ty::Ref(_, _, _)
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Alias(_, _) | ty::Alias(_, _)

View file

@ -330,8 +330,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Alias(_, _) | ty::Alias(_, _)

View file

@ -388,7 +388,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Foreign(..) => tcx.types.unit, | ty::Foreign(..) => tcx.types.unit,
@ -556,7 +555,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Foreign(..) | ty::Foreign(..)
| ty::Adt(_, _) | ty::Adt(_, _)

View file

@ -879,8 +879,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(_, _)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Adt(_, _) | ty::Adt(_, _)

View file

@ -827,9 +827,7 @@ where
// This should only be created when checking whether we have to check whether some // This should only be created when checking whether we have to check whether some
// auto trait impl applies. There will never be multiple impls, so we can just // auto trait impl applies. There will never be multiple impls, so we can just
// act as if it were a local type here. // act as if it were a local type here.
ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => { ty::GeneratorWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
}
ty::Alias(ty::Opaque, ..) => { ty::Alias(ty::Opaque, ..) => {
// This merits some explanation. // This merits some explanation.
// Normally, opaque types are not involved when performing // Normally, opaque types are not involved when performing

View file

@ -1847,7 +1847,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Generator(..) => Some(18), ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19), ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20), ty::GeneratorWitness(..) => Some(20),
ty::GeneratorWitnessMIR(..) => Some(21),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
} }
} }

View file

@ -30,10 +30,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTi
use rustc_middle::hir::map; use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, GenericArgs, InferTy, IsSuggestable, InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperFoldable, TypeVisitableExt, TypeckResults,
TypeVisitableExt, TypeckResults,
}; };
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
@ -58,15 +57,12 @@ pub enum GeneratorInteriorOrUpvar {
// This type provides a uniform interface to retrieve data on generators, whether it originated from // This type provides a uniform interface to retrieve data on generators, whether it originated from
// the local crate being compiled or from a foreign crate. // the local crate being compiled or from a foreign crate.
#[derive(Debug)] #[derive(Debug)]
pub enum GeneratorData<'tcx, 'a> { struct GeneratorData<'tcx, 'a>(&'a TypeckResults<'tcx>);
Local(&'a TypeckResults<'tcx>),
Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
}
impl<'tcx, 'a> GeneratorData<'tcx, 'a> { impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
// Try to get information about variables captured by the generator that matches a type we are /// Try to get information about variables captured by the generator that matches a type we are
// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
// meet an obligation /// meet an obligation
fn try_get_upvar_span<F>( fn try_get_upvar_span<F>(
&self, &self,
infer_context: &InferCtxt<'tcx>, infer_context: &InferCtxt<'tcx>,
@ -76,27 +72,21 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
where where
F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
{ {
match self { infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
GeneratorData::Local(typeck_results) => { upvars.iter().find_map(|(upvar_id, upvar)| {
infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| { let upvar_ty = self.0.node_type(*upvar_id);
upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
let upvar_ty = typeck_results.node_type(*upvar_id); ty_matches(ty::Binder::dummy(upvar_ty))
let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty); .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span))
ty_matches(ty::Binder::dummy(upvar_ty)) })
.then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span)) })
})
})
}
GeneratorData::Foreign(_) => None,
}
} }
// Try to get the span of a type being awaited on that matches the type we are looking with the /// Try to get the span of a type being awaited on that matches the type we are looking with the
// `ty_matches` function. We uses it to find awaited type which causes a failure to meet an /// `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
// obligation /// obligation
fn get_from_await_ty<F>( fn get_from_await_ty<F>(
&self, &self,
tcx: TyCtxt<'tcx>,
visitor: AwaitsVisitor, visitor: AwaitsVisitor,
hir: map::Map<'tcx>, hir: map::Map<'tcx>,
ty_matches: F, ty_matches: F,
@ -104,69 +94,12 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
where where
F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
{ {
match self { visitor
GeneratorData::Local(typeck_results) => visitor .awaits
.awaits .into_iter()
.into_iter() .map(|id| hir.expect_expr(id))
.map(|id| hir.expect_expr(id)) .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(&await_expr))))
.find(|await_expr| { .map(|expr| expr.span)
ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
})
.map(|expr| expr.span),
GeneratorData::Foreign(generator_diagnostic_data) => visitor
.awaits
.into_iter()
.map(|id| hir.expect_expr(id))
.find(|await_expr| {
ty_matches(ty::Binder::dummy(
generator_diagnostic_data
.adjustments
.get(&await_expr.hir_id.local_id)
.map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
.last()
.map_or_else::<Ty<'tcx>, _, _>(
|| {
generator_diagnostic_data
.nodes_types
.get(&await_expr.hir_id.local_id)
.cloned()
.unwrap_or_else(|| {
bug!(
"node_type: no type for node {}",
tcx.hir().node_to_string(await_expr.hir_id)
)
})
},
|adj| adj.target,
),
))
})
.map(|expr| expr.span),
}
}
/// Get the type, expression, span and optional scope span of all types
/// that are live across the yield of this generator
fn get_generator_interior_types(
&self,
) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> {
match self {
GeneratorData::Local(typeck_result) => {
typeck_result.generator_interior_types.as_deref()
}
GeneratorData::Foreign(generator_diagnostic_data) => {
generator_diagnostic_data.generator_interior_types.as_deref()
}
}
}
// Used to get the source of the data, note we don't have as much information for generators
// originated from foreign crates
fn is_foreign(&self) -> bool {
match self {
GeneratorData::Local(_) => false,
GeneratorData::Foreign(_) => true,
}
} }
} }
@ -316,7 +249,7 @@ pub trait TypeErrCtxtExt<'tcx> {
outer_generator: Option<DefId>, outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>, trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>, target_ty: Ty<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>, typeck_results: &ty::TypeckResults<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>, next_code: Option<&ObligationCauseCode<'tcx>>,
); );
@ -2240,11 +2173,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
); );
match *ty.kind() { match *ty.kind() {
ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => { ty::Generator(did, ..) | ty::GeneratorWitness(did, _) => {
generator = generator.or(Some(did)); generator = generator.or(Some(did));
outer_generator = Some(did); outer_generator = Some(did);
} }
ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations // By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself, // of a generator, the first non-generator item is now the tuple itself,
@ -2270,11 +2202,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
); );
match *ty.kind() { match *ty.kind() {
ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => { ty::Generator(did, ..) | ty::GeneratorWitness(did, ..) => {
generator = generator.or(Some(did)); generator = generator.or(Some(did));
outer_generator = Some(did); outer_generator = Some(did);
} }
ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations // By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself, // of a generator, the first non-generator item is now the tuple itself,
@ -2351,12 +2282,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// cycles. If we can't use resolved types because the generator comes from another crate, // cycles. If we can't use resolved types because the generator comes from another crate,
// we still provide a targeted error but without all the relevant spans. // we still provide a targeted error but without all the relevant spans.
let generator_data = match &self.typeck_results { let generator_data = match &self.typeck_results {
Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData::Local(&t), Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData(&t),
_ if generator_did.is_local() => { _ if generator_did.is_local() => {
GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())) GeneratorData(self.tcx.typeck(generator_did.expect_local()))
}
_ if let Some(generator_diag_data) = self.tcx.generator_diagnostic_data(generator_did) => {
GeneratorData::Foreign(generator_diag_data)
} }
_ => return false, _ => return false,
}; };
@ -2368,30 +2296,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut interior_or_upvar_span = None; let mut interior_or_upvar_span = None;
let from_awaited_ty = generator_data.get_from_await_ty(self.tcx, visitor, hir, ty_matches); let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
debug!(?from_awaited_ty); debug!(?from_awaited_ty);
// The generator interior types share the same binders // Avoid disclosing internal information to downstream crates.
if let Some(cause) = if generator_did.is_local()
generator_data.get_generator_interior_types().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
},
)
{
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
*span,
Some((*scope_span, *yield_span, *expr, from_awaited_ty)),
));
if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None));
}
} else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir
// Avoid disclosing internal information to downstream crates.
&& generator_did.is_local()
// Try to avoid cycles. // Try to avoid cycles.
&& !generator_within_in_progress_typeck && !generator_within_in_progress_typeck
&& let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did) && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
@ -2420,17 +2329,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
generator_data.try_get_upvar_span(&self, generator_did, ty_matches); generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
} }
if interior_or_upvar_span.is_none() && generator_data.is_foreign() { if interior_or_upvar_span.is_none() && !generator_did.is_local() {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None)); interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None));
} }
debug!(?interior_or_upvar_span); debug!(?interior_or_upvar_span);
if let Some(interior_or_upvar_span) = interior_or_upvar_span { if let Some(interior_or_upvar_span) = interior_or_upvar_span {
let is_async = self.tcx.generator_is_async(generator_did); let is_async = self.tcx.generator_is_async(generator_did);
let typeck_results = match generator_data { let typeck_results = generator_data.0;
GeneratorData::Local(typeck_results) => Some(typeck_results),
GeneratorData::Foreign(_) => None,
};
self.note_obligation_cause_for_async_await( self.note_obligation_cause_for_async_await(
err, err,
interior_or_upvar_span, interior_or_upvar_span,
@ -2459,7 +2365,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
outer_generator: Option<DefId>, outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>, trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>, target_ty: Ty<'tcx>,
typeck_results: Option<&ty::TypeckResults<'tcx>>, typeck_results: &ty::TypeckResults<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>, next_code: Option<&ObligationCauseCode<'tcx>>,
) { ) {
@ -2584,11 +2490,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
); );
} else { } else {
// Look at the last interior type to get a span for the `.await`. // Look at the last interior type to get a span for the `.await`.
debug!(
generator_interior_types = ?format_args!(
"{:#?}", typeck_results.as_ref().map(|t| &t.generator_interior_types)
),
);
explain_yield(interior_span, yield_span, scope_span); explain_yield(interior_span, yield_span, scope_span);
} }
@ -2608,14 +2509,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self` // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
// ``` // ```
// //
let is_region_borrow = if let Some(typeck_results) = typeck_results { let is_region_borrow = typeck_results
typeck_results .expr_adjustments(expr)
.expr_adjustments(expr) .iter()
.iter() .any(|adj| adj.is_region_borrow());
.any(|adj| adj.is_region_borrow())
} else {
false
};
// ```rust // ```rust
// struct Foo(*const u8); // struct Foo(*const u8);
@ -2628,16 +2525,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(), DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
_ => false, _ => false,
}; };
if let Some(typeck_results) = typeck_results { if (typeck_results.is_method_call(e) && is_region_borrow)
if (typeck_results.is_method_call(e) && is_region_borrow) || is_raw_borrow_inside_fn_like_call
|| is_raw_borrow_inside_fn_like_call {
{ err.span_help(
err.span_help( parent_span,
parent_span, "consider moving this into a `let` \
"consider moving this into a `let` \
binding to create a shorter lived borrow", binding to create a shorter lived borrow",
); );
}
} }
} }
} }
@ -3090,20 +2985,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} }
err.span_note(self.tcx.def_span(def_id), msg) err.span_note(self.tcx.def_span(def_id), msg)
} }
ty::GeneratorWitness(bound_tys) => { ty::GeneratorWitness(def_id, args) => {
use std::fmt::Write;
// FIXME: this is kind of an unusual format for rustc, can we make it more clear?
// Maybe we should just remove this note altogether?
// FIXME: only print types which don't meet the trait requirement
let mut msg =
"required because it captures the following types: ".to_owned();
for ty in bound_tys.skip_binder() {
with_forced_trimmed_paths!(write!(msg, "`{ty}`, ").unwrap());
}
err.note(msg.trim_end_matches(", ").to_string())
}
ty::GeneratorWitnessMIR(def_id, args) => {
use std::fmt::Write; use std::fmt::Write;
// FIXME: this is kind of an unusual format for rustc, can we make it more clear? // FIXME: this is kind of an unusual format for rustc, can we make it more clear?

View file

@ -1813,7 +1813,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(..) | ty::Tuple(..)
// Integers and floats always have `u8` as their discriminant. // Integers and floats always have `u8` as their discriminant.
@ -1863,7 +1862,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
// Extern types have unit metadata, according to RFC 2850 // Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_) | ty::Foreign(_)

View file

@ -36,7 +36,6 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::Char | ty::Char
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::RawPtr(_) | ty::RawPtr(_)
| ty::Ref(..) | ty::Ref(..)
| ty::Str | ty::Str
@ -218,8 +217,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
| ty::Ref(..) | ty::Ref(..)
| ty::FnDef(..) | ty::FnDef(..)
| ty::FnPtr(_) | ty::FnPtr(_)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..) => {
| ty::GeneratorWitnessMIR(..) => {
// these types never have a destructor // these types never have a destructor
} }

View file

@ -436,8 +436,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Ref(_, _, _) | ty::Ref(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(_, _)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::Error(_) => return true, | ty::Error(_) => return true,
@ -569,8 +568,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Generator(..) | ty::Generator(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..) => {
| ty::GeneratorWitnessMIR(..) => {
// Only consider auto impls if there are no manual impls for the root of `self_ty`. // Only consider auto impls if there are no manual impls for the root of `self_ty`.
// //
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
@ -946,8 +944,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::Tuple(_) | ty::Tuple(_)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..) => {
| ty::GeneratorWitnessMIR(..) => {
// These are built-in, and cannot have a custom `impl const Destruct`. // These are built-in, and cannot have a custom `impl const Destruct`.
candidates.vec.push(ConstDestructCandidate(None)); candidates.vec.push(ConstDestructCandidate(None));
} }
@ -1020,8 +1017,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Dynamic(_, _, _) | ty::Dynamic(_, _, _)
| ty::Closure(_, _) | ty::Closure(_, _)
| ty::Generator(_, _, _) | ty::Generator(_, _, _)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Alias(..) | ty::Alias(..)
| ty::Param(_) | ty::Param(_)
@ -1083,7 +1079,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Tuple(..) | ty::Tuple(..)
| ty::Alias(..) | ty::Alias(..)

View file

@ -1238,10 +1238,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let generator = args.as_generator(); let generator = args.as_generator();
stack.extend([generator.tupled_upvars_ty(), generator.witness()]); stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
} }
ty::GeneratorWitness(tys) => { ty::GeneratorWitness(def_id, args) => {
stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
}
ty::GeneratorWitnessMIR(def_id, args) => {
let tcx = self.tcx(); let tcx = self.tcx();
stack.extend(tcx.generator_hidden_types(def_id).map(|bty| { stack.extend(tcx.generator_hidden_types(def_id).map(|bty| {
let ty = bty.instantiate(tcx, args); let ty = bty.instantiate(tcx, args);

View file

@ -2131,7 +2131,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Ref(..) | ty::Ref(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Array(..) | ty::Array(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never
@ -2230,22 +2229,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
} }
} }
ty::GeneratorWitness(binder) => { ty::GeneratorWitness(def_id, ref args) => {
let witness_tys = binder.skip_binder();
for witness_ty in witness_tys.iter() {
let resolved = self.infcx.shallow_resolve(witness_ty);
if resolved.is_ty_var() {
return Ambiguous;
}
}
// (*) binder moved here
let all_vars = self.tcx().mk_bound_variable_kinds_from_iter(
obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()),
);
Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
}
ty::GeneratorWitnessMIR(def_id, ref args) => {
let hidden_types = bind_generator_hidden_types_above( let hidden_types = bind_generator_hidden_types_above(
self.infcx, self.infcx,
def_id, def_id,
@ -2350,12 +2334,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
} }
ty::GeneratorWitness(types) => { ty::GeneratorWitness(def_id, ref args) => {
debug_assert!(!types.has_escaping_bound_vars());
types.map_bound(|types| types.to_vec())
}
ty::GeneratorWitnessMIR(def_id, ref args) => {
bind_generator_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) bind_generator_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
} }
@ -3115,25 +3094,25 @@ fn bind_generator_hidden_types_above<'tcx>(
.generator_hidden_types(def_id) .generator_hidden_types(def_id)
// Deduplicate tys to avoid repeated work. // Deduplicate tys to avoid repeated work.
.filter(|bty| seen_tys.insert(*bty)) .filter(|bty| seen_tys.insert(*bty))
.map(|bty| { .map(|mut bty| {
let mut ty = bty.instantiate(tcx, args);
// Only remap erased regions if we use them. // Only remap erased regions if we use them.
if considering_regions { if considering_regions {
ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() { bty = bty.map_bound(|ty| {
ty::ReErased => { tcx.fold_regions(ty, |r, current_depth| match r.kind() {
let br = ty::BoundRegion { ty::ReErased => {
var: ty::BoundVar::from_u32(counter), let br = ty::BoundRegion {
kind: ty::BrAnon(None), var: ty::BoundVar::from_u32(counter),
}; kind: ty::BrAnon(None),
counter += 1; };
ty::Region::new_late_bound(tcx, current_depth, br) counter += 1;
} ty::Region::new_late_bound(tcx, current_depth, br)
r => bug!("unexpected region: {r:?}"), }
r => bug!("unexpected region: {r:?}"),
})
}) })
} }
ty bty.instantiate(tcx, args)
}) })
.collect(); .collect();
if considering_regions { if considering_regions {

View file

@ -79,7 +79,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
ty::Closure(..) => { ty::Closure(..) => {
return ControlFlow::Break(ty); return ControlFlow::Break(ty);
} }
ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => { ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(ty); return ControlFlow::Break(ty);
} }
ty::FnDef(..) => { ty::FnDef(..) => {

View file

@ -609,7 +609,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
| ty::Error(_) | ty::Error(_)
| ty::Str | ty::Str
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Param(_) | ty::Param(_)
| ty::Bound(..) | ty::Bound(..)

View file

@ -577,11 +577,7 @@ fn layout_of_uncached<'tcx>(
return Err(error(cx, LayoutError::Unknown(ty))); return Err(error(cx, LayoutError::Unknown(ty)));
} }
ty::Bound(..) ty::Bound(..) | ty::GeneratorWitness(..) | ty::Infer(_) | ty::Error(_) => {
| ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(_)
| ty::Error(_) => {
bug!("Layout::compute: unexpected type `{}`", ty) bug!("Layout::compute: unexpected type `{}`", ty)
} }

View file

@ -7,7 +7,7 @@ use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
use rustc_session::Limit; use rustc_session::Limit;
use rustc_span::{sym, DUMMY_SP}; use rustc_span::sym;
use crate::errors::NeedsDropOverflow; use crate::errors::NeedsDropOverflow;
@ -133,7 +133,7 @@ where
// The information required to determine whether a generator has drop is // The information required to determine whether a generator has drop is
// computed on MIR, while this very method is used to build MIR. // computed on MIR, while this very method is used to build MIR.
// To avoid cycles, we consider that generators always require drop. // To avoid cycles, we consider that generators always require drop.
ty::Generator(..) if tcx.sess.opts.unstable_opts.drop_tracking_mir => { ty::Generator(..) => {
return Some(Err(AlwaysRequiresDrop)); return Some(Err(AlwaysRequiresDrop));
} }
@ -145,29 +145,6 @@ where
} }
} }
ty::Generator(def_id, args, _) => {
let args = args.as_generator();
for upvar in args.upvar_tys() {
queue_type(self, upvar);
}
let witness = args.witness();
let interior_tys = match witness.kind() {
&ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys),
_ => {
tcx.sess.delay_span_bug(
tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP),
format!("unexpected generator witness type {witness:?}"),
);
return Some(Err(AlwaysRequiresDrop));
}
};
for interior_ty in interior_tys {
queue_type(self, interior_ty);
}
}
// Check for a `Drop` impl and whether this is a union or // Check for a `Drop` impl and whether this is a union or
// `ManuallyDrop`. If it's a struct or enum without a `Drop` // `ManuallyDrop`. If it's a struct or enum without a `Drop`
// impl then check whether the field types need `Drop`. // impl then check whether the field types need `Drop`.
@ -215,7 +192,6 @@ where
| ty::Tuple(_) | ty::Tuple(_)
| ty::Bound(..) | ty::Bound(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Never | ty::Never
| ty::Infer(_) | ty::Infer(_)
| ty::Error(_) => { | ty::Error(_) => {

View file

@ -21,13 +21,7 @@ fn sized_constraint_for_ty<'tcx>(
Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
| FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
Str Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
| Dynamic(..)
| Slice(_)
| Foreign(..)
| Error(_)
| GeneratorWitness(..)
| GeneratorWitnessMIR(..) => {
// these are never sized - return the target type // these are never sized - return the target type
vec![ty] vec![ty]
} }

View file

@ -143,31 +143,6 @@ pub enum TyKind<I: Interner> {
/// `GeneratorArgs`. /// `GeneratorArgs`.
Generator(I::DefId, I::GenericArgsRef, I::Movability), Generator(I::DefId, I::GenericArgsRef, I::Movability),
/// A type representing the types stored inside a generator.
/// This should only appear as part of the `GeneratorArgs`.
///
/// Note that the captured variables for generators are stored separately
/// using a tuple in the same way as for closures.
///
/// Unlike upvars, the witness can reference lifetimes from
/// inside of the generator itself. To deal with them in
/// the type of the generator, we convert them to higher ranked
/// lifetimes bound by the witness itself.
///
/// Looking at the following example, the witness for this generator
/// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
///
/// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
/// #![feature(generators)]
/// |a| {
/// let x = &vec![3];
/// yield a;
/// yield x[0];
/// }
/// # ;
/// ```
GeneratorWitness(I::BinderListTy),
/// A type representing the types stored inside a generator. /// A type representing the types stored inside a generator.
/// This should only appear as part of the `GeneratorArgs`. /// This should only appear as part of the `GeneratorArgs`.
/// ///
@ -192,7 +167,7 @@ pub enum TyKind<I: Interner> {
/// } /// }
/// # ; /// # ;
/// ``` /// ```
GeneratorWitnessMIR(I::DefId, I::GenericArgsRef), GeneratorWitness(I::DefId, I::GenericArgsRef),
/// The never type `!`. /// The never type `!`.
Never, Never,
@ -278,7 +253,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
Dynamic(..) => 14, Dynamic(..) => 14,
Closure(_, _) => 15, Closure(_, _) => 15,
Generator(_, _, _) => 16, Generator(_, _, _) => 16,
GeneratorWitness(_) => 17, GeneratorWitness(_, _) => 17,
Never => 18, Never => 18,
Tuple(_) => 19, Tuple(_) => 19,
Alias(_, _) => 20, Alias(_, _) => 20,
@ -287,7 +262,6 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
Placeholder(_) => 23, Placeholder(_) => 23,
Infer(_) => 24, Infer(_) => 24,
Error(_) => 25, Error(_) => 25,
GeneratorWitnessMIR(_, _) => 26,
} }
} }
@ -312,8 +286,7 @@ impl<I: Interner> Clone for TyKind<I> {
Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr), Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr),
Closure(d, s) => Closure(d.clone(), s.clone()), Closure(d, s) => Closure(d.clone(), s.clone()),
Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
GeneratorWitness(g) => GeneratorWitness(g.clone()), GeneratorWitness(d, s) => GeneratorWitness(d.clone(), s.clone()),
GeneratorWitnessMIR(d, s) => GeneratorWitnessMIR(d.clone(), s.clone()),
Never => Never, Never => Never,
Tuple(t) => Tuple(t.clone()), Tuple(t) => Tuple(t.clone()),
Alias(k, p) => Alias(*k, p.clone()), Alias(k, p) => Alias(*k, p.clone()),
@ -355,10 +328,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
(Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
a_d == b_d && a_s == b_s && a_m == b_m a_d == b_d && a_s == b_s && a_m == b_m
} }
(GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, (GeneratorWitness(a_d, a_s), GeneratorWitness(b_d, b_s)) => a_d == b_d && a_s == b_s,
(GeneratorWitnessMIR(a_d, a_s), GeneratorWitnessMIR(b_d, b_s)) => {
a_d == b_d && a_s == b_s
}
(Tuple(a_t), Tuple(b_t)) => a_t == b_t, (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
(Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
(Param(a_p), Param(b_p)) => a_p == b_p, (Param(a_p), Param(b_p)) => a_p == b_p,
@ -415,10 +385,9 @@ impl<I: Interner> Ord for TyKind<I> {
(Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => { (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m))) a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m)))
} }
(GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g),
( (
GeneratorWitnessMIR(a_d, a_s), GeneratorWitness(a_d, a_s),
GeneratorWitnessMIR(b_d, b_s), GeneratorWitness(b_d, b_s),
) => match Ord::cmp(a_d, b_d) { ) => match Ord::cmp(a_d, b_d) {
Ordering::Equal => Ord::cmp(a_s, b_s), Ordering::Equal => Ord::cmp(a_s, b_s),
cmp => cmp, cmp => cmp,
@ -483,8 +452,7 @@ impl<I: Interner> hash::Hash for TyKind<I> {
s.hash(state); s.hash(state);
m.hash(state) m.hash(state)
} }
GeneratorWitness(g) => g.hash(state), GeneratorWitness(d, s) => {
GeneratorWitnessMIR(d, s) => {
d.hash(state); d.hash(state);
s.hash(state); s.hash(state);
} }
@ -558,9 +526,8 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
}, },
Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)), Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)),
Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, &this.wrap(s), m), Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, &this.wrap(s), m),
GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", &this.wrap(g)), GeneratorWitness(d, s) => {
GeneratorWitnessMIR(d, s) => { f.debug_tuple_field2_finish("GeneratorWitness", d, &this.wrap(s))
f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, &this.wrap(s))
} }
Never => write!(f, "!"), Never => write!(f, "!"),
Tuple(t) => { Tuple(t) => {
@ -682,10 +649,7 @@ where
args.encode(e); args.encode(e);
m.encode(e); m.encode(e);
}), }),
GeneratorWitness(b) => e.emit_enum_variant(disc, |e| { GeneratorWitness(def_id, args) => e.emit_enum_variant(disc, |e| {
b.encode(e);
}),
GeneratorWitnessMIR(def_id, args) => e.emit_enum_variant(disc, |e| {
def_id.encode(e); def_id.encode(e);
args.encode(e); args.encode(e);
}), }),
@ -762,7 +726,7 @@ where
14 => Dynamic(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 14 => Dynamic(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)),
15 => Closure(Decodable::decode(d), Decodable::decode(d)), 15 => Closure(Decodable::decode(d), Decodable::decode(d)),
16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)),
17 => GeneratorWitness(Decodable::decode(d)), 17 => GeneratorWitness(Decodable::decode(d), Decodable::decode(d)),
18 => Never, 18 => Never,
19 => Tuple(Decodable::decode(d)), 19 => Tuple(Decodable::decode(d)),
20 => Alias(Decodable::decode(d), Decodable::decode(d)), 20 => Alias(Decodable::decode(d), Decodable::decode(d)),
@ -771,12 +735,11 @@ where
23 => Placeholder(Decodable::decode(d)), 23 => Placeholder(Decodable::decode(d)),
24 => Infer(Decodable::decode(d)), 24 => Infer(Decodable::decode(d)),
25 => Error(Decodable::decode(d)), 25 => Error(Decodable::decode(d)),
26 => GeneratorWitnessMIR(Decodable::decode(d), Decodable::decode(d)),
_ => panic!( _ => panic!(
"{}", "{}",
format!( format!(
"invalid enum variant tag while decoding `{}`, expected 0..{}", "invalid enum variant tag while decoding `{}`, expected 0..{}",
"TyKind", 27, "TyKind", 26,
) )
), ),
} }
@ -870,10 +833,7 @@ where
args.hash_stable(__hcx, __hasher); args.hash_stable(__hcx, __hasher);
m.hash_stable(__hcx, __hasher); m.hash_stable(__hcx, __hasher);
} }
GeneratorWitness(b) => { GeneratorWitness(def_id, args) => {
b.hash_stable(__hcx, __hasher);
}
GeneratorWitnessMIR(def_id, args) => {
def_id.hash_stable(__hcx, __hasher); def_id.hash_stable(__hcx, __hasher);
args.hash_stable(__hcx, __hasher); args.hash_stable(__hcx, __hasher);
} }

View file

@ -2288,7 +2288,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Bound(..) => panic!("Bound"), ty::Bound(..) => panic!("Bound"),
ty::Placeholder(..) => panic!("Placeholder"), ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::GeneratorWitnessMIR(..) => panic!("GeneratorWitnessMIR"),
ty::Infer(..) => panic!("Infer"), ty::Infer(..) => panic!("Infer"),
ty::Error(_) => rustc_errors::FatalError.raise(), ty::Error(_) => rustc_errors::FatalError.raise(),
} }

View file

@ -522,8 +522,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty::Alias(..) ty::Alias(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(_) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Dynamic(..) | ty::Dynamic(..)
| ty::Param(_) | ty::Param(_)
| ty::Bound(..) | ty::Bound(..)

View file

@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths}; use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_hir::{AsyncGeneratorKind, Body, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause; use rustc_middle::mir::GeneratorLayout;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
@ -197,28 +197,35 @@ impl LateLintPass<'_> for AwaitHolding {
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
use AsyncGeneratorKind::{Block, Closure, Fn}; use AsyncGeneratorKind::{Block, Closure, Fn};
if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind { if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
let body_id = BodyId { let def_id = cx.tcx.hir().body_owner_def_id(body.id());
hir_id: body.value.hir_id, if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) {
}; self.check_interior_types(cx, generator_layout);
let typeck_results = cx.tcx.typeck_body(body_id); }
self.check_interior_types(
cx,
typeck_results.generator_interior_types.as_ref().skip_binder(),
body.value.span,
);
} }
} }
} }
impl AwaitHolding { impl AwaitHolding {
fn check_interior_types(&self, cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) { fn check_interior_types(&self, cx: &LateContext<'_>, generator: &GeneratorLayout<'_>) {
for ty_cause in ty_causes { for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() {
if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
let await_points = || {
generator
.variant_source_info
.iter_enumerated()
.filter_map(|(variant, source_info)| {
generator.variant_fields[variant]
.raw
.contains(&ty_index)
.then_some(source_info.span)
})
.collect::<Vec<_>>()
};
if is_mutex_guard(cx, adt.did()) { if is_mutex_guard(cx, adt.did()) {
span_lint_and_then( span_lint_and_then(
cx, cx,
AWAIT_HOLDING_LOCK, AWAIT_HOLDING_LOCK,
ty_cause.span, ty_cause.source_info.span,
"this `MutexGuard` is held across an `await` point", "this `MutexGuard` is held across an `await` point",
|diag| { |diag| {
diag.help( diag.help(
@ -226,7 +233,7 @@ impl AwaitHolding {
`MutexGuard` is dropped before calling await", `MutexGuard` is dropped before calling await",
); );
diag.span_note( diag.span_note(
ty_cause.scope_span.unwrap_or(span), await_points(),
"these are all the `await` points this lock is held through", "these are all the `await` points this lock is held through",
); );
}, },
@ -235,18 +242,18 @@ impl AwaitHolding {
span_lint_and_then( span_lint_and_then(
cx, cx,
AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_REFCELL_REF,
ty_cause.span, ty_cause.source_info.span,
"this `RefCell` reference is held across an `await` point", "this `RefCell` reference is held across an `await` point",
|diag| { |diag| {
diag.help("ensure the reference is dropped before calling `await`"); diag.help("ensure the reference is dropped before calling `await`");
diag.span_note( diag.span_note(
ty_cause.scope_span.unwrap_or(span), await_points(),
"these are all the `await` points this reference is held through", "these are all the `await` points this reference is held through",
); );
}, },
); );
} else if let Some(disallowed) = self.def_ids.get(&adt.did()) { } else if let Some(disallowed) = self.def_ids.get(&adt.did()) {
emit_invalid_type(cx, ty_cause.span, disallowed); emit_invalid_type(cx, ty_cause.source_info.span, disallowed);
} }
} }
} }

View file

@ -940,7 +940,6 @@ impl TyCoercionStability {
| ty::FnDef(..) | ty::FnDef(..)
| ty::Generator(..) | ty::Generator(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Closure(..) | ty::Closure(..)
| ty::Never | ty::Never
| ty::Tuple(_) | ty::Tuple(_)

View file

@ -7,8 +7,10 @@ async fn bad() -> u32 {
} }
async fn bad_reason() -> u32 { async fn bad_reason() -> u32 {
let _x = Ipv4Addr::new(127, 0, 0, 1); let x = Ipv4Addr::new(127, 0, 0, 1);
baz().await let y = baz().await;
let _x = x;
y
} }
async fn good() -> u32 { async fn good() -> u32 {

View file

@ -11,11 +11,11 @@ LL | let _x = String::from("hello");
error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
--> $DIR/await_holding_invalid_type.rs:10:9 --> $DIR/await_holding_invalid_type.rs:10:9
| |
LL | let _x = Ipv4Addr::new(127, 0, 0, 1); LL | let x = Ipv4Addr::new(127, 0, 0, 1);
| ^^ | ^
error: `std::string::String` may not be held across an `await` point per `clippy.toml` error: `std::string::String` may not be held across an `await` point per `clippy.toml`
--> $DIR/await_holding_invalid_type.rs:31:13 --> $DIR/await_holding_invalid_type.rs:33:13
| |
LL | let _x = String::from("hi!"); LL | let _x = String::from("hi!");
| ^^ | ^^

View file

@ -6,13 +6,10 @@ LL | let guard = x.lock().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:9:9 --> $DIR/await_holding_lock.rs:11:15
| |
LL | / let guard = x.lock().unwrap(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
= note: `-D clippy::await-holding-lock` implied by `-D warnings` = note: `-D clippy::await-holding-lock` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]`
@ -24,13 +21,10 @@ LL | let guard = x.read().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:25:9 --> $DIR/await_holding_lock.rs:27:15
| |
LL | / let guard = x.read().unwrap(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:31:13 --> $DIR/await_holding_lock.rs:31:13
@ -40,13 +34,10 @@ LL | let mut guard = x.write().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:31:9 --> $DIR/await_holding_lock.rs:33:15
| |
LL | / let mut guard = x.write().unwrap(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:53:13 --> $DIR/await_holding_lock.rs:53:13
@ -56,16 +47,13 @@ LL | let guard = x.lock().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:53:9 --> $DIR/await_holding_lock.rs:56:28
| |
LL | / let guard = x.lock().unwrap(); LL | let second = baz().await;
LL | | | ^^^^^
LL | | LL |
LL | | let second = baz().await; LL | let third = baz().await;
... | | ^^^^^
LL | | first + second + third
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:67:17 --> $DIR/await_holding_lock.rs:67:17
@ -75,13 +63,10 @@ LL | let guard = x.lock().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:67:13 --> $DIR/await_holding_lock.rs:69:19
| |
LL | / let guard = x.lock().unwrap(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | };
| |_________^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:80:17 --> $DIR/await_holding_lock.rs:80:17
@ -91,13 +76,10 @@ LL | let guard = x.lock().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:80:13 --> $DIR/await_holding_lock.rs:82:19
| |
LL | / let guard = x.lock().unwrap(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_________^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:93:13 --> $DIR/await_holding_lock.rs:93:13
@ -107,13 +89,10 @@ LL | let guard = x.lock();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:93:9 --> $DIR/await_holding_lock.rs:95:15
| |
LL | / let guard = x.lock(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:109:13 --> $DIR/await_holding_lock.rs:109:13
@ -123,13 +102,10 @@ LL | let guard = x.read();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:109:9 --> $DIR/await_holding_lock.rs:111:15
| |
LL | / let guard = x.read(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:115:13 --> $DIR/await_holding_lock.rs:115:13
@ -139,13 +115,10 @@ LL | let mut guard = x.write();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:115:9 --> $DIR/await_holding_lock.rs:117:15
| |
LL | / let mut guard = x.write(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:137:13 --> $DIR/await_holding_lock.rs:137:13
@ -155,16 +128,13 @@ LL | let guard = x.lock();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:137:9 --> $DIR/await_holding_lock.rs:140:28
| |
LL | / let guard = x.lock(); LL | let second = baz().await;
LL | | | ^^^^^
LL | | LL |
LL | | let second = baz().await; LL | let third = baz().await;
... | | ^^^^^
LL | | first + second + third
LL | | }
| |_____^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:151:17 --> $DIR/await_holding_lock.rs:151:17
@ -174,13 +144,10 @@ LL | let guard = x.lock();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:151:13 --> $DIR/await_holding_lock.rs:153:19
| |
LL | / let guard = x.lock(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | };
| |_________^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:164:17 --> $DIR/await_holding_lock.rs:164:17
@ -190,13 +157,10 @@ LL | let guard = x.lock();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:164:13 --> $DIR/await_holding_lock.rs:166:19
| |
LL | / let guard = x.lock(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_________^
error: this `MutexGuard` is held across an `await` point error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:185:9 --> $DIR/await_holding_lock.rs:185:9
@ -206,15 +170,10 @@ LL | let mut guard = x.lock().unwrap();
| |
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:185:5 --> $DIR/await_holding_lock.rs:189:11
| |
LL | / let mut guard = x.lock().unwrap(); LL | baz().await;
LL | | | ^^^^^
LL | | *guard += 1;
LL | | drop(guard);
LL | | baz().await;
LL | | }
| |_^
error: aborting due to 13 previous errors error: aborting due to 13 previous errors

View file

@ -6,13 +6,10 @@ LL | let b = x.borrow();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:6:5 --> $DIR/await_holding_refcell_ref.rs:8:11
| |
LL | / let b = x.borrow(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_^
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]`
@ -24,13 +21,10 @@ LL | let b = x.borrow_mut();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:12:5 --> $DIR/await_holding_refcell_ref.rs:14:11
| |
LL | / let b = x.borrow_mut(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_^
error: this `RefCell` reference is held across an `await` point error: this `RefCell` reference is held across an `await` point
--> $DIR/await_holding_refcell_ref.rs:34:9 --> $DIR/await_holding_refcell_ref.rs:34:9
@ -40,16 +34,13 @@ LL | let b = x.borrow_mut();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:34:5 --> $DIR/await_holding_refcell_ref.rs:37:24
| |
LL | / let b = x.borrow_mut(); LL | let second = baz().await;
LL | | | ^^^^^
LL | | LL |
LL | | let second = baz().await; LL | let third = baz().await;
... | | ^^^^^
LL | | first + second + third
LL | | }
| |_^
error: this `RefCell` reference is held across an `await` point error: this `RefCell` reference is held across an `await` point
--> $DIR/await_holding_refcell_ref.rs:47:9 --> $DIR/await_holding_refcell_ref.rs:47:9
@ -59,16 +50,10 @@ LL | let b = x.borrow_mut();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:47:5 --> $DIR/await_holding_refcell_ref.rs:50:24
| |
LL | / let b = x.borrow_mut(); LL | let second = baz().await;
LL | | | ^^^^^
LL | |
LL | | let second = baz().await;
... |
LL | | first + second + third
LL | | }
| |_^
error: this `RefCell` reference is held across an `await` point error: this `RefCell` reference is held across an `await` point
--> $DIR/await_holding_refcell_ref.rs:63:13 --> $DIR/await_holding_refcell_ref.rs:63:13
@ -78,13 +63,10 @@ LL | let b = x.borrow_mut();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:63:9 --> $DIR/await_holding_refcell_ref.rs:65:15
| |
LL | / let b = x.borrow_mut(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | };
| |_____^
error: this `RefCell` reference is held across an `await` point error: this `RefCell` reference is held across an `await` point
--> $DIR/await_holding_refcell_ref.rs:76:13 --> $DIR/await_holding_refcell_ref.rs:76:13
@ -94,13 +76,10 @@ LL | let b = x.borrow_mut();
| |
= help: ensure the reference is dropped before calling `await` = help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:76:9 --> $DIR/await_holding_refcell_ref.rs:78:15
| |
LL | / let b = x.borrow_mut(); LL | baz().await
LL | | | ^^^^^
LL | | baz().await
LL | | }
| |_____^
error: aborting due to 6 previous errors error: aborting due to 6 previous errors

View file

@ -59,6 +59,7 @@ where
{ {
let rt = &t; let rt = &t;
async { true }.await; async { true }.await;
let _ = rt;
t t
} }

View file

@ -12,19 +12,12 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
LL | LL |
LL | async { true }.await LL | async { true }.await
| ^^^^^ await occurs here, with `rc` maybe used later | ^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: future is not `Send` as this value is used across an await note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> $DIR/future_not_send.rs:9:20 --> $DIR/future_not_send.rs:7:39
| |
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ---- has type `&std::cell::Cell<usize>` which is not `Send` | ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
LL |
LL | async { true }.await
| ^^^^^ await occurs here, with `cell` maybe used later
LL | }
| - `cell` is later dropped here
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
= note: `-D clippy::future-not-send` implied by `-D warnings` = note: `-D clippy::future-not-send` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]`
@ -43,8 +36,6 @@ LL | pub async fn public_future(rc: Rc<[u8]>) {
LL | LL |
LL | async { true }.await; LL | async { true }.await;
| ^^^^^ await occurs here, with `rc` maybe used later | ^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
@ -93,9 +84,6 @@ LL | async fn private_future(&self) -> usize {
LL | LL |
LL | async { true }.await; LL | async { true }.await;
| ^^^^^ await occurs here, with `&self` maybe used later | ^^^^^ await occurs here, with `&self` maybe used later
LL | self.rc.len()
LL | }
| - `&self` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
@ -104,16 +92,11 @@ error: future cannot be sent between threads safely
LL | pub async fn public_future(&self) { LL | pub async fn public_future(&self) {
| ^ future returned by `public_future` is not `Send` | ^ future returned by `public_future` is not `Send`
| |
note: future is not `Send` as this value is used across an await note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> $DIR/future_not_send.rs:46:31 --> $DIR/future_not_send.rs:44:32
| |
LL | pub async fn public_future(&self) { LL | pub async fn public_future(&self) {
| ----- has type `&Dummy` which is not `Send` | ^^^^^ has type `&Dummy` which is not `Send`, because `Dummy` is not `Sync`
LL |
LL | self.private_future().await;
| ^^^^^ await occurs here, with `&self` maybe used later
LL | }
| - `&self` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
@ -129,19 +112,16 @@ LL | let rt = &t;
| -- has type `&T` which is not `Send` | -- has type `&T` which is not `Send`
LL | async { true }.await; LL | async { true }.await;
| ^^^^^ await occurs here, with `rt` maybe used later | ^^^^^ await occurs here, with `rt` maybe used later
LL | t
LL | }
| - `rt` is later dropped here
= note: `T` doesn't implement `std::marker::Sync` = note: `T` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely error: future cannot be sent between threads safely
--> $DIR/future_not_send.rs:72:34 --> $DIR/future_not_send.rs:73:34
| |
LL | async fn unclear_future<T>(t: T) {} LL | async fn unclear_future<T>(t: T) {}
| ^ future returned by `unclear_future` is not `Send` | ^ future returned by `unclear_future` is not `Send`
| |
note: captured value is not `Send` note: captured value is not `Send`
--> $DIR/future_not_send.rs:72:28 --> $DIR/future_not_send.rs:73:28
| |
LL | async fn unclear_future<T>(t: T) {} LL | async fn unclear_future<T>(t: T) {}
| ^ has type `T` which is not `Send` | ^ has type `T` which is not `Send`

View file

@ -5,12 +5,14 @@
// ignore-tidy-linelength // ignore-tidy-linelength
// compile-flags: -C debuginfo=2 --edition=2018 // compile-flags: -C debuginfo=2 --edition=2018
async fn foo() {} #![crate_type = "lib"]
async fn async_fn_test() { pub async fn async_fn_test() {
foo().await; foo().await;
} }
pub async fn foo() {}
// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]], // NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]],
// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>", // MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>",
// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test", // NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test",
@ -19,7 +21,3 @@ async fn async_fn_test() {
// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], // NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>", // MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", // NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
fn main() {
let _fn = async_fn_test();
}

View file

@ -18,22 +18,30 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:11:14: 11:16}>
bb0: { bb0: {
_5 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:11:14: 11:16}))); _5 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:11:14: 11:16})));
switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; switchInt(move _5) -> [0: bb1, 1: bb4, otherwise: bb5];
} }
bb1: { bb1: {
_4 = move _2; _4 = move _2;
_3 = const (); _3 = const ();
goto -> bb3;
}
bb2: {
_0 = Poll::<()>::Ready(move _3); _0 = Poll::<()>::Ready(move _3);
discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:11:14: 11:16}))) = 1; discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:11:14: 11:16}))) = 1;
return; return;
} }
bb2: { bb3: {
assert(const false, "`async fn` resumed after completion") -> [success: bb2, unwind unreachable]; goto -> bb2;
} }
bb3: { bb4: {
assert(const false, "`async fn` resumed after completion") -> [success: bb4, unwind unreachable];
}
bb5: {
unreachable; unreachable;
} }
} }

View file

@ -104,7 +104,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
bb0: { bb0: {
_39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:14:18: 17:2}))); _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:14:18: 17:2})));
switchInt(move _39) -> [0: bb1, 1: bb28, 3: bb26, 4: bb27, otherwise: bb29]; switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb30];
} }
bb1: { bb1: {
@ -187,7 +187,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
StorageDead(_12); StorageDead(_12);
StorageDead(_9); StorageDead(_9);
StorageDead(_8); StorageDead(_8);
goto -> bb12; drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:14:18: 17:2})) as variant#3).0: impl std::future::Future<Output = ()>)) -> [return: bb12, unwind unreachable];
} }
bb11: { bb11: {
@ -279,7 +279,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
StorageDead(_28); StorageDead(_28);
StorageDead(_25); StorageDead(_25);
StorageDead(_24); StorageDead(_24);
goto -> bb23; drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:14:18: 17:2})) as variant#4).0: impl std::future::Future<Output = ()>)) -> [return: bb23, unwind unreachable];
} }
bb22: { bb22: {
@ -297,7 +297,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
bb24: { bb24: {
StorageDead(_21); StorageDead(_21);
goto -> bb25; goto -> bb26;
} }
bb25: { bb25: {
@ -307,6 +307,10 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
} }
bb26: { bb26: {
goto -> bb25;
}
bb27: {
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
StorageLive(_19); StorageLive(_19);
@ -315,7 +319,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
goto -> bb11; goto -> bb11;
} }
bb27: { bb28: {
StorageLive(_21); StorageLive(_21);
StorageLive(_35); StorageLive(_35);
StorageLive(_36); StorageLive(_36);
@ -323,11 +327,11 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:14:18: 17:2}>,
goto -> bb22; goto -> bb22;
} }
bb28: { bb29: {
assert(const false, "`async fn` resumed after completion") -> [success: bb28, unwind unreachable]; assert(const false, "`async fn` resumed after completion") -> [success: bb29, unwind unreachable];
} }
bb29: { bb30: {
unreachable; unreachable;
} }
} }

View file

@ -36,62 +36,67 @@
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
- _4 = g() -> [return: bb1, unwind unreachable]; - _4 = g() -> [return: bb1, unwind unreachable];
- }
-
- bb1: {
+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; + _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
_3 = &mut _4; + _3 = &mut _4;
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind unreachable];
- }
-
- bb2: {
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
StorageDead(_3); + StorageDead(_3);
- _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable];
+ StorageLive(_5); + StorageLive(_5);
+ _5 = const false; + _5 = const false;
+ _6 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); + _6 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
+ _7 = discriminant((*_6)); + _7 = discriminant((*_6));
+ switchInt(move _7) -> [0: bb2, 1: bb6, 3: bb7, otherwise: bb8]; + switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9];
} }
- bb3: { bb1: {
+ bb1: { - _3 = &mut _4;
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind unreachable];
+ StorageDead(_5); + StorageDead(_5);
StorageDead(_2); + StorageDead(_2);
StorageDead(_4); + drop(_4) -> [return: bb2, unwind unreachable];
_0 = const (); }
StorageDead(_1);
return; bb2: {
+ } - StorageDead(_3);
+ - _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable];
+ bb2: { + StorageDead(_4);
+ _0 = const ();
+ StorageDead(_1);
+ return;
}
bb3: {
- StorageDead(_2);
- drop(_4) -> [return: bb4, unwind unreachable];
+ StorageLive(_8); + StorageLive(_8);
+ switchInt(_5) -> [0: bb3, otherwise: bb4]; + switchInt(_5) -> [0: bb4, otherwise: bb5];
+ } }
+
+ bb3: { bb4: {
- StorageDead(_4);
- _0 = const ();
- StorageDead(_1);
- return;
+ _8 = const 13_i32; + _8 = const 13_i32;
+ goto -> bb5; + goto -> bb6;
+ }
+
+ bb4: {
+ _8 = const 7_i32;
+ goto -> bb5;
+ } + }
+ +
+ bb5: { + bb5: {
+ _8 = const 7_i32;
+ goto -> bb6;
+ }
+
+ bb6: {
+ _1 = GeneratorState::<i32, bool>::Yielded(move _8); + _1 = GeneratorState::<i32, bool>::Yielded(move _8);
+ _9 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); + _9 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
+ discriminant((*_9)) = 3; + discriminant((*_9)) = 3;
+ goto -> bb1; + goto -> bb1;
+ } + }
+ +
+ bb6: { + bb7: {
+ assert(const false, "generator resumed after completion") -> [success: bb6, unwind unreachable]; + assert(const false, "generator resumed after completion") -> [success: bb7, unwind unreachable];
+ } + }
+ +
+ bb7: { + bb8: {
+ StorageLive(_8); + StorageLive(_8);
+ StorageDead(_8); + StorageDead(_8);
+ _1 = GeneratorState::<i32, bool>::Complete(_5); + _1 = GeneratorState::<i32, bool>::Complete(_5);
@ -100,7 +105,7 @@
+ goto -> bb1; + goto -> bb1;
+ } + }
+ +
+ bb8: { + bb9: {
+ unreachable; + unreachable;
} }
} }

View file

@ -41,62 +41,74 @@
- bb1: { - bb1: {
+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; + _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
_3 = &mut _4; _3 = &mut _4;
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb4]; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5];
- } - }
- -
- bb2: { - bb2: {
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
StorageDead(_3); StorageDead(_3);
- _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; - _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5];
+ StorageLive(_5); + StorageLive(_5);
+ _5 = const false; + _5 = const false;
+ _6 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); + _6 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
+ _7 = discriminant((*_6)); + _7 = discriminant((*_6));
+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; + switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11];
} }
- bb3: { - bb3: {
+ bb1: { + bb1: {
+ StorageDead(_5); + StorageDead(_5);
StorageDead(_2); StorageDead(_2);
- drop(_4) -> [return: bb4, unwind: bb6];
+ drop(_4) -> [return: bb2, unwind: bb4];
}
- bb4: {
+ bb2: {
StorageDead(_4); StorageDead(_4);
_0 = const (); _0 = const ();
StorageDead(_1); StorageDead(_1);
return; return;
} }
- bb4 (cleanup): { - bb5 (cleanup): {
+ bb2 (cleanup): { - drop(_4) -> [return: bb6, unwind terminate(cleanup)];
+ bb3 (cleanup): {
+ drop(_4) -> [return: bb4, unwind terminate(cleanup)];
}
- bb6 (cleanup): {
+ bb4 (cleanup): {
resume; resume;
+ } + }
+ +
+ bb3: {
+ StorageLive(_8);
+ switchInt(_5) -> [0: bb4, otherwise: bb5];
+ }
+
+ bb4: {
+ _8 = const 13_i32;
+ goto -> bb6;
+ }
+
+ bb5: { + bb5: {
+ _8 = const 7_i32; + StorageLive(_8);
+ goto -> bb6; + switchInt(_5) -> [0: bb6, otherwise: bb7];
+ } + }
+ +
+ bb6: { + bb6: {
+ _8 = const 13_i32;
+ goto -> bb8;
+ }
+
+ bb7: {
+ _8 = const 7_i32;
+ goto -> bb8;
+ }
+
+ bb8: {
+ _1 = GeneratorState::<i32, bool>::Yielded(move _8); + _1 = GeneratorState::<i32, bool>::Yielded(move _8);
+ _9 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); + _9 = deref_copy (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8});
+ discriminant((*_9)) = 3; + discriminant((*_9)) = 3;
+ goto -> bb1; + goto -> bb1;
+ } + }
+ +
+ bb7: { + bb9: {
+ assert(const false, "generator resumed after completion") -> [success: bb7, unwind: bb2]; + assert(const false, "generator resumed after completion") -> [success: bb9, unwind: bb3];
+ } + }
+ +
+ bb8: { + bb10: {
+ StorageLive(_8); + StorageLive(_8);
+ StorageDead(_8); + StorageDead(_8);
+ _1 = GeneratorState::<i32, bool>::Complete(_5); + _1 = GeneratorState::<i32, bool>::Complete(_5);
@ -105,7 +117,7 @@
+ goto -> bb1; + goto -> bb1;
+ } + }
+ +
+ bb9: { + bb11: {
+ unreachable; + unreachable;
} }
} }

View file

@ -31,7 +31,6 @@ fn main() {
TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::GeneratorWitnessMIR(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Alias(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Alias(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`

View file

@ -121,65 +121,59 @@ LL | TyKind::GeneratorWitness(..) => (),
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:34:9 --> $DIR/ty_tykind_usage.rs:34:9
| |
LL | TyKind::GeneratorWitnessMIR(..) => (), LL | TyKind::Never => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:35:9 --> $DIR/ty_tykind_usage.rs:35:9
| |
LL | TyKind::Never => (), LL | TyKind::Tuple(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:36:9 --> $DIR/ty_tykind_usage.rs:36:9
| |
LL | TyKind::Tuple(..) => (), LL | TyKind::Alias(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:37:9 --> $DIR/ty_tykind_usage.rs:37:9
| |
LL | TyKind::Alias(..) => (), LL | TyKind::Param(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:38:9 --> $DIR/ty_tykind_usage.rs:38:9
| |
LL | TyKind::Param(..) => (), LL | TyKind::Bound(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:39:9 --> $DIR/ty_tykind_usage.rs:39:9
| |
LL | TyKind::Bound(..) => (), LL | TyKind::Placeholder(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:40:9 --> $DIR/ty_tykind_usage.rs:40:9
| |
LL | TyKind::Placeholder(..) => (), LL | TyKind::Infer(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:41:9 --> $DIR/ty_tykind_usage.rs:41:9
| |
LL | TyKind::Infer(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:42:9
|
LL | TyKind::Error(_) => (), LL | TyKind::Error(_) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:47:12 --> $DIR/ty_tykind_usage.rs:46:12
| |
LL | if let TyKind::Int(int_ty) = kind {} LL | if let TyKind::Int(int_ty) = kind {}
| ^^^^^^ help: try using `ty::<kind>` directly: `ty` | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind` error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:49:24 --> $DIR/ty_tykind_usage.rs:48:24
| |
LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
| ^^^^^^^^^^ | ^^^^^^^^^^
@ -187,7 +181,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
= help: try using `Ty` instead = help: try using `Ty` instead
error: usage of `ty::TyKind` error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:51:37 --> $DIR/ty_tykind_usage.rs:50:37
| |
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -195,7 +189,7 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
= help: try using `Ty` instead = help: try using `Ty` instead
error: usage of `ty::TyKind` error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:51:53 --> $DIR/ty_tykind_usage.rs:50:53
| |
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -203,12 +197,12 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
= help: try using `Ty` instead = help: try using `Ty` instead
error: usage of `ty::TyKind::<kind>` error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:54:9 --> $DIR/ty_tykind_usage.rs:53:9
| |
LL | IrTyKind::Bool LL | IrTyKind::Bool
| --------^^^^^^ | --------^^^^^^
| | | |
| help: try using `ty::<kind>` directly: `ty` | help: try using `ty::<kind>` directly: `ty`
error: aborting due to 33 previous errors error: aborting due to 32 previous errors

View file

@ -1,106 +0,0 @@
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:48:13
|
LL | is_send(foo(Some(true)));
| ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:11:14
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await
| ^^^^^^ await occurs here, with `r` maybe used later
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error[E0277]: `Rc<()>` cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:50:13
|
LL | async fn foo2(x: Option<bool>) {
| - within this `impl Future<Output = ()>`
...
LL | is_send(foo2(Some(true)));
| ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: required because it's used within this `async fn` body
--> $DIR/async-await-let-else.rs:27:29
|
LL | async fn bar2<T>(_: T) -> ! {
| _____________________________^
LL | | panic!()
LL | | }
| |_^
= note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
note: required because it's used within this `async fn` body
--> $DIR/async-await-let-else.rs:21:32
|
LL | async fn foo2(x: Option<bool>) {
| ________________________________^
LL | | let Some(_) = x else {
LL | | bar2(Rc::new(())).await
LL | | };
LL | | }
| |_^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:52:13
|
LL | is_send(foo3(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:33:28
|
LL | (Rc::new(()), bar().await);
| ----------- ^^^^^^ - `Rc::new(())` is later dropped here
| | |
| | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:54:13
|
LL | is_send(foo4(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:41:14
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await;
| ^^^^^^ await occurs here, with `r` maybe used later
...
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,106 +0,0 @@
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:48:13
|
LL | is_send(foo(Some(true)));
| ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:11:15
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await
| ^^^^^ await occurs here, with `r` maybe used later
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error[E0277]: `Rc<()>` cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:50:13
|
LL | async fn foo2(x: Option<bool>) {
| - within this `impl Future<Output = ()>`
...
LL | is_send(foo2(Some(true)));
| ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: required because it's used within this `async fn` body
--> $DIR/async-await-let-else.rs:27:29
|
LL | async fn bar2<T>(_: T) -> ! {
| _____________________________^
LL | | panic!()
LL | | }
| |_^
= note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
note: required because it's used within this `async fn` body
--> $DIR/async-await-let-else.rs:21:32
|
LL | async fn foo2(x: Option<bool>) {
| ________________________________^
LL | | let Some(_) = x else {
LL | | bar2(Rc::new(())).await
LL | | };
LL | | }
| |_^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:52:13
|
LL | is_send(foo3(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:33:29
|
LL | (Rc::new(()), bar().await);
| ----------- ^^^^^ - `Rc::new(())` is later dropped here
| | |
| | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:54:13
|
LL | is_send(foo4(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:41:15
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await;
| ^^^^^ await occurs here, with `r` maybe used later
...
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

Some files were not shown because too many files have changed in this diff Show more