Skip to content

Commit b490a40

Browse files
authored
Merge pull request rust-lang#103 from oli-obk/tuples
allow using tuple variant names as function handles
2 parents dc336ee + ce95ae5 commit b490a40

6 files changed

+155
-33
lines changed

Diff for: src/bin/miri.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ extern crate rustc_errors;
88
extern crate env_logger;
99
extern crate log_settings;
1010
extern crate syntax;
11-
#[macro_use] extern crate log;
11+
extern crate log;
1212

1313
use rustc::session::Session;
1414
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};

Diff for: src/eval_context.rs

+72-22
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
223223
}
224224

225225
pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
226-
let substituted = ty.subst(self.tcx, substs);
226+
// miri doesn't care about lifetimes, and will choke on some crazy ones
227+
// let's simply get rid of them
228+
let without_lifetimes = self.tcx.erase_regions(&ty);
229+
let substituted = without_lifetimes.subst(self.tcx, substs);
227230
self.tcx.normalize_associated_type(&substituted)
228231
}
229232

@@ -355,18 +358,44 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
355358
Ok(())
356359
}
357360

358-
fn assign_fields<I: IntoIterator<Item = u64>>(
361+
pub fn assign_discr_and_fields<
362+
I: IntoIterator<Item = u64>,
363+
V: IntoValTyPair<'tcx>,
364+
J: IntoIterator<Item = V>,
365+
>(
359366
&mut self,
360367
dest: Lvalue<'tcx>,
361368
offsets: I,
362-
operands: &[mir::Operand<'tcx>],
369+
operands: J,
370+
discr_val: u128,
371+
discr_size: u64,
372+
) -> EvalResult<'tcx, ()> {
373+
// FIXME(solson)
374+
let dest_ptr = self.force_allocation(dest)?.to_ptr();
375+
376+
let mut offsets = offsets.into_iter();
377+
let discr_offset = offsets.next().unwrap();
378+
let discr_dest = dest_ptr.offset(discr_offset);
379+
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
380+
381+
self.assign_fields(dest, offsets, operands)
382+
}
383+
384+
pub fn assign_fields<
385+
I: IntoIterator<Item = u64>,
386+
V: IntoValTyPair<'tcx>,
387+
J: IntoIterator<Item = V>,
388+
>(
389+
&mut self,
390+
dest: Lvalue<'tcx>,
391+
offsets: I,
392+
operands: J,
363393
) -> EvalResult<'tcx, ()> {
364394
// FIXME(solson)
365395
let dest = self.force_allocation(dest)?.to_ptr();
366396

367397
for (offset, operand) in offsets.into_iter().zip(operands) {
368-
let value = self.eval_operand(operand)?;
369-
let value_ty = self.operand_ty(operand);
398+
let (value, value_ty) = operand.into_val_ty_pair(self)?;
370399
let field_dest = dest.offset(offset);
371400
self.write_value_to_ptr(value, field_dest, value_ty)?;
372401
}
@@ -431,18 +460,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
431460
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
432461
let discr_val = adt_def.variants[variant].disr_val.to_u128_unchecked();
433462
let discr_size = discr.size().bytes();
434-
let discr_offset = variants[variant].offsets[0].bytes();
435463

436-
// FIXME(solson)
437-
let dest = self.force_allocation(dest)?;
438-
let discr_dest = (dest.to_ptr()).offset(discr_offset);
439-
440-
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
441-
442-
// Don't include the first offset; it's for the discriminant.
443-
let field_offsets = variants[variant].offsets.iter().skip(1)
444-
.map(|s| s.bytes());
445-
self.assign_fields(dest, field_offsets, operands)?;
464+
self.assign_discr_and_fields(
465+
dest,
466+
variants[variant].offsets.iter().cloned().map(Size::bytes),
467+
operands,
468+
discr_val,
469+
discr_size,
470+
)?;
446471
} else {
447472
bug!("tried to assign {:?} to Layout::General", kind);
448473
}
@@ -660,22 +685,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
660685
let path = discrfield.iter().skip(2).map(|&i| i as usize);
661686

