Skip to content

Commit da6f136

Browse files
committed
I say we take off and nuke the lifetimes from orbit
1 parent 64d196a commit da6f136

File tree

4 files changed

+132
-27
lines changed

4 files changed

+132
-27
lines changed

src/error.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::error::Error;
22
use std::fmt;
33
use rustc::mir;
4-
use rustc::ty::{PolyFnSig, Ty, layout};
4+
use rustc::ty::{FnSig, Ty, layout};
55
use memory::{Pointer, Function};
66
use rustc_const_math::ConstMathErr;
77
use syntax::codemap::Span;
88

99
#[derive(Clone, Debug)]
1010
pub enum EvalError<'tcx> {
11-
FunctionPointerTyMismatch(PolyFnSig<'tcx>, PolyFnSig<'tcx>),
11+
FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>),
1212
NoMirFor(String),
1313
UnterminatedCString(Pointer),
1414
DanglingPointerDeref,
@@ -151,7 +151,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
151151
},
152152
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
153153
EvalError::FunctionPointerTyMismatch(sig, got) =>
154-
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig.skip_binder(), got.skip_binder()),
154+
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
155155
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
156156
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
157157
EvalError::Math(span, ref err) =>

src/terminator/mod.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,36 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
6565
let func_ty = self.operand_ty(func);
6666
let fn_def = match func_ty.sty {
6767
ty::TyFnPtr(bare_sig) => {
68+
let bare_sig = self.tcx.erase_late_bound_regions(&bare_sig);
69+
let bare_sig = self.tcx.erase_regions(&bare_sig);
6870
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
6971
let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?;
7072
match fn_def {
7173
Function::Concrete(fn_def) => {
7274
// transmuting function pointers in miri is fine as long as the number of
7375
// arguments and the abi don't change.
74-
// FIXME: also check the size of the arguments' type and the return type
75-
// Didn't get it to work, since that triggers an assertion in rustc which
76-
// checks whether the type has escaping regions
77-
if fn_def.sig.abi() != bare_sig.abi() ||
78-
fn_def.sig.variadic() != bare_sig.variadic() ||
79-
fn_def.sig.inputs().skip_binder().len() != bare_sig.inputs().skip_binder().len() {
80-
return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
76+
let sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
77+
let sig = self.tcx.erase_regions(&sig);
78+
if sig.abi != bare_sig.abi ||
79+
sig.variadic != bare_sig.variadic ||
80+
sig.inputs_and_output != bare_sig.inputs_and_output {
81+
return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig));
8182
}
8283
},
8384
Function::NonCaptureClosureAsFnPtr(fn_def) => {
84-
assert_eq!(fn_def.sig.abi(), Abi::RustCall);
85-
if fn_def.sig.variadic() != bare_sig.variadic() ||
86-
fn_def.sig.inputs().skip_binder().len() != 1 {
87-
return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
85+
let sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
86+
let sig = self.tcx.erase_regions(&sig);
87+
assert_eq!(sig.abi, Abi::RustCall);
88+
if sig.variadic != bare_sig.variadic ||
89+
sig.inputs().len() != 1 {
90+
return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig));
8891
}
89-
if let ty::TyTuple(fields, _) = fn_def.sig.inputs().skip_binder()[0].sty {
90-
if fields.len() != bare_sig.inputs().skip_binder().len() {
91-
return Err(EvalError::FunctionPointerTyMismatch(fn_def.sig, bare_sig));
92+
if let ty::TyTuple(fields, _) = sig.inputs()[0].sty {
93+
if **fields != *bare_sig.inputs() {
94+
return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig));
9295
}
96+
} else {
97+
return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig));
9398
}
9499
},
95100
other => return Err(EvalError::ExpectedConcreteFunction(other)),
@@ -165,7 +170,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
165170
match fn_def {
166171
// Intrinsics can only be addressed directly
167172
Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => {
168-
let ty = *sig.output().skip_binder();
173+
let sig = self.tcx.erase_late_bound_regions(&sig);
174+
let sig = self.tcx.erase_regions(&sig);
175+
let ty = sig.output();
169176
let layout = self.type_layout(ty)?;
170177
let (ret, target) = match destination {
171178
Some(dest) if is_inhabited(self.tcx, ty) => dest,
@@ -177,7 +184,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
177184
},
178185
// C functions can only be addressed directly
179186
Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => {
180-
let ty = *sig.output().skip_binder();
187+
let sig = self.tcx.erase_late_bound_regions(&sig);
188+
let sig = self.tcx.erase_regions(&sig);
189+
let ty = sig.output();
181190
let (ret, target) = destination.unwrap();
182191
self.call_c_abi(def_id, arg_operands, ret, ty)?;
183192
self.dump_local(ret);
@@ -266,6 +275,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
266275
)
267276
},
268277
Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => {
278+
let sig = self.tcx.erase_late_bound_regions(&sig);
279+
let sig = self.tcx.erase_regions(&sig);
269280
let mut args = Vec::new();
270281
for arg in arg_operands {
271282
let arg_val = self.eval_operand(arg)?;
@@ -274,7 +285,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
274285
}
275286
args.insert(0, (
276287
Value::ByVal(PrimVal::Undef),
277-
sig.inputs().skip_binder()[0],
288+
sig.inputs()[0],
278289
));
279290
self.eval_fn_call_inner(
280291
def_id,
@@ -285,7 +296,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
285296
span,
286297
)
287298
}
288-
other => Err(EvalError::Unimplemented(format!("can't call function kind {:?}", other))),
299+
Function::Concrete(fn_def) => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", fn_def.sig.abi()))),
300+
other => Err(EvalError::Unimplemented(format!("can't call function kind {:#?}", other))),
289301
}
290302
}
291303

