From 352577f4bb7c0214570db062d84dc69004348769 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Aug 2017 13:56:19 -0700 Subject: [PATCH] Initial pass review comments --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/mir/mod.rs | 7 +- src/librustc/traits/select.rs | 2 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/outlives.rs | 2 +- src/librustc/ty/relate.rs | 2 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc/ty/sty.rs | 14 +-- src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_data_structures/indexed_set.rs | 39 +++++++ src/librustc_mir/hair/cx/expr.rs | 94 +++++++-------- src/librustc_mir/transform/generator.rs | 109 ++++-------------- src/librustc_mir/util/liveness.rs | 25 +++- src/librustc_mir/util/pretty.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 4 +- .../check/generator_interior.rs | 44 ++++--- src/librustc_typeck/check/mod.rs | 33 +++--- .../run-pass/generator/auxiliary/xcrate.rs | 25 ++++ src/test/run-pass/generator/panic-drops.rs | 8 +- src/test/run-pass/generator/xcrate.rs | 26 +++++ .../generator/borrowing.rs | 0 .../generator/no-arguments-on-generators.rs | 0 .../generator/not-send-sync.rs | 0 .../generator/yield-in-const.rs | 0 .../generator/yield-in-function.rs | 0 .../generator/yield-in-static.rs | 0 28 files changed, 251 insertions(+), 205 deletions(-) create mode 100644 src/test/run-pass/generator/auxiliary/xcrate.rs create mode 100644 src/test/run-pass/generator/xcrate.rs rename src/test/{compile-fail => ui}/generator/borrowing.rs (100%) rename src/test/{compile-fail => ui}/generator/no-arguments-on-generators.rs (100%) rename src/test/{compile-fail => ui}/generator/not-send-sync.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-const.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-function.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-static.rs (100%) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 9286d3c73ed..e316fd5f3e6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -320,7 +320,7 @@ fn hash_stable(&self, impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); -impl_stable_hash_for!(tuple_struct ty::GeneratorInterior<'tcx> { ty }); +impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness }); impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4063609474b..e688af43160 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -411,8 +411,13 @@ pub struct LocalDecl<'tcx> { /// True if this corresponds to a user-declared local variable. pub is_user_variable: bool, - /// True if this an internal local. + /// True if this is an internal local. /// Such locals are not checked against the legal types in a generator. + /// + /// Scalar state variables created by optimizations (e.g. nonzeroing drop + /// flags) should not be included in generator OIBIT computations. + /// Therefore, we mark them as `internal` so we can ignore them when + /// sanity-checking the OIBIT list. pub internal: bool, /// Type of this local. diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9d5494d1fba..52c8b67278e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2126,7 +2126,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { } ty::TyGenerator(def_id, ref substs, interior) => { - let witness = iter::once(interior.witness()); + let witness = iter::once(interior.witness); substs.upvar_tys(def_id, self.tcx()).chain(witness).collect() } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 02d50ce29e4..f40e1d370a9 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -89,7 +89,7 @@ fn add_sty(&mut self, st: &ty::TypeVariants) { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); self.add_substs(&substs.substs); - self.add_ty(interior.witness()); + self.add_ty(interior.witness); } &ty::TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 3549a770643..657ed407791 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -122,7 +122,7 @@ fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec>) { } // But generators can have additional interior types - self.compute_components(interior.witness(), out); + self.compute_components(interior.witness, out); } // OutlivesTypeParameterEnv -- the actual checking that `X:'a` diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 437f511cb3d..da94eddf295 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -531,7 +531,7 @@ fn relate<'a, 'gcx, R>(relation: &mut R, -> RelateResult<'tcx, ty::GeneratorInterior<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let interior = relation.relate(&a.witness(), &b.witness())?; + let interior = relation.relate(&a.witness, &b.witness)?; Ok(ty::GeneratorInterior::new(interior)) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 087c41a7883..cbb0a45cf1e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -232,8 +232,8 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option Lift<'tcx> for ty::GeneratorInterior<'a> { type Lifted = ty::GeneratorInterior<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.witness()).map(|witness| { - ty::GeneratorInterior(witness) + tcx.lift(&self.witness).map(|witness| { + ty::GeneratorInterior { witness } }) } } @@ -737,11 +737,11 @@ fn super_visit_with>(&self, visitor: &mut V) -> bool { impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::GeneratorInterior(self.0.fold_with(folder)) + ty::GeneratorInterior::new(self.witness.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) + self.witness.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 2f3fd5244ae..9898ce5d73d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -295,19 +295,17 @@ impl Iterator> + 'tcx /// The state transformation MIR pass may only produce layouts which mention types in this tuple. /// Upvars are not counted here. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct GeneratorInterior<'tcx>(pub Ty<'tcx>); +pub struct GeneratorInterior<'tcx> { + pub witness: Ty<'tcx>, +} impl<'tcx> GeneratorInterior<'tcx> { pub fn new(witness: Ty<'tcx>) -> GeneratorInterior<'tcx> { - GeneratorInterior(witness) - } - - pub fn witness(&self) -> Ty<'tcx> { - self.0 + GeneratorInterior { witness } } pub fn as_slice(&self) -> &'tcx Slice> { - match self.0.sty { + match self.witness.sty { ty::TyTuple(s, _) => s, _ => bug!(), } @@ -638,10 +636,8 @@ pub struct GenSig<'tcx> { pub return_ty: Ty<'tcx>, } -#[allow(warnings)] pub type PolyGenSig<'tcx> = Binder>; -#[allow(warnings)] impl<'tcx> PolyGenSig<'tcx> { pub fn yield_ty(&self) -> ty::Binder> { self.map_bound_ref(|sig| sig.yield_ty) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6bbcc674ef4..67ec8d2ae63 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -570,7 +570,7 @@ pub fn dtorck_constraint_for_ty(self, } ty::TyGenerator(def_id, substs, interior) => { - substs.upvar_tys(def_id, self).chain(iter::once(interior.witness())).map(|ty| { + substs.upvar_tys(def_id, self).chain(iter::once(interior.witness)).map(|ty| { self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) }).collect() } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a2087b0b2f1..bfabacdb172 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -114,7 +114,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { } ty::TyGenerator(_, ref substs, ref interior) => { stack.extend(substs.substs.types().rev()); - stack.push(interior.witness()); + stack.push(interior.witness); } ty::TyTuple(ts, _) => { stack.extend(ts.iter().cloned().rev()); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 33ab83d236f..ed72f242948 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -717,7 +717,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { impl<'tcx> fmt::Display for ty::GeneratorInterior<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) + self.witness.fmt(f) } } diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 821e2b01431..9fa47cee659 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -9,9 +9,11 @@ // except according to those terms. use std::fmt; +use std::iter; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Range}; +use std::slice; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; use indexed_vec::Idx; @@ -161,4 +163,41 @@ pub fn union(&mut self, other: &IdxSet) -> bool { pub fn subtract(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Subtract) } + + pub fn iter(&self) -> Iter { + Iter { + cur: None, + iter: self.words().iter().enumerate(), + _pd: PhantomData, + } + } +} + +pub struct Iter<'a, T: Idx> { + cur: Option<(Word, usize)>, + iter: iter::Enumerate>, + _pd: PhantomData, +} + +impl<'a, T: Idx> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + let word_bits = mem::size_of::() * 8; + loop { + if let Some((ref mut word, offset)) = self.cur { + let bit_pos = word.trailing_zeros(); + if bit_pos != word_bits as u32 { + let bit = 1 << bit_pos; + *word ^= bit; + return Some(T::new(bit + offset)) + } + } + + match self.iter.next() { + Some((i, word)) => self.cur = Some((*word, word_bits * i)), + None => return None, + } + } + } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 9b3585fff58..a81103213b8 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -703,57 +703,57 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let region = cx.tcx.mk_region(region); let self_expr = if let ty::TyClosure(..) = closure_ty.sty { - match cx.tcx.closure_kind(closure_def_id) { - ty::ClosureKind::Fn => { - let ref_closure_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: closure_ty, - mutbl: hir::MutImmutable, - }); - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), - }, + match cx.tcx.closure_kind(closure_def_id) { + ty::ClosureKind::Fn => { + let ref_closure_ty = cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: closure_ty, + mutbl: hir::MutImmutable, + }); + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::Deref { + arg: Expr { + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + } + .to_ref(), + }, + } } - } - ty::ClosureKind::FnMut => { - let ref_closure_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: closure_ty, - mutbl: hir::MutMutable, - }); - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - }.to_ref(), - }, + ty::ClosureKind::FnMut => { + let ref_closure_ty = cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: closure_ty, + mutbl: hir::MutMutable, + }); + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::Deref { + arg: Expr { + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + }.to_ref(), + }, + } } - } - ty::ClosureKind::FnOnce => { - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, + ty::ClosureKind::FnOnce => { + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + } } } - } } else { Expr { ty: closure_ty, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index dc86bc6818d..f57ba0cf42a 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -10,8 +10,6 @@ //! Transforms generators into state machines -#![allow(warnings)] - use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; @@ -23,11 +21,11 @@ use util::dump_mir; use util::liveness; use rustc_const_math::ConstInt; -use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::Idx; use std::collections::HashMap; use std::borrow::Cow; use std::iter::once; +use std::mem; use syntax::ast::NodeId; use transform::simplify; @@ -150,7 +148,7 @@ fn visit_basic_block_data(&mut self, } }); - ret_val.map(|(state_idx, resume, v, drop)| { + if let Some((state_idx, resume, v, drop)) = ret_val { let bb_idx = { let bb_targets = &mut self.bb_targets; let bb_target = &mut self.bb_target_count; @@ -168,54 +166,12 @@ fn visit_basic_block_data(&mut self, self.make_state(state_idx, v)), }); data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; - }); + } self.super_basic_block_data(block, data); } } -fn get_body_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: NodeId) -> (bool, hir::BodyId) { - // Figure out what primary body this item has. - match tcx.hir.get(node_id) { - hir::map::NodeItem(item) => { - match item.node { - hir::ItemConst(_, body) | - hir::ItemStatic(_, _, body) | - hir::ItemFn(.., body) => (false, body), - _ => bug!(), - } - } - hir::map::NodeTraitItem(item) => { - match item.node { - hir::TraitItemKind::Const(_, Some(body)) | - hir::TraitItemKind::Method(_, - hir::TraitMethod::Provided(body)) => (false, body), - _ => bug!(), - } - } - hir::map::NodeImplItem(item) => { - match item.node { - hir::ImplItemKind::Const(_, body) | - hir::ImplItemKind::Method(_, body) => (false, body), - _ => bug!(), - } - } - hir::map::NodeExpr(expr) => { - // FIXME(eddyb) Closures should have separate - // function definition IDs and expression IDs. - // Type-checking should not let closures get - // this far in a constant position. - // Assume that everything other than closures - // is a constant "initializer" expression. - match expr.node { - hir::ExprClosure(_, _, body, _, _) => (true, body), - _ => (false, hir::BodyId { node_id: expr.id }) - } - } - _ => bug!(), - } -} - fn ensure_generator_state_argument<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: NodeId, @@ -281,7 +237,6 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, source: MirSource) -> liveness::LocalSet { - use rustc_data_structures::indexed_set::IdxSetBuf; let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); let result = liveness::liveness_of_locals(mir); liveness::dump_mir(tcx, "generator_liveness", source, mir, &result); @@ -299,18 +254,12 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, source: MirSource, interior: GeneratorInterior<'tcx>, mir: &mut Mir<'tcx>) -> (HashMap, usize)>, GeneratorLayout<'tcx>) { - let source_info = SourceInfo { - span: mir.span, - scope: ARGUMENT_VISIBILITY_SCOPE, - }; - - let mut live_locals = locals_live_across_suspend_points(tcx, mir, source); + let live_locals = locals_live_across_suspend_points(tcx, mir, source); let allowed = tcx.erase_regions(&interior.as_slice()); @@ -319,34 +268,23 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } if !allowed.contains(&decl.ty) { - tcx.sess.span_warn(mir.span, - &format!("generator contains type {} in MIR, but typeck only knows about {}", - decl.ty, - interior)); + span_bug!(mir.span, + "Broken MIR: generator contains type {} in MIR, \ + but typeck only knows about {}", + decl.ty, + interior); } } let upvar_len = mir.upvar_decls.len(); - let live_decls : Vec<_> = mir.local_decls - .iter_enumerated_mut() - .filter(|&(local, _)| live_locals.contains(&local)) - .collect(); - - let mut remap = HashMap::new(); - let unit = tcx.mk_nil(); - let mut vars: Vec<_> = live_decls.into_iter().enumerate().map(|(idx, (local, decl))| { - let var = decl.clone(); - *decl = LocalDecl { - mutability: Mutability::Mut, - ty: unit, - name: None, - source_info, - internal: false, - is_user_variable: false, - }; - remap.insert(local, (var.ty, upvar_len + 1 + idx)); - var - }).collect(); + let dummy_local = LocalDecl::new_internal(tcx.mk_nil(), mir.span); + let live_decls = live_locals.iter().map(|local| { + let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone()); + (local, var) + }); + let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| { + ((local, (var.ty, upvar_len + 1 + idx)), var) + }).unzip(); let layout = GeneratorLayout { fields: vars @@ -369,7 +307,7 @@ fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>, fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, mir: &mut Mir<'tcx>) { - use util::elaborate_drops::{elaborate_drop, Unwind, DropElaborator, DropStyle, DropFlagMode}; + use util::elaborate_drops::{elaborate_drop, Unwind}; use util::patch::MirPatch; use shim::DropShimElaborator; @@ -418,7 +356,6 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn generate_drop<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, transform: &TransformVisitor<'a, 'tcx>, - node_id: NodeId, def_id: DefId, source: MirSource, gen_ty: Ty<'tcx>, @@ -439,7 +376,7 @@ fn generate_drop<'a, 'tcx>( is_cleanup: false, }); - let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(r, u), &s)| { + let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| { u.map(|d| (s, d)) }).collect(); @@ -581,10 +518,9 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cleanup } -fn generate_resume<'a, 'tcx>( +fn generate_entry_point<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mut transform: TransformVisitor<'a, 'tcx>, - node_id: NodeId, def_id: DefId, source: MirSource, cleanup: Option, @@ -721,7 +657,7 @@ fn run_pass<'a, 'tcx>(&self, let new_ret_local = replace_result_variable(ret_ty, mir); - let (remap, layout) = compute_layout(tcx, def_id, source, interior, mir); + let (remap, layout) = compute_layout(tcx, source, interior, mir); let tail_block = BasicBlock::new(mir.basic_blocks().len()); @@ -763,7 +699,6 @@ fn run_pass<'a, 'tcx>(&self, generate_drop(tcx, &transform, - node_id, def_id, source, gen_ty, @@ -772,6 +707,6 @@ fn run_pass<'a, 'tcx>(&self, mir.generator_drop = Some(box drop_impl); - generate_resume(tcx, transform, node_id, def_id, source, arg_cleanup, mir); + generate_entry_point(tcx, transform, def_id, source, arg_cleanup, mir); } } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 946e9ff4747..fd15c90dc90 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -9,6 +9,29 @@ // except according to those terms. //! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks +//! +//! This analysis considers references as being used only at the point of the +//! borrow. This means that this does not track uses because of references that +//! already exist: +//! +//! ```Rust +//! fn foo() { +//! x = 0; +//! // `x` is live here +//! GLOBAL = &x: *const u32; +//! // but not here, even while it can be accessed through `GLOBAL`. +//! foo(); +//! x = 1; +//! // `x` is live again here, because it is assigned to `OTHER_GLOBAL` +//! OTHER_GLOBAL = &x: *const u32; +//! // ... +//! } +//! ``` +//! +//! This means that users of this analysis still have to check whether +//! pre-existing references can be used to access the value (e.g. at movable +//! generator yield points, all pre-existing references are invalidated, so this +//! doesn't matter). use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; @@ -60,7 +83,7 @@ fn visit_lvalue(&mut self, // Borrows only consider their local used at the point of the borrow. // This won't affect the results since we use this analysis for generators // and we only care about the result at suspension points. Borrows cannot - // cross suspension points so this behavoir is unproblematic. + // cross suspension points so this behavior is unproblematic. LvalueContext::Borrow { .. } | LvalueContext::Inspect | diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index e3087efbfe6..0811783a9e5 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -348,7 +348,9 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, ") -> {}", mir.return_ty) } - _ => { + MirSource::Const(..) | + MirSource::Static(..) | + MirSource::Promoted(..) => { assert_eq!(mir.arg_count, 0); write!(w, ": {} =", mir.return_ty) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index d646b515bf4..10b66fb1991 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -287,9 +287,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); - let buffer = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)); - - buffer.finish(hash) + SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) } // Follow C++ namespace-mangling style, see diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index f116620388f..6753d42b0c5 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use log; +use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Body, Pat, PatKind, Expr}; -use rustc::hir::def_id::DefId; -use rustc::ty::Ty; use rustc::middle::region::{RegionMaps, CodeExtent}; -use util::nodemap::FxHashSet; +use rustc::ty::Ty; use std::rc::Rc; use super::FnCtxt; +use util::nodemap::FxHashSet; struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, @@ -28,36 +29,34 @@ fn record(&mut self, ty: Ty<'tcx>, scope: Option, expr: Option<&'tcx use syntax_pos::DUMMY_SP; if scope.map(|s| self.fcx.tcx.yield_in_extent(s).is_some()).unwrap_or(true) { - if self.fcx.tcx.sess.verbose() { + if log_enabled!(log::LogLevel::Debug) { if let Some(s) = scope { - self.fcx.tcx.sess.span_warn(s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP), - &format!("type in generator with scope = {:?}, type = {:?}", - scope, - self.fcx.resolve_type_vars_if_possible(&ty))); + let span = s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP); + debug!("type in generator with scope = {:?}, type = {:?}, span = {:?}", + scope, + self.fcx.resolve_type_vars_if_possible(&ty), + span); } else { - self.fcx.tcx.sess.span_warn(DUMMY_SP, - &format!("type in generator WITHOUT scope, type = {:?}", - self.fcx.resolve_type_vars_if_possible(&ty))); + debug!("type in generator WITHOUT scope, type = {:?}", + self.fcx.resolve_type_vars_if_possible(&ty)); } if let Some(e) = expr { - self.fcx.tcx.sess.span_warn(e.span, - &format!("type from expression: {:?}", e)); + debug!("type from expression: {:?}, span={:?}", e, e.span); } } self.types.insert(ty); - } else if self.fcx.tcx.sess.verbose() { + } else { if let Some(e) = expr { - self.fcx.tcx.sess.span_warn(e.span, - &format!("NO type from expression: {:?}", e)); + debug!("NO type from expression: {:?}, span = {:?}", e, e.span); } } } } -pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - body_id: hir::BodyId, - witness: Ty<'tcx>) { +pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + body_id: hir::BodyId, + witness: Ty<'tcx>) { let body = fcx.tcx.hir.body(body_id); let mut visitor = InteriorVisitor { fcx, @@ -74,10 +73,7 @@ pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let tuple = fcx.tcx.intern_tup(&types, false); - if fcx.tcx.sess.verbose() { - fcx.tcx.sess.span_warn(body.value.span, - &format!("Types in generator {:?}", tuple)); - } + debug!("Types in generator {:?}, span = {:?}", tuple, body.value.span); // Unify the tuple with the witness match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(witness, tuple) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ed6d0c035de..fee10f50378 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -892,7 +892,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); - fcx.find_generator_interiors(def_id); + fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); if fn_decl.is_some() { @@ -2107,10 +2107,10 @@ fn check_casts(&self) { } } - fn find_generator_interiors(&self, def_id: DefId) { + fn resolve_generator_interiors(&self, def_id: DefId) { let mut deferred_generator_interiors = self.deferred_generator_interiors.borrow_mut(); for (body_id, witness) in deferred_generator_interiors.drain(..) { - generator_interior::find_interior(self, def_id, body_id, witness); + generator_interior::resolve_interior(self, def_id, body_id, witness); } } @@ -2677,8 +2677,8 @@ fn check_expr_eq_type(&self, } pub fn check_expr_has_type_or_error(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) -> Ty<'tcx> { self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) } @@ -3138,13 +3138,13 @@ fn check_tup_field(&self, return field_ty; } - if tuple_like { + if tuple_like { type_error_struct!(self.tcx().sess, expr.span, expr_t, E0612, - "attempted out-of-bounds tuple index `{}` on type `{}`", - idx.node, expr_t).emit(); - } else { + "attempted out-of-bounds tuple index `{}` on type `{}`", + idx.node, expr_t).emit(); + } else { self.no_such_field_err(expr.span, idx.node, expr_t).emit(); - } + } self.tcx().types.err } @@ -3733,14 +3733,11 @@ fn check_expr_kind(&self, // Only check this if not in an `if` condition, as the // mistyped comparison help is more appropriate. if !self.tcx.expr_is_lval(&lhs) { - struct_span_err!( - self.tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label( - expr.span, - "left-hand of expression not valid") - .emit(); - } + struct_span_err!(self.tcx.sess, expr.span, E0070, + "invalid left-hand side expression") + .span_label(expr.span, "left-hand of expression not valid") + .emit(); + } } } diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs new file mode 100644 index 00000000000..519c34cd0ed --- /dev/null +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -0,0 +1,25 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait, conservative_impl_trait)] + +use std::ops::Generator; + +fn bar() -> bool { + false +} + +pub fn foo() -> impl Generator { + || { + if bar() { + yield; + } + } +} diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 4837f68be5e..53cd3235d9d 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -24,10 +24,14 @@ fn drop(&mut self) { } } +fn bool_true() -> bool { + true +} + fn main() { let b = B; let mut foo = || { - if true { + if bool_true() { panic!(); } drop(b); @@ -42,7 +46,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 1); let mut foo = || { - if true { + if bool_true() { panic!(); } drop(B); diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs new file mode 100644 index 00000000000..5d6cdee1a24 --- /dev/null +++ b/src/test/run-pass/generator/xcrate.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:xcrate.rs + +#![feature(generators, generator_trait)] + +extern crate xcrate; + +use std::ops::{GeneratorState, Generator}; + +fn main() { + let mut foo = xcrate::foo(); + + match foo.resume() { + GeneratorState::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } +} diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs similarity index 100% rename from src/test/compile-fail/generator/borrowing.rs rename to src/test/ui/generator/borrowing.rs diff --git a/src/test/compile-fail/generator/no-arguments-on-generators.rs b/src/test/ui/generator/no-arguments-on-generators.rs similarity index 100% rename from src/test/compile-fail/generator/no-arguments-on-generators.rs rename to src/test/ui/generator/no-arguments-on-generators.rs diff --git a/src/test/compile-fail/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs similarity index 100% rename from src/test/compile-fail/generator/not-send-sync.rs rename to src/test/ui/generator/not-send-sync.rs diff --git a/src/test/compile-fail/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-const.rs rename to src/test/ui/generator/yield-in-const.rs diff --git a/src/test/compile-fail/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-function.rs rename to src/test/ui/generator/yield-in-function.rs diff --git a/src/test/compile-fail/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-static.rs rename to src/test/ui/generator/yield-in-static.rs -- 2.44.0