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,
/// 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.
}
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()
}
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) => {
}
// 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`
-> 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))
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorInterior<'a> {
type Lifted = ty::GeneratorInterior<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.witness()).map(|witness| {
- ty::GeneratorInterior(witness)
+ tcx.lift(&self.witness).map(|witness| {
+ ty::GeneratorInterior { witness }
})
}
}
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.0.visit_with(visitor)
+ self.witness.visit_with(visitor)
}
}
/// 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<Ty<'tcx>> {
- match self.0.sty {
+ match self.witness.sty {
ty::TyTuple(s, _) => s,
_ => bug!(),
}
pub return_ty: Ty<'tcx>,
}
-#[allow(warnings)]
pub type PolyGenSig<'tcx> = Binder<GenSig<'tcx>>;
-#[allow(warnings)]
impl<'tcx> PolyGenSig<'tcx> {
pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> {
self.map_bound_ref(|sig| sig.yield_ty)
}
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()
}
}
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());
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)
}
}
// 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;
pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Subtract)
}
+
+ pub fn iter(&self) -> Iter<T> {
+ Iter {
+ cur: None,
+ iter: self.words().iter().enumerate(),
+ _pd: PhantomData,
+ }
+ }
+}
+
+pub struct Iter<'a, T: Idx> {
+ cur: Option<(Word, usize)>,
+ iter: iter::Enumerate<slice::Iter<'a, Word>>,
+ _pd: PhantomData<fn(&T)>,
+}
+
+impl<'a, T: Idx> Iterator for Iter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ let word_bits = mem::size_of::<Word>() * 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,
+ }
+ }
+ }
}
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,
//! Transforms generators into state machines
-#![allow(warnings)]
-
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::const_val::ConstVal;
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;
}
});
- 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;
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,
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);
}
fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId,
source: MirSource,
interior: GeneratorInterior<'tcx>,
mir: &mut Mir<'tcx>)
-> (HashMap<Local, (Ty<'tcx>, 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());
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
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;
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>,
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();
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<BasicBlock>,
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());
generate_drop(tcx,
&transform,
- node_id,
def_id,
source,
gen_ty,
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);
}
}
// 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};
// 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 |
write!(w, ") -> {}", mir.return_ty)
}
- _ => {
+ MirSource::Const(..) |
+ MirSource::Static(..) |
+ MirSource::Promoted(..) => {
assert_eq!(mir.arg_count, 0);
write!(w, ": {} =", mir.return_ty)
}
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
// 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>,
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,
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) {
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() {
}
}
- 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);
}
}
}
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))
}
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
}
// 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();
+ }
}
}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators, generator_trait)]
-
-use std::ops::Generator;
-
-fn main() {
- let _b = {
- let a = 3;
- (|| yield &a).resume()
- //~^ ERROR: `a` does not live long enough
- };
-
- let _b = {
- let a = 3;
- || {
- yield &a
- //~^ ERROR: `a` does not live long enough
- }
- };
-}
-
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-fn main() {
- let gen = |start| { //~ ERROR generators cannot have explicit arguments
- yield;
- };
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-use std::cell::Cell;
-
-fn main() {
- fn assert_sync<T: Sync>(_: T) {}
- fn assert_send<T: Send>(_: T) {}
-
- assert_sync(|| {
- //~^ ERROR: Sync` is not satisfied
- let a = Cell::new(2);
- yield;
- });
-
- let a = Cell::new(2);
- assert_send(|| {
- //~^ ERROR: Sync` is not satisfied
- drop(&a);
- yield;
- });
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-const A: u8 = { yield 3u8; 3u8};
-//~^ ERROR yield statement outside
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-fn main() { yield; }
-//~^ ERROR yield statement outside
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-static B: u8 = { yield 3u8; 3u8};
-//~^ ERROR yield statement outside
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Yield = (), Return = ()> {
+ || {
+ if bar() {
+ yield;
+ }
+ }
+}
}
}
+fn bool_true() -> bool {
+ true
+}
+
fn main() {
let b = B;
let mut foo = || {
- if true {
+ if bool_true() {
panic!();
}
drop(b);
assert_eq!(A.load(Ordering::SeqCst), 1);
let mut foo = || {
- if true {
+ if bool_true() {
panic!();
}
drop(B);
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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),
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn main() {
+ let _b = {
+ let a = 3;
+ (|| yield &a).resume()
+ //~^ ERROR: `a` does not live long enough
+ };
+
+ let _b = {
+ let a = 3;
+ || {
+ yield &a
+ //~^ ERROR: `a` does not live long enough
+ }
+ };
+}
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+fn main() {
+ let gen = |start| { //~ ERROR generators cannot have explicit arguments
+ yield;
+ };
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+use std::cell::Cell;
+
+fn main() {
+ fn assert_sync<T: Sync>(_: T) {}
+ fn assert_send<T: Send>(_: T) {}
+
+ assert_sync(|| {
+ //~^ ERROR: Sync` is not satisfied
+ let a = Cell::new(2);
+ yield;
+ });
+
+ let a = Cell::new(2);
+ assert_send(|| {
+ //~^ ERROR: Sync` is not satisfied
+ drop(&a);
+ yield;
+ });
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+const A: u8 = { yield 3u8; 3u8};
+//~^ ERROR yield statement outside
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+fn main() { yield; }
+//~^ ERROR yield statement outside
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+static B: u8 = { yield 3u8; 3u8};
+//~^ ERROR yield statement outside