662687
// Handle the field index for the outer non-null variant.
663-
let inner_ty = match ty.sty {
688+
let (inner_offset, inner_ty) = match ty.sty {
664689
ty::TyAdt(adt_def, substs) => {
665690
let variant = &adt_def.variants[nndiscr as usize];
666691
let index = discrfield[1];
667692
let field = &variant.fields[index as usize];
668-
field.ty(self.tcx, substs)
693+
(self.get_field_offset(ty, index as usize)?, field.ty(self.tcx, substs))
669694
}
670695
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
671696
};
672697

673-
self.field_path_offset_and_ty(inner_ty, path)
698+
self.field_path_offset_and_ty(inner_offset, inner_ty, path)
674699
}
675700

676-
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
677-
let mut offset = Size::from_bytes(0);
678-
701+
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(
702+
&self,
703+
mut offset: Size,
704+
mut ty: Ty<'tcx>,
705+
path: I,
706+
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
679707
// Skip the initial 0 intended for LLVM GEP.
680708
for field_index in path {
681709
let field_offset = self.get_field_offset(ty, field_index)?;
@@ -722,6 +750,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
722750
let bytes = field_index as u64 * self.memory.pointer_size();
723751
Ok(Size::from_bytes(bytes))
724752
}
753+
StructWrappedNullablePointer { ref nonnull, .. } => {
754+
Ok(nonnull.offsets[field_index])
755+
}
725756
_ => {
726757
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
727758
Err(EvalError::Unimplemented(msg))
@@ -736,6 +767,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
736767
match *layout {
737768
Univariant { ref variant, .. } => Ok(variant.offsets.len()),
738769
FatPointer { .. } => Ok(2),
770+
StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len()),
739771
_ => {
740772
let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
741773
Err(EvalError::Unimplemented(msg))
@@ -1464,3 +1496,21 @@ pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::
14641496
pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
14651497
ty.uninhabited_from(&mut FxHashSet::default(), tcx).is_empty()
14661498
}
1499+
1500+
pub trait IntoValTyPair<'tcx> {
1501+
fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a;
1502+
}
1503+
1504+
impl<'tcx> IntoValTyPair<'tcx> for (Value, Ty<'tcx>) {
1505+
fn into_val_ty_pair<'a>(self, _: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
1506+
Ok(self)
1507+
}
1508+
}
1509+
1510+
impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> {
1511+
fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
1512+
let value = ecx.eval_operand(self)?;
1513+
let value_ty = ecx.operand_ty(self);
1514+
Ok((value, value_ty))
1515+
}
1516+
}

Diff for: src/terminator/mod.rs

