From 8878a4030acf5285a48e7e248e5f96e4d01060ec Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 28 Feb 2017 12:35:00 +0100 Subject: [PATCH 1/8] rustup to rustc 1.17.0-nightly (60a0edc6c 2017-02-26) --- src/eval_context.rs | 17 +- src/memory.rs | 29 ++- src/terminator/mod.rs | 230 +++++++++++------- src/traits.rs | 23 +- .../run-pass/non_capture_closure_to_fn_ptr.rs | 16 ++ tests/run-pass/recursive_static.rs | 2 - 6 files changed, 215 insertions(+), 102 deletions(-) create mode 100644 tests/run-pass/non_capture_closure_to_fn_ptr.rs diff --git a/src/eval_context.rs b/src/eval_context.rs index 0ab6e85e38..1a1102c13a 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -649,16 +649,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, UnsafeFnPointer => match dest_ty.sty { - ty::TyFnPtr(unsafe_fn_ty) => { + ty::TyFnPtr(_) => { let src = self.eval_operand(operand)?; - let ptr = src.read_ptr(&self.memory)?; - let fn_def = self.memory.get_fn(ptr.alloc_id)?.expect_concrete()?; - let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty); - let fn_ptr = self.memory.create_fn_ptr(self.tcx, fn_def.def_id, fn_def.substs, unsafe_fn_ty); - self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; + self.write_value(src, dest, dest_ty)?; }, ref other => bug!("fn to unsafe fn cast on {:?}", other), }, + + ClosureFnPointer => match self.operand_ty(operand).sty { + ty::TyClosure(def_id, substs) => { + let fn_ty = self.tcx.closure_type(def_id, substs); + let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(self.tcx, def_id, substs, fn_ty); + self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; + }, + ref other => bug!("reify fn pointer on {:?}", other), + }, } } diff --git a/src/memory.rs b/src/memory.rs index 459a9bed41..fd035b7fcb 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -130,15 +130,11 @@ pub enum Function<'tcx> { FnPtrAsTraitObject(&'tcx ty::FnSig<'tcx>), /// Glue for Closures Closure(FunctionDefinition<'tcx>), + /// Glue for noncapturing closures casted to function pointers + NonCaptureClosureAsFnPtr(FunctionDefinition<'tcx>), } impl<'tcx> Function<'tcx> { - pub fn expect_concrete(self) -> EvalResult<'tcx, FunctionDefinition<'tcx>> { - match self { - Function::Concrete(fn_def) => Ok(fn_def), - other => Err(EvalError::ExpectedConcreteFunction(other)), - } - } pub fn expect_drop_glue_real_ty(self) -> EvalResult<'tcx, ty::Ty<'tcx>> { match self { Function::DropGlue(real_ty) => Ok(real_ty), @@ -238,6 +234,23 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { })) } + pub fn create_fn_ptr_from_noncapture_closure(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer { + // FIXME: this is a hack + let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + unsafety: fn_ty.unsafety, + abi: fn_ty.abi, + sig: fn_ty.sig, + }); + self.create_fn_alloc(Function::NonCaptureClosureAsFnPtr(FunctionDefinition { + def_id, + substs: substs.substs, + abi: Abi::Rust, // adjust abi + // FIXME: why doesn't this compile? + //sig: tcx.erase_late_bound_regions(&fn_ty.sig), + sig: fn_ty.sig.skip_binder(), + })) + } + pub fn create_fn_as_trait_glue(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer { self.create_fn_alloc(Function::FnDefAsTraitObject(FunctionDefinition { def_id, @@ -535,6 +548,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { trace!("{} closure glue for {}", msg, dump_fn_def(fn_def)); continue; }, + (None, Some(&Function::NonCaptureClosureAsFnPtr(fn_def))) => { + trace!("{} non-capture closure as fn ptr glue for {}", msg, dump_fn_def(fn_def)); + continue; + }, (None, None) => { trace!("{} (deallocated)", msg); continue; diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 183a3f54fb..0befb5ba9f 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -2,14 +2,14 @@ use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::layout::Layout; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, BareFnTy}; +use rustc::ty::{self, Ty}; use syntax::codemap::Span; use syntax::attr; use error::{EvalError, EvalResult}; use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited}; use lvalue::Lvalue; -use memory::{Pointer, FunctionDefinition}; +use memory::{Pointer, FunctionDefinition, Function}; use value::PrimVal; use value::Value; @@ -61,35 +61,54 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; let func_ty = self.operand_ty(func); - match func_ty.sty { + let fn_def = match func_ty.sty { ty::TyFnPtr(bare_fn_ty) => { let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; - let FunctionDefinition {def_id, substs, abi, sig} = self.memory.get_fn(fn_ptr.alloc_id)?.expect_concrete()?; + let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?; let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig); let bare_sig = self.tcx.erase_regions(&bare_sig); - // transmuting function pointers in miri is fine as long as the number of - // arguments and the abi don't change. - // FIXME: also check the size of the arguments' type and the return type - // Didn't get it to work, since that triggers an assertion in rustc which - // checks whether the type has escaping regions - if abi != bare_fn_ty.abi || - sig.variadic != bare_sig.variadic || - sig.inputs().len() != bare_sig.inputs().len() { - return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty)); + match fn_def { + Function::Concrete(fn_def) => { + // transmuting function pointers in miri is fine as long as the number of + // arguments and the abi don't change. + // FIXME: also check the size of the arguments' type and the return type + // Didn't get it to work, since that triggers an assertion in rustc which + // checks whether the type has escaping regions + if fn_def.abi != bare_fn_ty.abi || + fn_def.sig.variadic != bare_sig.variadic || + fn_def.sig.inputs().len() != bare_sig.inputs().len() { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + } + }, + Function::NonCaptureClosureAsFnPtr(fn_def) => { + if fn_def.abi != bare_fn_ty.abi || + fn_def.sig.variadic != bare_sig.variadic || + fn_def.sig.inputs().len() != 1 { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + } + if let ty::TyTuple(fields, _) = fn_def.sig.inputs()[0].sty { + if fields.len() != bare_sig.inputs().len() { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + } + } + }, + other => return Err(EvalError::ExpectedConcreteFunction(other)), } - self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args, - terminator.source_info.span)? + self.memory.get_fn(fn_ptr.alloc_id)? }, - ty::TyFnDef(def_id, substs, fn_ty) => { - self.eval_fn_call(def_id, substs, fn_ty, destination, args, - terminator.source_info.span)? - } + ty::TyFnDef(def_id, substs, fn_ty) => Function::Concrete(FunctionDefinition { + def_id, + substs, + abi: fn_ty.abi, + sig: fn_ty.sig.skip_binder(), + }), _ => { let msg = format!("can't handle callee of type {:?}", func_ty); return Err(EvalError::Unimplemented(msg)); } - } + }; + self.eval_fn_call(fn_def, destination, args, terminator.source_info.span)?; } Drop { ref location, target, .. } => { @@ -138,17 +157,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn eval_fn_call( &mut self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - fn_ty: &'tcx BareFnTy, + fn_def: Function<'tcx>, destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, ) -> EvalResult<'tcx> { use syntax::abi::Abi; - match fn_ty.abi { - Abi::RustIntrinsic => { - let ty = fn_ty.sig.0.output(); + match fn_def { + // Intrinsics can only be addressed directly + Function::Concrete(FunctionDefinition { def_id, substs, abi: Abi::RustIntrinsic, sig }) => { + let ty = sig.output(); let layout = self.type_layout(ty)?; let (ret, target) = match destination { Some(dest) if is_inhabited(self.tcx, ty) => dest, @@ -157,18 +175,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?; self.dump_local(ret); Ok(()) - } - - Abi::C => { - let ty = fn_ty.sig.0.output(); + }, + // C functions can only be addressed directly + Function::Concrete(FunctionDefinition { def_id, abi: Abi::C, sig, ..}) => { + let ty = sig.output(); let (ret, target) = destination.unwrap(); self.call_c_abi(def_id, arg_operands, ret, ty)?; self.dump_local(ret); self.goto_block(target); Ok(()) - } - - Abi::Rust | Abi::RustCall => { + }, + Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), + Function::Concrete(FunctionDefinition { def_id, abi: Abi::RustCall, sig, substs }) | + Function::Concrete(FunctionDefinition { def_id, abi: Abi::Rust, sig, substs }) => { let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; @@ -185,7 +204,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; // FIXME(eddyb) Detect ADT constructors more efficiently. - if let Some(adt_def) = fn_ty.sig.skip_binder().output().ty_adt_def() { + if let Some(adt_def) = sig.output().ty_adt_def() { if let Some(v) = adt_def.variants.iter().find(|v| resolved_def_id == v.did) { let (lvalue, target) = destination.expect("tuple struct constructors can't diverge"); let dest_ty = self.tcx.item_type(adt_def.did); @@ -240,66 +259,105 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { return Ok(()); } } - - let mir = match self.load_mir(resolved_def_id) { - Ok(mir) => mir, - Err(EvalError::NoMirFor(path)) => { - match &path[..] { - // let's just ignore all output for now - "std::io::_print" => { - self.goto_block(destination.unwrap().1); - return Ok(()); - }, - "std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())), - "std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())), - "std::panicking::rust_panic_with_hook" | - "std::rt::begin_panic_fmt" => return Err(EvalError::Panic), - "std::panicking::panicking" | - "std::rt::panicking" => { - let (lval, block) = destination.expect("std::rt::panicking does not diverge"); - // we abort on panic -> `std::rt::panicking` always returns false - let bool = self.tcx.types.bool; - self.write_primval(lval, PrimVal::from_bool(false), bool)?; - self.goto_block(block); - return Ok(()); - } - _ => {}, - } - return Err(EvalError::NoMirFor(path)); - }, - Err(other) => return Err(other), - }; - let (return_lvalue, return_to_block) = match destination { - Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), - None => { - // FIXME(solson) - let lvalue = Lvalue::from_ptr(Pointer::never_ptr()); - (lvalue, StackPopCleanup::None) - } - }; - - self.push_stack_frame( + self.eval_fn_call_inner( resolved_def_id, - span, - mir, resolved_substs, - return_lvalue, - return_to_block, + destination, + args, temporaries, - )?; - - let arg_locals = self.frame().mir.args_iter(); - assert_eq!(self.frame().mir.arg_count, args.len()); - for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) { - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - self.write_value(arg_val, dest, arg_ty)?; + span, + ) + }, + Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, abi: Abi::Rust, substs, sig }) => { + let mut args = Vec::new(); + for arg in arg_operands { + let arg_val = self.eval_operand(arg)?; + let arg_ty = self.operand_ty(arg); + args.push((arg_val, arg_ty)); } + args.insert(0, ( + Value::ByVal(PrimVal::Undef), + sig.inputs()[0], + )); + self.eval_fn_call_inner( + def_id, + substs, + destination, + args, + Vec::new(), + span, + ) + } + other => Err(EvalError::Unimplemented(format!("can't call function kind {:?}", other))), + } + } - Ok(()) + fn eval_fn_call_inner( + &mut self, + resolved_def_id: DefId, + resolved_substs: &'tcx Substs, + destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + args: Vec<(Value, Ty<'tcx>)>, + temporaries: Vec<(Pointer, Ty<'tcx>)>, + span: Span, + ) -> EvalResult<'tcx> { + trace!("eval_fn_call_inner: {:#?}, {:#?}, {:#?}", args, temporaries, destination); + + let mir = match self.load_mir(resolved_def_id) { + Ok(mir) => mir, + Err(EvalError::NoMirFor(path)) => { + match &path[..] { + // let's just ignore all output for now + "std::io::_print" => { + self.goto_block(destination.unwrap().1); + return Ok(()); + }, + "std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())), + "std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())), + "std::panicking::rust_panic_with_hook" | + "std::rt::begin_panic_fmt" => return Err(EvalError::Panic), + "std::panicking::panicking" | + "std::rt::panicking" => { + let (lval, block) = destination.expect("std::rt::panicking does not diverge"); + // we abort on panic -> `std::rt::panicking` always returns false + let bool = self.tcx.types.bool; + self.write_primval(lval, PrimVal::from_bool(false), bool)?; + self.goto_block(block); + return Ok(()); + } + _ => {}, + } + return Err(EvalError::NoMirFor(path)); + }, + Err(other) => return Err(other), + }; + let (return_lvalue, return_to_block) = match destination { + Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), + None => { + // FIXME(solson) + let lvalue = Lvalue::from_ptr(Pointer::never_ptr()); + (lvalue, StackPopCleanup::None) } + }; - abi => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))), + self.push_stack_frame( + resolved_def_id, + span, + mir, + resolved_substs, + return_lvalue, + return_to_block, + temporaries, + )?; + + let arg_locals = self.frame().mir.args_iter(); + assert_eq!(self.frame().mir.arg_count, args.len()); + for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) { + let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; + self.write_value(arg_val, dest, arg_ty)?; } + + Ok(()) } pub fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { diff --git a/src/traits.rs b/src/traits.rs index 733095322d..36293dde53 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -130,6 +130,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ); Ok((fn_def.def_id, fn_def.substs, Vec::new())) }, + Function::NonCaptureClosureAsFnPtr(fn_def) => { + args.insert(0, ( + Value::ByVal(PrimVal::Undef), + fn_def.sig.inputs()[0], + )); + Ok((fn_def.def_id, fn_def.substs, Vec::new())) + } Function::Closure(fn_def) => { self.unpack_fn_args(args)?; Ok((fn_def.def_id, fn_def.substs, Vec::new())) @@ -140,8 +147,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { args.remove(0); self.unpack_fn_args(args)?; let fn_ptr = self.memory.read_ptr(self_ptr)?; - let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?.expect_concrete()?; - assert_eq!(sig, fn_def.sig); + let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? { + Function::Concrete(fn_def) => { + assert_eq!(sig, fn_def.sig); + fn_def + }, + Function::NonCaptureClosureAsFnPtr(fn_def) => { + args.insert(0, ( + Value::ByVal(PrimVal::Undef), + fn_def.sig.inputs()[0], + )); + fn_def + }, + other => bug!("FnPtrAsTraitObject for {:?}", other), + }; Ok((fn_def.def_id, fn_def.substs, Vec::new())) } } diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs new file mode 100644 index 0000000000..6f73a3d09d --- /dev/null +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -0,0 +1,16 @@ +#![feature(closure_to_fn_coercion)] + +// allow(const_err) to work around a bug in warnings +#[allow(const_err)] +static FOO: fn() = || { assert_ne!(42, 43) }; +#[allow(const_err)] +static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; + +fn main() { + FOO(); + BAR(44, 45); + let bar: unsafe fn(i32, i32) = BAR; + unsafe { bar(46, 47) }; + let boo: &Fn(i32, i32) = &BAR; + boo(48, 49); +} diff --git a/tests/run-pass/recursive_static.rs b/tests/run-pass/recursive_static.rs index 5b27324964..77f2902917 100644 --- a/tests/run-pass/recursive_static.rs +++ b/tests/run-pass/recursive_static.rs @@ -1,5 +1,3 @@ -#![feature(static_recursion)] - struct S(&'static S); static S1: S = S(&S2); static S2: S = S(&S1); From 8405770b5196914dd397877c0447756a6b41fb2b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Mar 2017 13:11:33 +0100 Subject: [PATCH 2/8] Rustup to rustc 1.17.0-nightly (be760566c 2017-02-28) --- src/error.rs | 9 +++-- src/eval_context.rs | 25 +++++++------ src/memory.rs | 60 ++++++++----------------------- src/terminator/drop.rs | 4 +-- src/terminator/mod.rs | 55 ++++++++++++++-------------- src/traits.rs | 20 +++++------ tests/compile-fail/cast_fn_ptr.rs | 2 +- 7 files changed, 71 insertions(+), 104 deletions(-) diff --git a/src/error.rs b/src/error.rs index 72eedba5e3..34b672dda9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,15 +1,14 @@ use std::error::Error; use std::fmt; use rustc::mir; -use rustc::ty::{BareFnTy, Ty, FnSig, layout}; -use syntax::abi::Abi; +use rustc::ty::{PolyFnSig, Ty, layout}; use memory::{Pointer, Function}; use rustc_const_math::ConstMathErr; use syntax::codemap::Span; #[derive(Clone, Debug)] pub enum EvalError<'tcx> { - FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>), + FunctionPointerTyMismatch(PolyFnSig<'tcx>, PolyFnSig<'tcx>), NoMirFor(String), UnterminatedCString(Pointer), DanglingPointerDeref, @@ -151,8 +150,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size) }, EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func), - EvalError::FunctionPointerTyMismatch(abi, sig, got) => - write!(f, "tried to call a function with abi {:?} and sig {:?} through a function pointer of type {:?}", abi, sig, got), + EvalError::FunctionPointerTyMismatch(sig, got) => + write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig.skip_binder(), got.skip_binder()), EvalError::ArrayIndexOutOfBounds(span, len, index) => write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span), EvalError::Math(span, ref err) => diff --git a/src/eval_context.rs b/src/eval_context.rs index 1a1102c13a..9b23b849fc 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -181,8 +181,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Float(ConstFloat::F32(f)) => PrimVal::from_f32(f), Float(ConstFloat::F64(f)) => PrimVal::from_f64(f), - Float(ConstFloat::FInfer { .. }) => - bug!("uninferred constants only exist before typeck"), Bool(b) => PrimVal::from_bool(b), Char(c) => PrimVal::from_char(c), @@ -196,7 +194,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Struct(_) => unimplemented!(), Tuple(_) => unimplemented!(), - Function(_) => unimplemented!(), + Function(_, _) => unimplemented!(), Array(_) => unimplemented!(), Repeat(_, _) => unimplemented!(), }; @@ -457,7 +455,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { General { discr, ref variants, .. } => { if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { - let discr_val = adt_def.variants[variant].disr_val; + let discr_val = adt_def.discriminants(self.tcx) + .nth(variant) + .expect("broken mir: Adt variant id invalid") + .to_u128_unchecked(); let discr_size = discr.size().bytes(); if variants[variant].packed { let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0; @@ -530,7 +531,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { CEnum { .. } => { assert_eq!(operands.len(), 0); if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { - let n = adt_def.variants[variant].disr_val; + let n = adt_def.discriminants(self.tcx) + .nth(variant) + .expect("broken mir: Adt variant index invalid") + .to_u128_unchecked(); self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?; } else { bug!("tried to assign {:?} to Layout::CEnum", kind); @@ -640,9 +644,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } ReifyFnPointer => match self.operand_ty(operand).sty { - ty::TyFnDef(def_id, substs, fn_ty) => { - let fn_ty = self.tcx.erase_regions(&fn_ty); - let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty); + ty::TyFnDef(def_id, substs, sig) => { + let fn_ptr = self.memory.create_fn_ptr(def_id, substs, sig); self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("reify fn pointer on {:?}", other), @@ -658,8 +661,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ClosureFnPointer => match self.operand_ty(operand).sty { ty::TyClosure(def_id, substs) => { - let fn_ty = self.tcx.closure_type(def_id, substs); - let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(self.tcx, def_id, substs, fn_ty); + let fn_ty = self.tcx.closure_type(def_id); + let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(def_id, substs, fn_ty); self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("reify fn pointer on {:?}", other), @@ -673,7 +676,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let ptr = self.force_allocation(lval)?.to_ptr(); let discr_val = self.read_discriminant_value(ptr, ty)?; if let ty::TyAdt(adt_def, _) = ty.sty { - if adt_def.variants.iter().all(|v| discr_val != v.disr_val) { + if adt_def.discriminants(self.tcx).all(|v| discr_val != v.to_u128_unchecked()) { return Err(EvalError::InvalidDiscriminant); } } else { diff --git a/src/memory.rs b/src/memory.rs index fd035b7fcb..44959ea672 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -3,12 +3,10 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque, BTreeSet use std::{fmt, iter, ptr, mem, io}; use rustc::hir::def_id::DefId; -use rustc::ty::{self, BareFnTy, ClosureTy, ClosureSubsts, TyCtxt}; +use rustc::ty::{self, PolyFnSig, ClosureSubsts}; use rustc::ty::subst::Substs; use rustc::ty::layout::{self, TargetDataLayout}; -use syntax::abi::Abi; - use error::{EvalError, EvalResult}; use value::PrimVal; @@ -109,8 +107,7 @@ impl Pointer { pub struct FunctionDefinition<'tcx> { pub def_id: DefId, pub substs: &'tcx Substs<'tcx>, - pub abi: Abi, - pub sig: &'tcx ty::FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, } /// Either a concrete function, or a glue function @@ -127,7 +124,7 @@ pub enum Function<'tcx> { DropGlue(ty::Ty<'tcx>), /// Glue required to treat the ptr part of a fat pointer /// as a function pointer - FnPtrAsTraitObject(&'tcx ty::FnSig<'tcx>), + FnPtrAsTraitObject(PolyFnSig<'tcx>), /// Glue for Closures Closure(FunctionDefinition<'tcx>), /// Glue for noncapturing closures casted to function pointers @@ -217,67 +214,43 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { self.alloc_map.iter() } - pub fn create_closure_ptr(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer { - // FIXME: this is a hack - let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { - unsafety: fn_ty.unsafety, - abi: fn_ty.abi, - sig: fn_ty.sig, - }); + pub fn create_closure_ptr(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer { self.create_fn_alloc(Function::Closure(FunctionDefinition { def_id, substs: substs.substs, - abi: fn_ty.abi, - // FIXME: why doesn't this compile? - //sig: tcx.erase_late_bound_regions(&fn_ty.sig), - sig: fn_ty.sig.skip_binder(), + sig, })) } - pub fn create_fn_ptr_from_noncapture_closure(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ClosureSubsts<'tcx>, fn_ty: ClosureTy<'tcx>) -> Pointer { - // FIXME: this is a hack - let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { - unsafety: fn_ty.unsafety, - abi: fn_ty.abi, - sig: fn_ty.sig, - }); + pub fn create_fn_ptr_from_noncapture_closure(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer { self.create_fn_alloc(Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs: substs.substs, - abi: Abi::Rust, // adjust abi - // FIXME: why doesn't this compile? - //sig: tcx.erase_late_bound_regions(&fn_ty.sig), - sig: fn_ty.sig.skip_binder(), + sig, })) } - pub fn create_fn_as_trait_glue(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer { + pub fn create_fn_as_trait_glue(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer { self.create_fn_alloc(Function::FnDefAsTraitObject(FunctionDefinition { def_id, substs, - abi: fn_ty.abi, - // FIXME: why doesn't this compile? - //sig: tcx.erase_late_bound_regions(&fn_ty.sig), - sig: fn_ty.sig.skip_binder(), + sig, })) } - pub fn create_fn_ptr_as_trait_glue(&mut self, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer { - self.create_fn_alloc(Function::FnPtrAsTraitObject(fn_ty.sig.skip_binder())) + pub fn create_fn_ptr_as_trait_glue(&mut self, sig: PolyFnSig<'tcx>) -> Pointer { + self.create_fn_alloc(Function::FnPtrAsTraitObject(sig)) } pub fn create_drop_glue(&mut self, ty: ty::Ty<'tcx>) -> Pointer { self.create_fn_alloc(Function::DropGlue(ty)) } - pub fn create_fn_ptr(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer { + pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer { self.create_fn_alloc(Function::Concrete(FunctionDefinition { def_id, substs, - abi: fn_ty.abi, - // FIXME: why doesn't this compile? - //sig: tcx.erase_late_bound_regions(&fn_ty.sig), - sig: fn_ty.sig.skip_binder(), + sig, })) } @@ -623,12 +596,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { fn dump_fn_def<'tcx>(fn_def: FunctionDefinition<'tcx>) -> String { let name = ty::tls::with(|tcx| tcx.item_path_str(fn_def.def_id)); - let abi = if fn_def.abi == Abi::Rust { - format!("") - } else { - format!("extern {} ", fn_def.abi) - }; - format!("function pointer: {}: {}{}", name, abi, fn_def.sig) + format!("function pointer: {}: {}", name, fn_def.sig.skip_binder()) } /// Byte accessors diff --git a/src/terminator/drop.rs b/src/terminator/drop.rs index 289bae89c3..e8bd2164b8 100644 --- a/src/terminator/drop.rs +++ b/src/terminator/drop.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let (adt_ptr, extra) = lval.to_ptr_and_extra(); // run drop impl before the fields' drop impls - if let Some(drop_def_id) = adt_def.destructor() { + if let Some(drop_def_id) = adt_def.destructor(self.tcx) { let trait_ref = ty::Binder(ty::TraitRef { def_id: self.tcx.lang_items.drop_trait().unwrap(), substs: self.tcx.mk_substs_trait(ty, &[]), @@ -121,7 +121,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Layout::General { .. } => { let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128; let ptr = self.force_allocation(lval)?.to_ptr(); - match adt_def.variants.iter().position(|v| discr_val == v.disr_val) { + match adt_def.discriminants(self.tcx).position(|v| discr_val == v.to_u128_unchecked()) { Some(i) => { lval = Lvalue::Ptr { ptr, diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 0befb5ba9f..14392eda32 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -3,8 +3,10 @@ use rustc::mir; use rustc::ty::layout::Layout; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; +use rustc_const_math::ConstInt; use syntax::codemap::Span; use syntax::attr; +use syntax::abi::Abi; use error::{EvalError, EvalResult}; use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited}; @@ -62,11 +64,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let func_ty = self.operand_ty(func); let fn_def = match func_ty.sty { - ty::TyFnPtr(bare_fn_ty) => { + ty::TyFnPtr(bare_sig) => { let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?; - let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig); - let bare_sig = self.tcx.erase_regions(&bare_sig); match fn_def { Function::Concrete(fn_def) => { // transmuting function pointers in miri is fine as long as the number of @@ -74,21 +74,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // FIXME: also check the size of the arguments' type and the return type // Didn't get it to work, since that triggers an assertion in rustc which // checks whether the type has escaping regions - if fn_def.abi != bare_fn_ty.abi || - fn_def.sig.variadic != bare_sig.variadic || - fn_def.sig.inputs().len() != bare_sig.inputs().len() { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + if fn_def.sig.abi() != bare_sig.abi() || + fn_def.sig.variadic() != bare_sig.variadic() || + fn_def.sig.inputs().skip_binder().len() != bare_sig.inputs().skip_binder().len() { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); } }, Function::NonCaptureClosureAsFnPtr(fn_def) => { - if fn_def.abi != bare_fn_ty.abi || - fn_def.sig.variadic != bare_sig.variadic || - fn_def.sig.inputs().len() != 1 { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + assert_eq!(fn_def.sig.abi(), Abi::RustCall); + if fn_def.sig.variadic() != bare_sig.variadic() || + fn_def.sig.inputs().skip_binder().len() != 1 { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); } - if let ty::TyTuple(fields, _) = fn_def.sig.inputs()[0].sty { - if fields.len() != bare_sig.inputs().len() { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.abi, fn_def.sig, bare_fn_ty)); + if let ty::TyTuple(fields, _) = fn_def.sig.inputs().skip_binder()[0].sty { + if fields.len() != bare_sig.inputs().skip_binder().len() { + return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); } } }, @@ -99,8 +99,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TyFnDef(def_id, substs, fn_ty) => Function::Concrete(FunctionDefinition { def_id, substs, - abi: fn_ty.abi, - sig: fn_ty.sig.skip_binder(), + sig: fn_ty, }), _ => { @@ -165,8 +164,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { use syntax::abi::Abi; match fn_def { // Intrinsics can only be addressed directly - Function::Concrete(FunctionDefinition { def_id, substs, abi: Abi::RustIntrinsic, sig }) => { - let ty = sig.output(); + Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => { + let ty = *sig.output().skip_binder(); let layout = self.type_layout(ty)?; let (ret, target) = match destination { Some(dest) if is_inhabited(self.tcx, ty) => dest, @@ -177,8 +176,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(()) }, // C functions can only be addressed directly - Function::Concrete(FunctionDefinition { def_id, abi: Abi::C, sig, ..}) => { - let ty = sig.output(); + Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => { + let ty = *sig.output().skip_binder(); let (ret, target) = destination.unwrap(); self.call_c_abi(def_id, arg_operands, ret, ty)?; self.dump_local(ret); @@ -186,8 +185,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(()) }, Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), - Function::Concrete(FunctionDefinition { def_id, abi: Abi::RustCall, sig, substs }) | - Function::Concrete(FunctionDefinition { def_id, abi: Abi::Rust, sig, substs }) => { + Function::Concrete(FunctionDefinition { def_id, sig, substs }) if sig.abi() == Abi::Rust || sig.abi() == Abi::RustCall => { let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; @@ -204,20 +202,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; // FIXME(eddyb) Detect ADT constructors more efficiently. - if let Some(adt_def) = sig.output().ty_adt_def() { - if let Some(v) = adt_def.variants.iter().find(|v| resolved_def_id == v.did) { + if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() { + let dids = adt_def.variants.iter().map(|v| v.did); + let discrs = adt_def.discriminants(self.tcx).map(ConstInt::to_u128_unchecked); + if let Some((_, disr_val)) = dids.zip(discrs).find(|&(did, _)| resolved_def_id == did) { let (lvalue, target) = destination.expect("tuple struct constructors can't diverge"); let dest_ty = self.tcx.item_type(adt_def.did); let dest_layout = self.type_layout(dest_ty)?; trace!("layout({:?}) = {:#?}", dest_ty, dest_layout); match *dest_layout { Layout::Univariant { .. } => { - let disr_val = v.disr_val; assert_eq!(disr_val, 0); self.assign_fields(lvalue, dest_ty, args)?; }, Layout::General { discr, ref variants, .. } => { - let disr_val = v.disr_val; let discr_size = discr.size().bytes(); self.assign_discr_and_fields( lvalue, @@ -230,7 +228,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { )?; }, Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { - let disr_val = v.disr_val; if nndiscr as u128 == disr_val { self.assign_fields(lvalue, dest_ty, args)?; } else { @@ -268,7 +265,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { span, ) }, - Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, abi: Abi::Rust, substs, sig }) => { + Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => { let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; @@ -277,7 +274,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } args.insert(0, ( Value::ByVal(PrimVal::Undef), - sig.inputs()[0], + sig.inputs().skip_binder()[0], )); self.eval_fn_call_inner( def_id, diff --git a/src/traits.rs b/src/traits.rs index 36293dde53..986efc987d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match self.memory.get_fn(fn_ptr.alloc_id)? { Function::FnDefAsTraitObject(fn_def) => { trace!("sig: {:#?}", fn_def.sig); - assert!(fn_def.abi != abi::Abi::RustCall); + assert!(fn_def.sig.abi() != abi::Abi::RustCall); assert_eq!(args.len(), 2); // a function item turned into a closure trait object // the first arg is just there to give use the vtable @@ -126,14 +126,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { trace!("sig: {:#?}", fn_def.sig); args[0] = ( Value::ByVal(PrimVal::Ptr(self_ptr)), - fn_def.sig.inputs()[0], + fn_def.sig.inputs().skip_binder()[0], ); Ok((fn_def.def_id, fn_def.substs, Vec::new())) }, Function::NonCaptureClosureAsFnPtr(fn_def) => { args.insert(0, ( Value::ByVal(PrimVal::Undef), - fn_def.sig.inputs()[0], + fn_def.sig.inputs().skip_binder()[0], )); Ok((fn_def.def_id, fn_def.substs, Vec::new())) } @@ -155,7 +155,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Function::NonCaptureClosureAsFnPtr(fn_def) => { args.insert(0, ( Value::ByVal(PrimVal::Undef), - fn_def.sig.inputs()[0], + fn_def.sig.inputs().skip_binder()[0], )); fn_def }, @@ -220,7 +220,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ => bug!("bad function type: {}", fn_ty), }; let fn_ty = self.tcx.erase_regions(&fn_ty); - self.memory.create_fn_ptr(self.tcx, mth.method.def_id, mth.substs, fn_ty) + self.memory.create_fn_ptr(mth.method.def_id, mth.substs, fn_ty) })) .collect::>() .into_iter() @@ -233,15 +233,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { .. } ) => { - let closure_type = self.tcx.closure_type(closure_def_id, substs); - vec![Some(self.memory.create_closure_ptr(self.tcx, closure_def_id, substs, closure_type))].into_iter() + let closure_type = self.tcx.closure_type(closure_def_id); + vec![Some(self.memory.create_closure_ptr(closure_def_id, substs, closure_type))].into_iter() } // turn a function definition into a Fn trait object traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, .. }) => { match fn_ty.sty { ty::TyFnDef(did, substs, bare_fn_ty) => { - vec![Some(self.memory.create_fn_as_trait_glue(self.tcx, did, substs, bare_fn_ty))].into_iter() + vec![Some(self.memory.create_fn_as_trait_glue(did, substs, bare_fn_ty))].into_iter() }, ty::TyFnPtr(bare_fn_ty) => { vec![Some(self.memory.create_fn_ptr_as_trait_glue(bare_fn_ty))].into_iter() @@ -275,13 +275,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // in case there is no drop function to be called, this still needs to be initialized self.memory.write_usize(vtable, 0)?; if let ty::TyAdt(adt_def, substs) = trait_ref.self_ty().sty { - if let Some(drop_def_id) = adt_def.destructor() { + if let Some(drop_def_id) = adt_def.destructor(self.tcx) { let fn_ty = match self.tcx.item_type(drop_def_id).sty { ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty), _ => bug!("drop method is not a TyFnDef"), }; // The real type is taken from the self argument in `fn drop(&mut self)` - let real_ty = match fn_ty.sig.skip_binder().inputs()[0].sty { + let real_ty = match fn_ty.inputs().skip_binder()[0].sty { ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs), _ => bug!("first argument of Drop::drop must be &mut T"), }; diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index c8070913f1..7509ae6ed7 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with abi Rust and sig + g(42) //~ ERROR tried to call a function with sig fn() through a function pointer of type fn(i32) } From 41d59b117aa87c3c54c298a0fd49aaf3d00242bc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Mar 2017 12:49:56 +0100 Subject: [PATCH 3/8] Rustup to rustc 1.17.0-nightly (b1e31766d 2017-03-03) --- src/terminator/drop.rs | 4 ++-- src/traits.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/terminator/drop.rs b/src/terminator/drop.rs index e8bd2164b8..efa4156793 100644 --- a/src/terminator/drop.rs +++ b/src/terminator/drop.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let (adt_ptr, extra) = lval.to_ptr_and_extra(); // run drop impl before the fields' drop impls - if let Some(drop_def_id) = adt_def.destructor(self.tcx) { + if let Some(destructor) = adt_def.destructor(self.tcx) { let trait_ref = ty::Binder(ty::TraitRef { def_id: self.tcx.lang_items.drop_trait().unwrap(), substs: self.tcx.mk_substs_trait(ty, &[]), @@ -112,7 +112,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { LvalueExtra::Length(n) => Value::ByValPair(PrimVal::Ptr(adt_ptr), PrimVal::from_u128(n as u128)), LvalueExtra::Vtable(vtable) => Value::ByValPair(PrimVal::Ptr(adt_ptr), PrimVal::Ptr(vtable)), }; - drop.push((drop_def_id, val, vtable.substs)); + drop.push((destructor.did, val, vtable.substs)); } let layout = self.type_layout(ty)?; diff --git a/src/traits.rs b/src/traits.rs index 986efc987d..e4f9e4a24a 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -275,8 +275,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // in case there is no drop function to be called, this still needs to be initialized self.memory.write_usize(vtable, 0)?; if let ty::TyAdt(adt_def, substs) = trait_ref.self_ty().sty { - if let Some(drop_def_id) = adt_def.destructor(self.tcx) { - let fn_ty = match self.tcx.item_type(drop_def_id).sty { + if let Some(destructor) = adt_def.destructor(self.tcx) { + let fn_ty = match self.tcx.item_type(destructor.did).sty { ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty), _ => bug!("drop method is not a TyFnDef"), }; From 4cb1f639b7efeb30c8ca3e2fa97a85355ecdb7ac Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 13 Mar 2017 11:28:45 +0100 Subject: [PATCH 4/8] Rustup to rustc 1.17.0-nightly (824c9ebbd 2017-03-12) --- src/lvalue.rs | 4 ++-- src/step.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lvalue.rs b/src/lvalue.rs index d4d292cd4e..8971f050a8 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -137,9 +137,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Local(mir::RETURN_POINTER) => self.frame().return_lvalue, Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local, field: None }, - Static(def_id) => { + Static(ref statik) => { let substs = self.tcx.intern_substs(&[]); - Lvalue::Global(GlobalId { def_id, substs, promoted: None }) + Lvalue::Global(GlobalId { def_id: statik.def_id, substs, promoted: None }) } Projection(ref proj) => return self.eval_lvalue_projection(proj), diff --git a/src/step.rs b/src/step.rs index c08ac9693a..ced709b3a9 100644 --- a/src/step.rs +++ b/src/step.rs @@ -242,7 +242,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { location: mir::Location ) { self.super_lvalue(lvalue, context, location); - if let mir::Lvalue::Static(def_id) = *lvalue { + if let mir::Lvalue::Static(ref statik) = *lvalue { + let def_id = statik.def_id; let substs = self.ecx.tcx.intern_substs(&[]); let span = self.span; if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) { From 64d196a9dc14b5cacf7ef12bf8dd691355d0ffc9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Mar 2017 09:23:15 +0100 Subject: [PATCH 5/8] Use deterministic keyword renaming (append `_`) --- src/lvalue.rs | 4 ++-- src/step.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lvalue.rs b/src/lvalue.rs index 8971f050a8..afdb5b392d 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -137,9 +137,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Local(mir::RETURN_POINTER) => self.frame().return_lvalue, Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local, field: None }, - Static(ref statik) => { + Static(ref static_) => { let substs = self.tcx.intern_substs(&[]); - Lvalue::Global(GlobalId { def_id: statik.def_id, substs, promoted: None }) + Lvalue::Global(GlobalId { def_id: static_.def_id, substs, promoted: None }) } Projection(ref proj) => return self.eval_lvalue_projection(proj), diff --git a/src/step.rs b/src/step.rs index ced709b3a9..23f0142a7f 100644 --- a/src/step.rs +++ b/src/step.rs @@ -242,8 +242,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { location: mir::Location ) { self.super_lvalue(lvalue, context, location); - if let mir::Lvalue::Static(ref statik) = *lvalue { - let def_id = statik.def_id; + if let mir::Lvalue::Static(ref static_) = *lvalue { + let def_id = static_.def_id; let substs = self.ecx.tcx.intern_substs(&[]); let span = self.span; if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) { From da6f1369972ad972c60270e073361f727b68d8a6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Mar 2017 10:49:22 +0100 Subject: [PATCH 6/8] I say we take off and nuke the lifetimes from orbit --- src/error.rs | 6 +-- src/terminator/mod.rs | 48 ++++++++++++++--------- src/traits.rs | 24 +++++++++--- tests/run-pass/rfc1623.rs | 81 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 tests/run-pass/rfc1623.rs diff --git a/src/error.rs b/src/error.rs index 34b672dda9..370d59e5a3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,14 +1,14 @@ use std::error::Error; use std::fmt; use rustc::mir; -use rustc::ty::{PolyFnSig, Ty, layout}; +use rustc::ty::{FnSig, Ty, layout}; use memory::{Pointer, Function}; use rustc_const_math::ConstMathErr; use syntax::codemap::Span; #[derive(Clone, Debug)] pub enum EvalError<'tcx> { - FunctionPointerTyMismatch(PolyFnSig<'tcx>, PolyFnSig<'tcx>), + FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), NoMirFor(String), UnterminatedCString(Pointer), DanglingPointerDeref, @@ -151,7 +151,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { }, EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func), EvalError::FunctionPointerTyMismatch(sig, got) => - write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig.skip_binder(), got.skip_binder()), + write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got), EvalError::ArrayIndexOutOfBounds(span, len, index) => write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span), EvalError::Math(span, ref err) => diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 14392eda32..b0e7b76ae1 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -65,31 +65,36 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let func_ty = self.operand_ty(func); let fn_def = match func_ty.sty { ty::TyFnPtr(bare_sig) => { + let bare_sig = self.tcx.erase_late_bound_regions(&bare_sig); + let bare_sig = self.tcx.erase_regions(&bare_sig); let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?; match fn_def { Function::Concrete(fn_def) => { // transmuting function pointers in miri is fine as long as the number of // arguments and the abi don't change. - // FIXME: also check the size of the arguments' type and the return type - // Didn't get it to work, since that triggers an assertion in rustc which - // checks whether the type has escaping regions - if fn_def.sig.abi() != bare_sig.abi() || - fn_def.sig.variadic() != bare_sig.variadic() || - fn_def.sig.inputs().skip_binder().len() != bare_sig.inputs().skip_binder().len() { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); + let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let sig = self.tcx.erase_regions(&sig); + if sig.abi != bare_sig.abi || + sig.variadic != bare_sig.variadic || + sig.inputs_and_output != bare_sig.inputs_and_output { + return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); } }, Function::NonCaptureClosureAsFnPtr(fn_def) => { - assert_eq!(fn_def.sig.abi(), Abi::RustCall); - if fn_def.sig.variadic() != bare_sig.variadic() || - fn_def.sig.inputs().skip_binder().len() != 1 { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); + let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let sig = self.tcx.erase_regions(&sig); + assert_eq!(sig.abi, Abi::RustCall); + if sig.variadic != bare_sig.variadic || + sig.inputs().len() != 1 { + return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); } - if let ty::TyTuple(fields, _) = fn_def.sig.inputs().skip_binder()[0].sty { - if fields.len() != bare_sig.inputs().skip_binder().len() { - return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig)); + if let ty::TyTuple(fields, _) = sig.inputs()[0].sty { + if **fields != *bare_sig.inputs() { + return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); } + } else { + return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); } }, other => return Err(EvalError::ExpectedConcreteFunction(other)), @@ -165,7 +170,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match fn_def { // Intrinsics can only be addressed directly Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => { - let ty = *sig.output().skip_binder(); + let sig = self.tcx.erase_late_bound_regions(&sig); + let sig = self.tcx.erase_regions(&sig); + let ty = sig.output(); let layout = self.type_layout(ty)?; let (ret, target) = match destination { Some(dest) if is_inhabited(self.tcx, ty) => dest, @@ -177,7 +184,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, // C functions can only be addressed directly Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => { - let ty = *sig.output().skip_binder(); + let sig = self.tcx.erase_late_bound_regions(&sig); + let sig = self.tcx.erase_regions(&sig); + let ty = sig.output(); let (ret, target) = destination.unwrap(); self.call_c_abi(def_id, arg_operands, ret, ty)?; self.dump_local(ret); @@ -266,6 +275,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ) }, Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => { + let sig = self.tcx.erase_late_bound_regions(&sig); + let sig = self.tcx.erase_regions(&sig); let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; @@ -274,7 +285,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } args.insert(0, ( Value::ByVal(PrimVal::Undef), - sig.inputs().skip_binder()[0], + sig.inputs()[0], )); self.eval_fn_call_inner( def_id, @@ -285,7 +296,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { span, ) } - other => Err(EvalError::Unimplemented(format!("can't call function kind {:?}", other))), + Function::Concrete(fn_def) => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", fn_def.sig.abi()))), + other => Err(EvalError::Unimplemented(format!("can't call function kind {:#?}", other))), } } diff --git a/src/traits.rs b/src/traits.rs index e4f9e4a24a..19a4f6652d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -123,17 +123,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), Function::Concrete(fn_def) => { - trace!("sig: {:#?}", fn_def.sig); + let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let sig = self.tcx.erase_regions(&sig); + trace!("sig: {:#?}", sig); args[0] = ( Value::ByVal(PrimVal::Ptr(self_ptr)), - fn_def.sig.inputs().skip_binder()[0], + sig.inputs()[0], ); Ok((fn_def.def_id, fn_def.substs, Vec::new())) }, Function::NonCaptureClosureAsFnPtr(fn_def) => { + let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let sig = self.tcx.erase_regions(&sig); args.insert(0, ( Value::ByVal(PrimVal::Undef), - fn_def.sig.inputs().skip_binder()[0], + sig.inputs()[0], )); Ok((fn_def.def_id, fn_def.substs, Vec::new())) } @@ -142,6 +146,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok((fn_def.def_id, fn_def.substs, Vec::new())) } Function::FnPtrAsTraitObject(sig) => { + let sig = self.tcx.erase_late_bound_regions(&sig); + let sig = self.tcx.erase_regions(&sig); trace!("sig: {:#?}", sig); // the first argument was the fat ptr args.remove(0); @@ -149,13 +155,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let fn_ptr = self.memory.read_ptr(self_ptr)?; let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? { Function::Concrete(fn_def) => { - assert_eq!(sig, fn_def.sig); + let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let fn_def_sig = self.tcx.erase_regions(&fn_def_sig); + assert_eq!(sig, fn_def_sig); fn_def }, Function::NonCaptureClosureAsFnPtr(fn_def) => { + let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig); + let fn_def_sig = self.tcx.erase_regions(&fn_def_sig); args.insert(0, ( Value::ByVal(PrimVal::Undef), - fn_def.sig.inputs().skip_binder()[0], + fn_def_sig.inputs()[0], )); fn_def }, @@ -280,8 +290,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty), _ => bug!("drop method is not a TyFnDef"), }; + let fn_ty = self.tcx.erase_late_bound_regions(&fn_ty); + let fn_ty = self.tcx.erase_regions(&fn_ty); // The real type is taken from the self argument in `fn drop(&mut self)` - let real_ty = match fn_ty.inputs().skip_binder()[0].sty { + let real_ty = match fn_ty.inputs()[0].sty { ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs), _ => bug!("first argument of Drop::drop must be &mut T"), }; diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs new file mode 100644 index 0000000000..17453933c8 --- /dev/null +++ b/tests/run-pass/rfc1623.rs @@ -0,0 +1,81 @@ +// Copyright 2012 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. + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static STATIC_STR: &str = "&'static str"; +const CONST_STR: &str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg +} + +// one with a function, argument elided +static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) {} + +static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool], +} + +static STATIC_FOO: Foo = Foo { bools: &[true, false] }; +const CONST_FOO: Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR: Bar = Bar { bools: &[true, false] }; +const CONST_BAR: Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { + e.first().map(|x| *x) +} + +static STATIC_BAZ: &Baz = &(baz as Baz); +const CONST_BAZ: &Baz = &(baz as Baz); + +static BYTES: &[u8] = &[1, 2, 3]; + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + CONST_MULTI_FN(a, b, c); + } +} From adb3fbb285181bcbf1453efd42a0fc970424ed3e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Mar 2017 11:12:59 +0100 Subject: [PATCH 7/8] Add a method that hides the lifetime erasing boilerplate --- src/eval_context.rs | 9 ++++++++- src/terminator/mod.rs | 18 ++++++------------ src/traits.rs | 18 ++++++------------ 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/eval_context.rs b/src/eval_context.rs index 9b23b849fc..549530265e 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -9,7 +9,7 @@ use rustc::mir; use rustc::traits::Reveal; use rustc::ty::layout::{self, Layout, Size}; use rustc::ty::subst::{self, Subst, Substs}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder}; use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::{self, DUMMY_SP}; @@ -225,6 +225,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.tcx.normalize_associated_type(&substituted) } + pub fn erase_lifetimes(&self, value: &Binder) -> T + where T : TypeFoldable<'tcx> + { + let value = self.tcx.erase_late_bound_regions(value); + self.tcx.erase_regions(&value) + } + pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { self.type_size_with_substs(ty, self.substs()) } diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index b0e7b76ae1..7968272311 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -65,16 +65,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let func_ty = self.operand_ty(func); let fn_def = match func_ty.sty { ty::TyFnPtr(bare_sig) => { - let bare_sig = self.tcx.erase_late_bound_regions(&bare_sig); - let bare_sig = self.tcx.erase_regions(&bare_sig); + let bare_sig = self.erase_lifetimes(&bare_sig); let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?; match fn_def { Function::Concrete(fn_def) => { // transmuting function pointers in miri is fine as long as the number of // arguments and the abi don't change. - let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&fn_def.sig); if sig.abi != bare_sig.abi || sig.variadic != bare_sig.variadic || sig.inputs_and_output != bare_sig.inputs_and_output { @@ -82,8 +80,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } }, Function::NonCaptureClosureAsFnPtr(fn_def) => { - let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&fn_def.sig); assert_eq!(sig.abi, Abi::RustCall); if sig.variadic != bare_sig.variadic || sig.inputs().len() != 1 { @@ -170,8 +167,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match fn_def { // Intrinsics can only be addressed directly Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => { - let sig = self.tcx.erase_late_bound_regions(&sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&sig); let ty = sig.output(); let layout = self.type_layout(ty)?; let (ret, target) = match destination { @@ -184,8 +180,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, // C functions can only be addressed directly Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => { - let sig = self.tcx.erase_late_bound_regions(&sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&sig); let ty = sig.output(); let (ret, target) = destination.unwrap(); self.call_c_abi(def_id, arg_operands, ret, ty)?; @@ -275,8 +270,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ) }, Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => { - let sig = self.tcx.erase_late_bound_regions(&sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&sig); let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; diff --git a/src/traits.rs b/src/traits.rs index 19a4f6652d..72de17801d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -123,8 +123,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), Function::Concrete(fn_def) => { - let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&fn_def.sig); trace!("sig: {:#?}", sig); args[0] = ( Value::ByVal(PrimVal::Ptr(self_ptr)), @@ -133,8 +132,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok((fn_def.def_id, fn_def.substs, Vec::new())) }, Function::NonCaptureClosureAsFnPtr(fn_def) => { - let sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&fn_def.sig); args.insert(0, ( Value::ByVal(PrimVal::Undef), sig.inputs()[0], @@ -146,8 +144,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok((fn_def.def_id, fn_def.substs, Vec::new())) } Function::FnPtrAsTraitObject(sig) => { - let sig = self.tcx.erase_late_bound_regions(&sig); - let sig = self.tcx.erase_regions(&sig); + let sig = self.erase_lifetimes(&sig); trace!("sig: {:#?}", sig); // the first argument was the fat ptr args.remove(0); @@ -155,14 +152,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let fn_ptr = self.memory.read_ptr(self_ptr)?; let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? { Function::Concrete(fn_def) => { - let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let fn_def_sig = self.tcx.erase_regions(&fn_def_sig); + let fn_def_sig = self.erase_lifetimes(&fn_def.sig); assert_eq!(sig, fn_def_sig); fn_def }, Function::NonCaptureClosureAsFnPtr(fn_def) => { - let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig); - let fn_def_sig = self.tcx.erase_regions(&fn_def_sig); + let fn_def_sig = self.erase_lifetimes(&fn_def.sig); args.insert(0, ( Value::ByVal(PrimVal::Undef), fn_def_sig.inputs()[0], @@ -290,8 +285,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty), _ => bug!("drop method is not a TyFnDef"), }; - let fn_ty = self.tcx.erase_late_bound_regions(&fn_ty); - let fn_ty = self.tcx.erase_regions(&fn_ty); + let fn_ty = self.erase_lifetimes(&fn_ty); // The real type is taken from the self argument in `fn drop(&mut self)` let real_ty = match fn_ty.inputs()[0].sty { ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs), From 80be25e705b0c9b3e8cb43bc0fb4fae3108172bf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Mar 2017 11:14:53 +0100 Subject: [PATCH 8/8] Fix warnings in unit test --- tests/run-pass/rfc1623.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs index 17453933c8..0ee523a5be 100644 --- a/tests/run-pass/rfc1623.rs +++ b/tests/run-pass/rfc1623.rs @@ -28,13 +28,13 @@ static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = +static STATIC_NON_ELIDED_FN: &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = +const CONST_NON_ELIDED_FN: &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) {} +fn multi_args(_a: &u8, _b: &u8, _c: &u8) {} static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));