let mut reinit = None;
match expr.kind {
ExprKind::Assign(lhs, rhs, _) => {
- self.visit_expr(lhs);
self.visit_expr(rhs);
+ self.visit_expr(lhs);
reinit = Some(lhs);
}
self.drop_ranges.add_control_edge(self.expr_index, *target)
}),
- ExprKind::Break(destination, ..) => {
+ 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.
// will refer to the end of the block due to the post order traversal.
self.find_target_expression_from_destination(destination).map_or((), |target| {
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
- })
+ });
+
+ if let Some(value) = value {
+ self.visit_expr(value);
+ }
}
ExprKind::Call(f, args) => {
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(..)
// 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);
}
}
}
});
}
- debug!("hir_id_map: {:?}", tracked_value_map);
+ debug!("hir_id_map: {:#?}", tracked_value_map);
let num_values = tracked_value_map.len();
Self {
tracked_value_map,
//! 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};
.post_order_map
.iter()
.find(|(_hir_id, &post_order_id)| post_order_id == *n)
- .map_or("<unknown>".into(), |(hir_id, _)| self
- .tcx
- .hir()
- .node_to_string(*hir_id))
+ .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(),
)
yield_data.expr_and_pat_count, self.expr_count, source_span
);
- if self.fcx.sess().opts.unstable_opts.drop_tracking
- && self
- .drop_ranges
- .is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+ 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 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>(