From 58a59e9d231e36e3d39dd398b80c96094de591aa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 Aug 2017 11:13:01 +0200 Subject: [PATCH] Rustup (generator support) --- src/librustc_mir/interpret/eval_context.rs | 27 +++++--- src/librustc_mir/interpret/terminator/mod.rs | 9 ++- src/librustc_mir/interpret/validation.rs | 6 +- tests/run-pass/generator_control_flow.rs | 65 ++++++++++++++++++++ 4 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 tests/run-pass/generator_control_flow.rs diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b123ad7fd0b..b3d2617c9a3 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -480,15 +480,22 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local // `Value` for that. - let annotated_locals = collect_storage_annotations(mir); let num_locals = mir.local_decls.len() - 1; - let mut locals = vec![None; num_locals]; - for i in 0..num_locals { - let local = mir::Local::new(i + 1); - if !annotated_locals.contains(&local) { - locals[i] = Some(Value::ByVal(PrimVal::Undef)); + + // FIXME: generators produce broken storage annotations (https://github.com/rust-lang/rust/issues/44179) + let locals = if mir.generator_layout.is_some() { + vec![Some(Value::ByVal(PrimVal::Undef)); num_locals] + } else { + let annotated_locals = collect_storage_annotations(mir); + let mut locals = vec![None; num_locals]; + for i in 0..num_locals { + let local = mir::Local::new(i + 1); + if !annotated_locals.contains(&local) { + locals[i] = Some(Value::ByVal(PrimVal::Undef)); + } } - } + locals + }; self.stack.push(Frame { mir, @@ -2426,6 +2433,12 @@ fn resolve_associated_item<'a, 'tcx>( let substs = tcx.erase_regions(&substs); ty::Instance::new(def_id, substs) } + ::rustc::traits::VtableGenerator(closure_data) => { + ty::Instance { + def: ty::InstanceDef::Item(closure_data.closure_def_id), + substs: closure_data.substs.substs + } + } ::rustc::traits::VtableClosure(closure_data) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); resolve_closure( diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index ebd6649c447..bee0fe23f7f 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -137,8 +137,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { if expected == cond_val { self.goto_block(target); } else { + use rustc::mir::AssertMessage::*; return match *msg { - mir::AssertMessage::BoundsCheck { ref len, ref index } => { + BoundsCheck { ref len, ref index } => { let span = terminator.source_info.span; let len = self.eval_operand_to_primval(len) .expect("can't eval len") @@ -148,13 +149,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { .to_u64()?; err!(ArrayIndexOutOfBounds(span, len, index)) } - mir::AssertMessage::Math(ref err) => { + Math(ref err) => { err!(Math(terminator.source_info.span, err.clone())) } + GeneratorResumedAfterReturn | + GeneratorResumedAfterPanic => unimplemented!(), }; } } + Yield { .. } => unimplemented!("{:#?}", terminator.kind), + GeneratorDrop => unimplemented!(), DropAndReplace { .. } => unimplemented!(), Resume => unimplemented!(), Unreachable => return err!(Unreachable), diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs index 6454e12e037..63872f3c9c6 100644 --- a/src/librustc_mir/interpret/validation.rs +++ b/src/librustc_mir/interpret/validation.rs @@ -355,7 +355,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, TyAdt(adt, _) if adt.is_box() => true, TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | - TyDynamic(..) => false, + TyDynamic(..) | TyGenerator(..) => false, TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { bug!("I got an incomplete/unnormalized type for validation") } @@ -630,7 +630,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Is there other things we can/should check? Like vtable pointers? Ok(()) } - _ => bug!("We already establishd that this is a type we support."), + // FIXME: generators aren't validated right now + TyGenerator(..) => Ok(()), + _ => bug!("We already established that this is a type we support. ({})", query.ty), } } } diff --git a/tests/run-pass/generator_control_flow.rs b/tests/run-pass/generator_control_flow.rs new file mode 100644 index 00000000000..f15c7db9c20 --- /dev/null +++ b/tests/run-pass/generator_control_flow.rs @@ -0,0 +1,65 @@ +// 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)] + +use std::ops::{GeneratorState, Generator}; + +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Generator +{ + loop { + match t.resume() { + GeneratorState::Yielded(()) => amt -= 1, + GeneratorState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } + +} + +fn main() { + finish(1, || yield); + finish(3, || { + let mut x = 0; + yield; + x += 1; + yield; + x += 1; + yield; + assert_eq!(x, 2); + }); + finish(8, || { + for _ in 0..8 { + yield; + } + }); + finish(1, || { + if true { + yield; + } else { + } + }); + finish(1, || { + if false { + } else { + yield; + } + }); + finish(2, || { + if { yield; false } { + yield; + panic!() + } + yield + }); +}