+42-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc::hir::def_id::DefId;
22
use rustc::mir;
33
use rustc::traits::{self, Reveal};
44
use rustc::ty::fold::TypeFoldable;
5-
use rustc::ty::layout::Layout;
5+
use rustc::ty::layout::{Layout, Size};
66
use rustc::ty::subst::{Substs, Kind};
77
use rustc::ty::{self, Ty, TyCtxt, BareFnTy};
88
use syntax::codemap::{DUMMY_SP, Span};
@@ -238,20 +238,51 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
238238
let (lvalue, target) = destination.expect("tuple struct constructors can't diverge");
239239
let dest_ty = self.tcx.item_type(adt_def.did);
240240
let dest_layout = self.type_layout(dest_ty)?;
241+
trace!("layout({:?}) = {:#?}", dest_ty, dest_layout);
241242
match *dest_layout {
242243
Layout::Univariant { ref variant, .. } => {
243-
assert_eq!(v.disr_val.to_u128_unchecked(), 0);
244+
let disr_val = v.disr_val.to_u128_unchecked();
245+
assert_eq!(disr_val, 0);
244246
let offsets = variant.offsets.iter().map(|s| s.bytes());
245247

246-
// FIXME: don't allocate for single or dual field structs
247-
let dest = self.force_allocation(lvalue)?.to_ptr();
248-
249-
for (offset, (value, value_ty)) in offsets.into_iter().zip(args) {
250-
let field_dest = dest.offset(offset);
251-
self.write_value_to_ptr(value, field_dest, value_ty)?;
248+
self.assign_fields(lvalue, offsets, args)?;
249+
},
250+
Layout::General { discr, ref variants, .. } => {
251+
let disr_val = v.disr_val.to_u128_unchecked();
252+
let discr_size = discr.size().bytes();
253+
self.assign_discr_and_fields(
254+
lvalue,
255+
variants[disr_val as usize].offsets.iter().cloned().map(Size::bytes),
256+
args,
257+
disr_val,
258+
discr_size,
259+
)?;
260+
},
261+
Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
262+
let disr_val = v.disr_val.to_u128_unchecked();
263+
if nndiscr as u128 == disr_val {
264+
let offsets = nonnull.offsets.iter().map(|s| s.bytes());
265+
self.assign_fields(lvalue, offsets, args)?;
266+
} else {
267+
for (_, ty) in args {
268+
assert_eq!(self.type_size(ty)?, Some(0));
269+
}
270+
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
271+
272+
// FIXME(solson)
273+
let dest = self.force_allocation(lvalue)?.to_ptr();
274+
275+
let dest = dest.offset(offset.bytes());
276+
let dest_size = self.type_size(ty)?
277+
.expect("bad StructWrappedNullablePointer discrfield");
278+
self.memory.write_int(dest, 0, dest_size)?;
252279
}
253280
},
254-
// FIXME: enum variant constructors
281+
Layout::RawNullablePointer { .. } => {
282+
assert_eq!(args.len(), 1);
283+
let (val, ty) = args.pop().unwrap();
284+
self.write_value(val, lvalue, ty)?;
285+
},
255286
_ => bug!("bad layout for tuple struct constructor: {:?}", dest_layout),
256287
}
257288
self.goto_block(target);
@@ -295,7 +326,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
295326
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
296327
use rustc::ty::layout::Layout::*;
297328
let adt_layout = self.type_layout(adt_ty)?;
298-
trace!("read_discriminant_value {:?}", adt_layout);
329+
trace!("read_discriminant_value {:#?}", adt_layout);
299330

300331
let discr_val = match *adt_layout {
301332
General { discr, .. } | CEnum { discr, signed: false, .. } => {
@@ -332,6 +363,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
332363
}
333364

334365
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u128, discr_size: u64) -> EvalResult<'tcx, u128> {
366+
trace!("read_nonnull_discriminant_value: {:?}, {}, {}", ptr, nndiscr, discr_size);
335367
let not_null = match self.memory.read_uint(ptr, discr_size) {
336368
Ok(0) => false,
337369
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
assert_eq!(Some(42).map(Some), Some(Some(42)));
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
let x = 5;
3+
assert_eq!(Some(&x).map(Some), Some(Some(&x)));
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#[derive(Copy, Clone, PartialEq, Debug)]
2+
struct A<'a> {
3+
x: i32,
4+
y: &'a i32,
5+
}
6+
7+
#[derive(Copy, Clone, PartialEq, Debug)]
8+
struct B<'a>(i32, &'a i32);
9+
10+
#[derive(Copy, Clone, PartialEq, Debug)]
11+
enum C<'a> {
12+
Value(i32, &'a i32),
13+
#[allow(dead_code)]
14+
NoValue,
15+
}
16+
17+
fn main() {
18+
let x = 5;
19+
let a = A { x: 99, y: &x };
20+
assert_eq!(Some(a).map(Some), Some(Some(a)));
21+
let f = B;
22+
assert_eq!(Some(B(42, &x)), Some(f(42, &x)));
23+
// the following doesn't compile :(
24+
//let f: for<'a> fn(i32, &'a i32) -> B<'a> = B;
25+
//assert_eq!(Some(B(42, &x)), Some(f(42, &x)));
26+
assert_eq!(B(42, &x), foo(&x, B));
27+
let f = C::Value;
28+
assert_eq!(C::Value(42, &x), f(42, &x));
29+
}
30+
31+
fn foo<'a, F: Fn(i32, &'a i32) -> B<'a>>(i: &'a i32, f: F) -> B<'a> {
32+
f(42, i)
33+
}

0 commit comments

Comments
 (0)