Go through an allocation when accessing fields of constants
This commit is contained in:
parent
76ddede5c2
commit
6630678428
9 changed files with 87 additions and 38 deletions
|
@ -401,8 +401,9 @@ for ::mir::interpret::ConstValue<'gcx> {
|
||||||
a.hash_stable(hcx, hasher);
|
a.hash_stable(hcx, hasher);
|
||||||
b.hash_stable(hcx, hasher);
|
b.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
ByRef(alloc) => {
|
ByRef(alloc, offset) => {
|
||||||
alloc.hash_stable(hcx, hasher);
|
alloc.hash_stable(hcx, hasher);
|
||||||
|
offset.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
|
||||||
/// matches Value's optimizations for easy conversions between these two types
|
/// matches Value's optimizations for easy conversions between these two types
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
|
||||||
pub enum ConstValue<'tcx> {
|
pub enum ConstValue<'tcx> {
|
||||||
// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
|
/// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
|
||||||
ByVal(PrimVal),
|
ByVal(PrimVal),
|
||||||
// Used only for types with layout::abi::ScalarPair
|
/// Used only for types with layout::abi::ScalarPair
|
||||||
ByValPair(PrimVal, PrimVal),
|
ByValPair(PrimVal, PrimVal),
|
||||||
// Used only for the remaining cases
|
/// Used only for the remaining cases. An allocation + offset into the allocation
|
||||||
ByRef(&'tcx Allocation),
|
ByRef(&'tcx Allocation, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ConstValue<'tcx> {
|
impl<'tcx> ConstValue<'tcx> {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind};
|
||||||
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::{Slice, TyS};
|
use ty::{Slice, TyS};
|
||||||
use util::captures::Captures;
|
use util::captures::Captures;
|
||||||
use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
|
use mir::interpret::{PrimVal, MemoryPointer, Value, ConstValue};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -1767,15 +1767,6 @@ impl<'tcx> Const<'tcx> {
|
||||||
Self::from_const_val(tcx, ConstVal::Value(val), ty)
|
Self::from_const_val(tcx, ConstVal::Value(val), ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn from_alloc(
|
|
||||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
|
||||||
alloc: &'tcx Allocation,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> &'tcx Self {
|
|
||||||
Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_byval_value(
|
pub fn from_byval_value(
|
||||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
|
|
|
@ -129,7 +129,7 @@ pub fn codegen_static_initializer<'a, 'tcx>(
|
||||||
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
|
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
|
||||||
|
|
||||||
let alloc = match static_.val {
|
let alloc = match static_.val {
|
||||||
ConstVal::Value(ConstValue::ByRef(alloc)) => alloc,
|
ConstVal::Value(ConstValue::ByRef(alloc, 0)) => alloc,
|
||||||
_ => bug!("static const eval returned {:#?}", static_),
|
_ => bug!("static const eval returned {:#?}", static_),
|
||||||
};
|
};
|
||||||
Ok(const_alloc_to_llvm(cx, alloc))
|
Ok(const_alloc_to_llvm(cx, alloc))
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use llvm::ValueRef;
|
use llvm::{ValueRef, LLVMConstInBoundsGEP};
|
||||||
use rustc::middle::const_val::ConstEvalErr;
|
use rustc::middle::const_val::ConstEvalErr;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::mir::interpret::ConstValue;
|
use rustc::mir::interpret::ConstValue;
|
||||||
|
@ -137,9 +137,15 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
);
|
);
|
||||||
OperandValue::Pair(a_llval, b_llval)
|
OperandValue::Pair(a_llval, b_llval)
|
||||||
},
|
},
|
||||||
ConstValue::ByRef(alloc) => {
|
ConstValue::ByRef(alloc, offset) => {
|
||||||
let init = const_alloc_to_llvm(bx.cx, alloc);
|
let init = const_alloc_to_llvm(bx.cx, alloc);
|
||||||
let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
|
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
|
||||||
|
|
||||||
|
let llval = unsafe { LLVMConstInBoundsGEP(
|
||||||
|
consts::bitcast(base_addr, Type::i8p(bx.cx)),
|
||||||
|
&C_usize(bx.cx, offset),
|
||||||
|
1,
|
||||||
|
)};
|
||||||
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
|
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
|
||||||
return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
|
return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
|
||||||
},
|
},
|
||||||
|
|
|
@ -422,22 +422,23 @@ pub fn const_val_field<'a, 'tcx>(
|
||||||
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
let result = (|| {
|
let result = (|| {
|
||||||
let value = ecx.const_value_to_value(value, ty)?;
|
let value = ecx.const_value_to_value(value, ty)?;
|
||||||
let (field, ty) = match value {
|
let layout = ecx.layout_of(ty)?;
|
||||||
Value::ByValPair(..) | Value::ByVal(_) =>
|
let (ptr, align) = match value {
|
||||||
ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
|
Value::ByRef(ptr, align) => (ptr, align),
|
||||||
Value::ByRef(ptr, align) => {
|
Value::ByValPair(..) | Value::ByVal(_) => {
|
||||||
|
let ptr = ecx.alloc_ptr(ty)?.into();
|
||||||
|
ecx.write_value_to_ptr(value, ptr, ty)?;
|
||||||
|
(ptr, layout.align)
|
||||||
|
},
|
||||||
|
};
|
||||||
let place = Place::Ptr {
|
let place = Place::Ptr {
|
||||||
ptr,
|
ptr,
|
||||||
align,
|
align,
|
||||||
extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
|
extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
|
||||||
};
|
};
|
||||||
let layout = ecx.layout_of(ty)?;
|
|
||||||
let (place, layout) = ecx.place_field(place, field, layout)?;
|
let (place, layout) = ecx.place_field(place, field, layout)?;
|
||||||
let (ptr, align) = place.to_ptr_align();
|
let (ptr, align) = place.to_ptr_align();
|
||||||
(Value::ByRef(ptr, align), layout.ty)
|
Ok((Value::ByRef(ptr, align), layout.ty))
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(value_to_const_value(&ecx, field, ty))
|
|
||||||
})();
|
})();
|
||||||
result.map_err(|err| {
|
result.map_err(|err| {
|
||||||
let (trace, span) = ecx.generate_stacktrace(None);
|
let (trace, span) = ecx.generate_stacktrace(None);
|
||||||
|
@ -478,7 +479,10 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>(
|
||||||
(val, ty): (ConstValue<'tcx>, Ty<'tcx>),
|
(val, ty): (ConstValue<'tcx>, Ty<'tcx>),
|
||||||
) -> &'tcx Allocation {
|
) -> &'tcx Allocation {
|
||||||
match val {
|
match val {
|
||||||
ConstValue::ByRef(alloc) => return alloc,
|
ConstValue::ByRef(alloc, offset) => {
|
||||||
|
assert_eq!(offset, 0);
|
||||||
|
return alloc;
|
||||||
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
let result = || -> EvalResult<'tcx, &'tcx Allocation> {
|
let result = || -> EvalResult<'tcx, &'tcx Allocation> {
|
||||||
|
|
|
@ -243,10 +243,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||||
_ty: Ty<'tcx>,
|
_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx, Value> {
|
) -> EvalResult<'tcx, Value> {
|
||||||
match val {
|
match val {
|
||||||
ConstValue::ByRef(alloc) => {
|
ConstValue::ByRef(alloc, offset) => {
|
||||||
// FIXME: Allocate new AllocId for all constants inside
|
// FIXME: Allocate new AllocId for all constants inside
|
||||||
let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
|
let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
|
||||||
Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
|
Ok(Value::ByRef(MemoryPointer::new(id, offset).into(), alloc.align))
|
||||||
},
|
},
|
||||||
ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
|
ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
|
||||||
ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
|
ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
|
||||||
|
|
|
@ -1249,7 +1249,7 @@ fn collect_const<'a, 'tcx>(
|
||||||
ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
|
ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
|
||||||
ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
|
ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
|
||||||
collect_miri(tcx, ptr.alloc_id, output),
|
collect_miri(tcx, ptr.alloc_id, output),
|
||||||
ConstVal::Value(ConstValue::ByRef(alloc)) => {
|
ConstVal::Value(ConstValue::ByRef(alloc, _offset)) => {
|
||||||
for &id in alloc.relocations.values() {
|
for &id in alloc.relocations.values() {
|
||||||
collect_miri(tcx, id, output);
|
collect_miri(tcx, id, output);
|
||||||
}
|
}
|
||||||
|
|
47
src/test/ui/const-eval/issue-50706.rs
Normal file
47
src/test/ui/const-eval/issue-50706.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2018 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-pass
|
||||||
|
|
||||||
|
pub struct Stats;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct StatVariant {
|
||||||
|
pub id: u8,
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct Stat {
|
||||||
|
pub variant: StatVariant,
|
||||||
|
pub index: usize,
|
||||||
|
_priv: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stats {
|
||||||
|
pub const TEST: StatVariant = StatVariant{id: 0, _priv: (),};
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const A: Stat = Stat{
|
||||||
|
variant: Self::TEST,
|
||||||
|
index: 0,
|
||||||
|
_priv: (),};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stat {
|
||||||
|
pub fn from_index(variant: StatVariant, index: usize) -> Option<Stat> {
|
||||||
|
let stat = Stat{variant, index, _priv: (),};
|
||||||
|
match stat {
|
||||||
|
Stats::A => Some(Stats::A),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue