Skip to content

Commit c610be9

Browse files
committed
Auto merge of #51307 - oli-obk:miri_fixes, r=eddyb
ScalarPairs are offset==0 field + other non-zst field r? @eddyb fixes #51300
2 parents 41affd0 + f7eedfa commit c610be9

File tree

4 files changed

+82
-90
lines changed

4 files changed

+82
-90
lines changed

src/librustc_mir/interpret/place.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -120,29 +120,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
120120
variant: Option<usize>,
121121
field: mir::Field,
122122
base_ty: Ty<'tcx>,
123-
) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
123+
) -> EvalResult<'tcx, ValTy<'tcx>> {
124124
let mut base_layout = self.layout_of(base_ty)?;
125125
if let Some(variant_index) = variant {
126126
base_layout = base_layout.for_variant(self, variant_index);
127127
}
128128
let field_index = field.index();
129129
let field = base_layout.field(self, field_index)?;
130130
if field.size.bytes() == 0 {
131-
return Ok(Some((Value::Scalar(Scalar::undef()), field.ty)))
131+
return Ok(ValTy {
132+
value: Value::Scalar(Scalar::undef()),
133+
ty: field.ty,
134+
});
132135
}
133136
let offset = base_layout.fields.offset(field_index);
134-
match base {
137+
let value = match base {
135138
// the field covers the entire type
136139
Value::ScalarPair(..) |
137-
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
138-
// split fat pointers, 2 element tuples, ...
139-
Value::ScalarPair(a, b) if base_layout.fields.count() == 2 => {
140-
let val = [a, b][field_index];
141-
Ok(Some((Value::Scalar(val), field.ty)))
140+
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => base,
141+
// extract fields from types with `ScalarPair` ABI
142+
Value::ScalarPair(a, b) => {
143+
let val = if offset.bytes() == 0 { a } else { b };
144+
Value::Scalar(val)
142145
},
143-
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
144-
_ => Ok(None),
145-
}
146+
Value::ByRef(base_ptr, align) => {
147+
let offset = base_layout.fields.offset(field_index);
148+
let ptr = base_ptr.ptr_offset(offset, self)?;
149+
let align = align.min(base_layout.align).min(field.align);
150+
assert!(!field.is_unsized());
151+
Value::ByRef(ptr, align)
152+
},
153+
Value::Scalar(val) => bug!("field access on non aggregate {:?}, {:?}", val, base_ty),
154+
};
155+
Ok(ValTy {
156+
value,
157+
ty: field.ty,
158+
})
146159
}
147160

148161
fn try_read_place_projection(
@@ -156,7 +169,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
156169
};
157170
let base_ty = self.place_ty(&proj.base);
158171
match proj.elem {
159-
Field(field, _) => Ok(self.read_field(base, None, field, base_ty)?.map(|(f, _)| f)),
172+
Field(field, _) => Ok(Some(self.read_field(base, None, field, base_ty)?.value)),
160173
// The NullablePointer cases should work fine, need to take care for normal enums
161174
Downcast(..) |
162175
Subslice { .. } |

src/librustc_mir/interpret/terminator/mod.rs

+11-59
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc::ty::layout::LayoutOf;
44
use syntax::codemap::Span;
55
use rustc_target::spec::abi::Abi;
66

7-
use rustc::mir::interpret::{EvalResult, Scalar, Value};
7+
use rustc::mir::interpret::EvalResult;
88
use super::{EvalContext, Place, Machine, ValTy};
99

1010
use rustc_data_structures::indexed_vec::Idx;
@@ -338,65 +338,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
338338

339339
// unpack and write all other args
340340
let layout = self.layout_of(args[1].ty)?;
341-
if let ty::TyTuple(..) = args[1].ty.sty {
341+
if let ty::TyTuple(_) = args[1].ty.sty {
342+
if layout.is_zst() {
343+
// Nothing to do, no need to unpack zsts
344+
return Ok(());
345+
}
342346
if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
343-
match args[1].value {
344-
Value::ByRef(ptr, align) => {
345-
for (i, arg_local) in arg_locals.enumerate() {
346-
let field = layout.field(&self, i)?;
347-
let offset = layout.fields.offset(i);
348-
let arg = Value::ByRef(ptr.ptr_offset(offset, &self)?,
349-
align.min(field.align));
350-
let dest =
351-
self.eval_place(&mir::Place::Local(arg_local))?;
352-
trace!(
353-
"writing arg {:?} to {:?} (type: {})",
354-
arg,
355-
dest,
356-
field.ty
357-
);
358-
let valty = ValTy {
359-
value: arg,
360-
ty: field.ty,
361-
};
362-
self.write_value(valty, dest)?;
363-
}
364-
}
365-
Value::Scalar(Scalar::Bits { defined: 0, .. }) => {}
366-
other => {
367-
trace!("{:#?}, {:#?}", other, layout);
368-
let mut layout = layout;
369-
'outer: loop {
370-
for i in 0..layout.fields.count() {
371-
let field = layout.field(&self, i)?;
372-
if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
373-
layout = field;
374-
continue 'outer;
375-
}
376-
}
377-
break;
378-
}
379-
{
380-
let mut write_next = |value| {
381-
let dest = self.eval_place(&mir::Place::Local(
382-
arg_locals.next().unwrap(),
383-
))?;
384-
let valty = ValTy {
385-
value: Value::Scalar(value),
386-
ty: layout.ty,
387-
};
388-
self.write_value(valty, dest)
389-
};
390-
match other {
391-
Value::Scalar(value) | Value::ScalarPair(value, _) => write_next(value)?,
392-
_ => unreachable!(),
393-
}
394-
if let Value::ScalarPair(_, value) = other {
395-
write_next(value)?;
396-
}
397-
}
398-
assert!(arg_locals.next().is_none());
399-
}
347+
for (i, arg_local) in arg_locals.enumerate() {
348+
let field = mir::Field::new(i);
349+
let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
350+
let dest = self.eval_place(&mir::Place::Local(arg_local))?;
351+
self.write_value(valty, dest)?;
400352
}
401353
} else {
402354
trace!("manual impl of rust-call ABI");

src/librustc_mir/transform/const_prop.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use rustc::ty::subst::Substs;
2929
use rustc_data_structures::indexed_vec::IndexVec;
3030
use rustc::ty::ParamEnv;
3131
use rustc::ty::layout::{
32-
LayoutOf, TyLayout, LayoutError, LayoutCx,
32+
LayoutOf, TyLayout, LayoutError,
3333
HasTyCtxt, TargetDataLayout, HasDataLayout,
3434
};
3535

@@ -214,24 +214,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
214214
ProjectionElem::Field(field, _) => {
215215
trace!("field proj on {:?}", proj.base);
216216
let (base, ty, span) = self.eval_place(&proj.base)?;
217-
match base {
218-
Value::ScalarPair(a, b) => {
219-
trace!("by val pair: {:?}, {:?}", a, b);
220-
let base_layout = self.tcx.layout_of(self.param_env.and(ty)).ok()?;
221-
trace!("layout computed");
222-
use rustc_data_structures::indexed_vec::Idx;
223-
let field_index = field.index();
224-
let val = [a, b][field_index];
225-
let cx = LayoutCx {
226-
tcx: self.tcx,
227-
param_env: self.param_env,
228-
};
229-
let field = base_layout.field(cx, field_index).ok()?;
230-
trace!("projection resulted in: {:?}", val);
231-
Some((Value::Scalar(val), field.ty, span))
232-
},
233-
_ => None,
234-
}
217+
let valty = self.use_ecx(span, |this| {
218+
this.ecx.read_field(base, None, field, ty)
219+
})?;
220+
Some((valty.value, valty.ty, span))
235221
},
236222
_ => None,
237223
},

src/test/ui/const-eval/issue-51300.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2018 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+
// compile-pass
12+
// https://github.com/rust-lang/rust/issues/51300
13+
14+
#[derive(PartialEq, Eq, Clone, Copy)]
15+
pub struct Stat {
16+
pub id: u8,
17+
pub index: usize,
18+
}
19+
20+
impl Stat {
21+
pub const STUDENT_HAPPINESS: Stat = Stat{
22+
id: 0,
23+
index: 0,
24+
};
25+
pub const STUDENT_HUNGER: Stat = Stat{
26+
id: 0,
27+
index: Self::STUDENT_HAPPINESS.index + 1,
28+
};
29+
30+
}
31+
32+
pub fn from_index(id: u8, index: usize) -> Option<Stat> {
33+
let stat = Stat{id, index};
34+
match stat {
35+
Stat::STUDENT_HAPPINESS => Some(Stat::STUDENT_HAPPINESS),
36+
Stat::STUDENT_HUNGER => Some(Stat::STUDENT_HUNGER),
37+
_ => None,
38+
}
39+
}
40+
41+
fn main() { }

0 commit comments

Comments
 (0)