src/traits.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
123123
},
124124
Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue),
125125
Function::Concrete(fn_def) => {
126-
trace!("sig: {:#?}", fn_def.sig);
126+
let sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
127+
let sig = self.tcx.erase_regions(&sig);
128+
trace!("sig: {:#?}", sig);
127129
args[0] = (
128130
Value::ByVal(PrimVal::Ptr(self_ptr)),
129-
fn_def.sig.inputs().skip_binder()[0],
131+
sig.inputs()[0],
130132
);
131133
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
132134
},
133135
Function::NonCaptureClosureAsFnPtr(fn_def) => {
136+
let sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
137+
let sig = self.tcx.erase_regions(&sig);
134138
args.insert(0, (
135139
Value::ByVal(PrimVal::Undef),
136-
fn_def.sig.inputs().skip_binder()[0],
140+
sig.inputs()[0],
137141
));
138142
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
139143
}
@@ -142,20 +146,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
142146
Ok((fn_def.def_id, fn_def.substs, Vec::new()))
143147
}
144148
Function::FnPtrAsTraitObject(sig) => {
149+
let sig = self.tcx.erase_late_bound_regions(&sig);
150+
let sig = self.tcx.erase_regions(&sig);
145151
trace!("sig: {:#?}", sig);
146152
// the first argument was the fat ptr
147153
args.remove(0);
148154
self.unpack_fn_args(args)?;
149155
let fn_ptr = self.memory.read_ptr(self_ptr)?;
150156
let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? {
151157
Function::Concrete(fn_def) => {
152-
assert_eq!(sig, fn_def.sig);
158+
let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
159+
let fn_def_sig = self.tcx.erase_regions(&fn_def_sig);
160+
assert_eq!(sig, fn_def_sig);
153161
fn_def
154162
},
155163
Function::NonCaptureClosureAsFnPtr(fn_def) => {
164+
let fn_def_sig = self.tcx.erase_late_bound_regions(&fn_def.sig);
165+
let fn_def_sig = self.tcx.erase_regions(&fn_def_sig);
156166
args.insert(0, (
157167
Value::ByVal(PrimVal::Undef),
158-
fn_def.sig.inputs().skip_binder()[0],
168+
fn_def_sig.inputs()[0],
159169
));
160170
fn_def
161171
},
@@ -280,8 +290,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
280290
ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty),
281291
_ => bug!("drop method is not a TyFnDef"),
282292
};
293+
let fn_ty = self.tcx.erase_late_bound_regions(&fn_ty);
294+
let fn_ty = self.tcx.erase_regions(&fn_ty);
283295
// The real type is taken from the self argument in `fn drop(&mut self)`
284-
let real_ty = match fn_ty.inputs().skip_binder()[0].sty {
296+
let real_ty = match fn_ty.inputs()[0].sty {
285297
ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs),
286298
_ => bug!("first argument of Drop::drop must be &mut T"),
287299
};

tests/run-pass/rfc1623.rs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(dead_code)]
12+
13+
// very simple test for a 'static static with default lifetime
14+
static STATIC_STR: &str = "&'static str";
15+
const CONST_STR: &str = "&'static str";
16+
17+
// this should be the same as without default:
18+
static EXPLICIT_STATIC_STR: &'static str = "&'static str";
19+
const EXPLICIT_CONST_STR: &'static str = "&'static str";
20+
21+
// a function that elides to an unbound lifetime for both in- and output
22+
fn id_u8_slice(arg: &[u8]) -> &[u8] {
23+
arg
24+
}
25+
26+
// one with a function, argument elided
27+
static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
28+
const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
29+
30+
// this should be the same as without elision
31+
static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] =
32+
&(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
33+
const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] =
34+
&(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
35+
36+
// another function that elides, each to a different unbound lifetime
37+
fn multi_args(a: &u8, b: &u8, c: &u8) {}
38+
39+
static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
40+
const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
41+
42+
struct Foo<'a> {
43+
bools: &'a [bool],
44+
}
45+
46+
static STATIC_FOO: Foo = Foo { bools: &[true, false] };
47+
const CONST_FOO: Foo = Foo { bools: &[true, false] };
48+
49+
type Bar<'a> = Foo<'a>;
50+
51+
static STATIC_BAR: Bar = Bar { bools: &[true, false] };
52+
const CONST_BAR: Bar = Bar { bools: &[true, false] };
53+
54+
type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
55+
56+
fn baz(e: &[u8]) -> Option<u8> {
57+
e.first().map(|x| *x)
58+
}
59+
60+
static STATIC_BAZ: &Baz = &(baz as Baz);
61+
const CONST_BAZ: &Baz = &(baz as Baz);
62+
63+
static BYTES: &[u8] = &[1, 2, 3];
64+
65+
fn main() {
66+
// make sure that the lifetime is actually elided (and not defaulted)
67+
let x = &[1u8, 2, 3];
68+
STATIC_SIMPLE_FN(x);
69+
CONST_SIMPLE_FN(x);
70+
71+
STATIC_BAZ(BYTES); // neees static lifetime
72+
CONST_BAZ(BYTES);
73+
74+
// make sure this works with different lifetimes
75+
let a = &1;
76+
{
77+
let b = &2;
78+
let c = &3;
79+
CONST_MULTI_FN(a, b, c);
80+
}
81+
}

0 commit comments

Comments
 (0)