Skip to content

Commit 47f37d6

Browse files
committed
Correctly access ScalarPair fields during const eval
1 parent d830f46 commit 47f37d6

File tree

4 files changed

+80
-79
lines changed

4 files changed

+80
-79
lines changed

src/librustc_mir/interpret/place.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
136136
Value::ScalarPair(..) |
137137
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
138138
// split fat pointers, 2 element tuples, ...
139-
Value::ScalarPair(a, b) if base_layout.fields.count() == 2 => {
140-
let val = [a, b][field_index];
139+
Value::ScalarPair(a, b) => {
140+
let val = if offset.bytes() == 0 { a } else { b };
141141
Ok(Some((Value::Scalar(val), field.ty)))
142142
},
143143
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here

src/librustc_mir/interpret/terminator/mod.rs

+32-58
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, Value};
88
use super::{EvalContext, Place, Machine, ValTy};
99

1010
use rustc_data_structures::indexed_vec::Idx;
@@ -338,65 +338,39 @@ 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());
347+
for (i, arg_local) in arg_locals.enumerate() {
348+
let field = layout.field(&self, i)?;
349+
if field.is_zst() {
350+
continue;
399351
}
352+
let offset = layout.fields.offset(i);
353+
let value = match args[1].value {
354+
Value::ByRef(ptr, align) => Value::ByRef(
355+
ptr.ptr_offset(offset, &self)?,
356+
align.min(field.align),
357+
),
358+
other if field.size == layout.size => {
359+
// this is the case where the field covers the entire type
360+
assert_eq!(offset.bytes(), 0);
361+
other
362+
},
363+
Value::ScalarPair(a, _) if offset.bytes() == 0 => Value::Scalar(a),
364+
Value::ScalarPair(_, b) => Value::Scalar(b),
365+
Value::Scalar(_) => bug!("Scalar does not cover entire type"),
366+
};
367+
let dest =
368+
self.eval_place(&mir::Place::Local(arg_local))?;
369+
let valty = ValTy {
370+
value,
371+
ty: field.ty,
372+
};
373+
self.write_value(valty, dest)?;
400374
}
401375
} else {
402376
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 (value, field_ty) = self.use_ecx(span, |this| {
218+
this.ecx.read_field(base, None, field, ty)
219+
})??;
220+
Some((value, field_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)