//! 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_const_eval::transform::generator` and may be a subset of the
+//! is calculated in `rustc_mir_transform::generator` and may be a subset of the
//! types computed here.
use self::drop_ranges::DropRanges;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
-use rustc_middle::middle::region::{self, YieldData};
+use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
self.expr_count += 1;
- let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(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.
+ let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
+ self.region_scope_tree.temporary_scope(expr.hir_id.local_id)
+ } else {
+ debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
+ match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
+ Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
+ None => self.region_scope_tree.temporary_scope(expr.hir_id.local_id),
+ }
+ };
// If there are adjustments, then record the final type --
// this is the actual value that is being produced.
}
// Returns whether it emitted a diagnostic or not
-// Note that this fn and the proceding one are based on the code
+// 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 precendent in the compiler
+// as it is simpler and has precedent in the compiler
pub fn check_must_not_suspend_ty<'tcx>(
fcx: &FnCtxt<'_, 'tcx>,
ty: Ty<'tcx>,
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),
+ ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
// FIXME: support adding the attribute to TAITs
ty::Opaque(def, _) => {
let mut has_emitted = false;
}
has_emitted
}
- ty::Tuple(_) => {
+ ty::Tuple(fields) => {
let mut has_emitted = false;
let comps = match data.expr.map(|e| &e.kind) {
Some(hir::ExprKind::Tup(comps)) => {
- debug_assert_eq!(comps.len(), ty.tuple_fields().count());
+ debug_assert_eq!(comps.len(), fields.len());
Some(comps)
}
_ => None,
};
- for (i, ty) in ty.tuple_fields().enumerate() {
+ 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(