diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 66b3adb83c160..cbc061478f853 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -467,9 +467,13 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { } fn visit_pat(&mut self, pat: &'tcx Pat) { + intravisit::walk_pat(self, pat); + self.expr_and_pat_count += 1; - intravisit::walk_pat(self, pat); + if pat.id == self.id { + self.result = Some(self.expr_and_pat_count); + } } fn visit_expr(&mut self, expr: &'tcx Expr) { @@ -814,7 +818,8 @@ impl<'tcx> ScopeTree { /// Checks whether the given scope contains a `yield`. If so, /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions appearing before the `yield` in the body. + /// the number of expressions and patterns appearing before the `yield` in the body + 1. + /// If there a are multiple yields in a scope, the one with the highest number is returned. pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> { self.yield_in_scope.get(&scope).cloned() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 42200a3a44728..3cb9449901d0b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1261,6 +1261,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note("the return type of a function must have a \ statically known size"); } + ObligationCauseCode::SizedYieldType => { + err.note("the yield type of a generator must have a \ + statically known size"); + } ObligationCauseCode::AssignmentLhsSized => { err.note("the left-hand-side of an assignment must have a statically known size"); } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index fd47e09aad7f9..5bfa6f936db7d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -138,6 +138,8 @@ pub enum ObligationCauseCode<'tcx> { VariableType(ast::NodeId), /// Return type must be Sized SizedReturnType, + /// Yield type must be Sized + SizedYieldType, /// [T,..n] --> T must be Copy RepeatVec, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index e1e2798ecb51c..1eb14a222787d 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -209,6 +209,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::VariableType(id) => Some(super::VariableType(id)), super::ReturnType(id) => Some(super::ReturnType(id)), super::SizedReturnType => Some(super::SizedReturnType), + super::SizedYieldType => Some(super::SizedYieldType), super::RepeatVec => Some(super::RepeatVec), super::FieldSized(item) => Some(super::FieldSized(item)), super::ConstSized => Some(super::ConstSized), @@ -526,6 +527,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::VariableType(_) | super::ReturnType(_) | super::SizedReturnType | + super::SizedYieldType | super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | @@ -574,6 +576,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::VariableType(_) | super::ReturnType(_) | super::SizedReturnType | + super::SizedYieldType | super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index db7e4fe45ef76..d20cf556b71c0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -390,14 +390,21 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { state.map(move |d| d.ty.subst(tcx, self.substs)) } + /// This is the types of the fields of a generate which + /// is available before the generator transformation. + /// It includes the upvars and the state discriminant which is u32. + pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> + impl Iterator> + 'a + { + self.upvar_tys(def_id, tcx).chain(iter::once(tcx.types.u32)) + } + /// This is the types of all the fields stored in a generator. /// It includes the upvars, state types and the state discriminant which is u32. pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator> + 'a { - let upvars = self.upvar_tys(def_id, tcx); - let state = self.state_tys(def_id, tcx); - upvars.chain(iter::once(tcx.types.u32)).chain(state) + self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx)) } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 7bd3b6e39f053..7fadc4b36e44f 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -746,12 +746,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.describe_field_from_ty(&tnm.ty, field) } ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field), - ty::TyClosure(closure_def_id, _) => { + ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => { // Convert the def-id into a node-id. node-ids are only valid for // the local code in the current crate, so this returns an `Option` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]); self.tcx.hir.name(freevar.var_id()).to_string() diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 9dcd4435580ab..dc302b6cc354e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -533,15 +533,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ty::TyGenerator(def_id, substs, _) => { - // Try upvars first. `field_tys` requires final optimized MIR. - if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) { + // Try pre-transform fields first (upvars and current state) + if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) { return Ok(ty); } + // Then try `field_tys` which contains all the fields, but it + // requires the final optimized MIR. return match substs.field_tys(def_id, tcx).nth(field.index()) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count() + 1, + field_count: substs.field_tys(def_id, tcx).count(), }), }; } @@ -1233,13 +1235,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } AggregateKind::Generator(def_id, substs, _) => { - if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) { + // Try pre-transform fields first (upvars and current state) + if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) { Ok(ty) } else { + // Then try `field_tys` which contains all the fields, but it + // requires the final optimized MIR. match substs.field_tys(def_id, tcx).nth(field_index) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count() + 1, + field_count: substs.field_tys(def_id, tcx).count(), }), } } diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs new file mode 100644 index 0000000000000..244e8b5ccd7e4 --- /dev/null +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -0,0 +1,118 @@ +// 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. + +pub use super::*; + +use rustc::mir::*; +use rustc::mir::visit::Visitor; +use dataflow::BitDenotation; + +/// This calculates if any part of a MIR local could have previously been borrowed. +/// This means that once a local has been borrowed, its bit will always be set +/// from that point and onwards, even if the borrow ends. You could also think of this +/// as computing the lifetimes of infinite borrows. +/// This is used to compute which locals are live during a yield expression for +/// immovable generators. +#[derive(Copy, Clone)] +pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> { + pub fn new(mir: &'a Mir<'tcx>) + -> Self { + HaveBeenBorrowedLocals { mir: mir } + } + + pub fn mir(&self) -> &Mir<'tcx> { + self.mir + } +} + +impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> { + type Idx = Local; + fn name() -> &'static str { "has_been_borrowed_locals" } + fn bits_per_block(&self) -> usize { + self.mir.local_decls.len() + } + + fn start_block_effect(&self, _sets: &mut IdxSet) { + // Nothing is borrowed on function entry + } + + fn statement_effect(&self, + sets: &mut BlockSets, + loc: Location) { + BorrowedLocalsVisitor { + sets, + }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc); + } + + fn terminator_effect(&self, + sets: &mut BlockSets, + loc: Location) { + BorrowedLocalsVisitor { + sets, + }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc); + } + + fn propagate_call_return(&self, + _in_out: &mut IdxSet, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place) { + // Nothing to do when a call returns successfully + } +} + +impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + false // bottom = unborrowed + } +} + +struct BorrowedLocalsVisitor<'b, 'c: 'b> { + sets: &'b mut BlockSets<'c, Local>, +} + +fn find_local<'tcx>(place: &Place<'tcx>) -> Option { + match *place { + Place::Local(l) => Some(l), + Place::Static(..) => None, + Place::Projection(ref proj) => { + match proj.elem { + ProjectionElem::Deref => None, + _ => find_local(&proj.base) + } + } + } +} + +impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> { + fn visit_rvalue(&mut self, + rvalue: &Rvalue<'tcx>, + location: Location) { + if let Rvalue::Ref(_, _, ref place) = *rvalue { + if let Some(local) = find_local(place) { + self.sets.gen(&local); + } + } + + self.super_rvalue(rvalue, location) + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 106a88e703c79..c4942adc81493 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -33,6 +33,10 @@ mod storage_liveness; pub use self::storage_liveness::*; +mod borrowed_locals; + +pub use self::borrowed_locals::*; + #[allow(dead_code)] pub(super) mod borrows; diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index b18fb7c7b9cce..8156ff11f9bbe 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -30,6 +30,7 @@ pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements}; pub use self::impls::EverInitializedLvals; pub use self::impls::borrows::{Borrows, BorrowData}; +pub use self::impls::HaveBeenBorrowedLocals; pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex}; pub use self::at_location::{FlowAtLocation, FlowsAtLocation}; pub(crate) use self::drop_flag_effects::*; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index ebd34f81deb29..812665f5fa498 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -78,7 +78,8 @@ use std::mem; use transform::{MirPass, MirSource}; use transform::simplify; use transform::no_landing_pads::no_landing_pads; -use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location}; +use dataflow::{do_dataflow, DebugFormatted, state_for_location}; +use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; pub struct StateTransform; @@ -369,17 +370,33 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, HashMap) { let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap(); - let analysis = MaybeStorageLive::new(mir); + + // Calculate when MIR locals have live storage. This gives us an upper bound of their + // lifetimes. + let storage_live_analysis = MaybeStorageLive::new(mir); let storage_live = - do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis, + do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis, |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); + // Find the MIR locals which do not use StorageLive/StorageDead statements. + // The storage of these locals are always live. let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len())); ignored.visit_mir(mir); - let mut borrowed_locals = BorrowedLocals(IdxSetBuf::new_empty(mir.local_decls.len())); - borrowed_locals.visit_mir(mir); + // Calculate the MIR locals which have been previously + // borrowed (even if they are still active). + // This is only used for immovable generators. + let borrowed_locals = if !movable { + let analysis = HaveBeenBorrowedLocals::new(mir); + let result = + do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis, + |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); + Some((analysis, result)) + } else { + None + }; + // Calculate the liveness of MIR locals ignoring borrows. let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); let mut liveness = liveness::liveness_of_locals(mir, LivenessMode { include_regular_use: true, @@ -396,24 +413,41 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, statement_index: data.statements.len(), }; - let storage_liveness = state_for_location(loc, &analysis, &storage_live, mir); + if let Some((ref analysis, ref result)) = borrowed_locals { + let borrowed_locals = state_for_location(loc, + analysis, + result, + mir); + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. + // This is correct for movable generators since borrows cannot live across + // suspension points. However for immovable generators we need to account for + // borrows, so we conseratively assume that all borrowed locals live forever. + // To do this we just union our `liveness` result with `borrowed_locals`, which + // contains all the locals which has been borrowed before this suspension point. + // If a borrow is converted to a raw reference, we must also assume that it lives + // forever. Note that the final liveness is still bounded by the storage liveness + // of the local, which happens using the `intersect` operation below. + liveness.outs[block].union(&borrowed_locals); + } + + let mut storage_liveness = state_for_location(loc, + &storage_live_analysis, + &storage_live, + mir); + // Store the storage liveness for later use so we can restore the state + // after a suspension point storage_liveness_map.insert(block, storage_liveness.clone()); - let mut live_locals = storage_liveness; - // Mark locals without storage statements as always having live storage - live_locals.union(&ignored.0); + storage_liveness.union(&ignored.0); - if !movable { - // For immovable generators we consider borrowed locals to always be live. - // This effectively makes those locals use just the storage liveness. - liveness.outs[block].union(&borrowed_locals.0); - } + // Locals live are live at this point only if they are used across + // suspension points (the `liveness` variable) + // and their storage is live (the `storage_liveness` variable) + storage_liveness.intersect(&liveness.outs[block]); - // Locals live are live at this point only if they are used across suspension points - // and their storage is live - live_locals.intersect(&liveness.outs[block]); + let live_locals = storage_liveness; // Add the locals life at this suspension point to the set of locals which live across // any suspension points diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 781eeaef2482c..2e45e3b1f3521 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -150,15 +150,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> { } fn visit_pat(&mut self, pat: &'tcx Pat) { + intravisit::walk_pat(self, pat); + + self.expr_count += 1; + if let PatKind::Binding(..) = pat.node { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.tables.borrow().pat_ty(pat); self.record(ty, Some(scope), None, pat.span); } - - self.expr_count += 1; - - intravisit::walk_pat(self, pat); } fn visit_expr(&mut self, expr: &'tcx Expr) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9b24c09036bce..098a98a8d92f3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1001,7 +1001,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let span = body.value.span; if body.is_generator && can_be_generator.is_some() { - fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + fcx.yield_ty = Some(yield_ty); } GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 2be93c07d5ad7..7fbe781e9a1f6 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -112,6 +112,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { keywords::Unsafe.name(), keywords::While.name(), keywords::Yield.name(), + keywords::Static.name(), ].contains(&ident.name) } diff --git a/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs b/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs new file mode 100644 index 0000000000000..2314533a68153 --- /dev/null +++ b/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs @@ -0,0 +1,28 @@ +// Copyright 2018 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)] + +fn main() { + unsafe { + static move || { + // Tests that the generator transformation finds out that `a` is not live + // during the yield expression. Type checking will also compute liveness + // and it should also find out that `a` is not live. + // The compiler will panic if the generator transformation finds that + // `a` is live and type checking finds it dead. + let a = { + yield (); + 4i32 + }; + &a; + }; + } +} diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr index 0a52a928f69d4..0f7d2e540d80a 100644 --- a/src/test/ui/generator/generator-with-nll.stderr +++ b/src/test/ui/generator/generator-with-nll.stderr @@ -1,12 +1,3 @@ -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/generator-with-nll.rs:20:17 - | -20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast) - | ^^^^^^^^^ -21 | //~^ borrow may still be in use when generator yields (Mir) -22 | yield (); - | -------- possible yield occurs here - error[E0626]: borrow may still be in use when generator yields (Ast) --> $DIR/generator-with-nll.rs:19:23 | @@ -25,5 +16,14 @@ error[E0626]: borrow may still be in use when generator yields (Ast) 22 | yield (); | -------- possible yield occurs here +error[E0626]: borrow may still be in use when generator yields (Mir) + --> $DIR/generator-with-nll.rs:20:17 + | +20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast) + | ^^^^^^^^^ +21 | //~^ borrow may still be in use when generator yields (Mir) +22 | yield (); + | -------- possible yield occurs here + error: aborting due to 3 previous errors diff --git a/src/test/ui/generator/pattern-borrow.rs b/src/test/ui/generator/pattern-borrow.rs new file mode 100644 index 0000000000000..557a5e62f7e46 --- /dev/null +++ b/src/test/ui/generator/pattern-borrow.rs @@ -0,0 +1,23 @@ +// Copyright 2018 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)] + +enum Test { A(i32), B, } + +fn main() { } + +fn fun(test: Test) { + move || { + if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields + yield (); + } + }; +} diff --git a/src/test/ui/generator/pattern-borrow.stderr b/src/test/ui/generator/pattern-borrow.stderr new file mode 100644 index 0000000000000..6b39b272d0e42 --- /dev/null +++ b/src/test/ui/generator/pattern-borrow.stderr @@ -0,0 +1,10 @@ +error[E0626]: borrow may still be in use when generator yields + --> $DIR/pattern-borrow.rs:19:24 + | +19 | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields + | ^^^^^^ +20 | yield (); + | -------- possible yield occurs here + +error: aborting due to previous error + diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs new file mode 100644 index 0000000000000..f38ebf8b94636 --- /dev/null +++ b/src/test/ui/generator/sized-yield.rs @@ -0,0 +1,21 @@ +// Copyright 2018 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)] + +use std::ops::Generator; + +fn main() { + let s = String::from("foo"); + let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + yield s[..]; + }; + gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +} diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr new file mode 100644 index 0000000000000..7adb2cc5598dc --- /dev/null +++ b/src/test/ui/generator/sized-yield.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied + --> $DIR/sized-yield.rs:17:26 + | +17 | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | __________________________^ +18 | | yield s[..]; +19 | | }; + | |____^ `str` does not have a constant size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: the yield type of a generator must have a statically known size + +error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied + --> $DIR/sized-yield.rs:20:8 + | +20 | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | ^^^^^^ `str` does not have a constant size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 7961dd9744136..114fe8ffcab0e 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -1,12 +1,3 @@ -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/yield-while-local-borrowed.rs:24:17 - | -24 | let a = &mut 3; - | ^^^^^^ -... -27 | yield(); - | ------- possible yield occurs here - error[E0626]: borrow may still be in use when generator yields (Ast) --> $DIR/yield-while-local-borrowed.rs:24:22 | @@ -25,6 +16,15 @@ error[E0626]: borrow may still be in use when generator yields (Ast) 55 | yield(); | ------- possible yield occurs here +error[E0626]: borrow may still be in use when generator yields (Mir) + --> $DIR/yield-while-local-borrowed.rs:24:17 + | +24 | let a = &mut 3; + | ^^^^^^ +... +27 | yield(); + | ------- possible yield occurs here + error[E0626]: borrow may still be in use when generator yields (Mir) --> $DIR/yield-while-local-borrowed.rs:52:21 |