Skip to content

Commit c4cf115

Browse files
committed
Auto merge of #55720 - RalfJung:const-eval-raw, r=oli-obk
Make const_eval_raw query return just an AllocId r? @oli-obk
2 parents 3991bfb + 612febc commit c4cf115

21 files changed

+138
-109
lines changed

Diff for: src/librustc/ich/impls_ty.rs

+4
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ impl_stable_hash_for!(
317317
ByRef(id, alloc, offset),
318318
}
319319
);
320+
impl_stable_hash_for!(struct ::mir::interpret::RawConst<'tcx> {
321+
alloc_id,
322+
ty,
323+
});
320324

321325
impl_stable_hash_for! {
322326
impl<Tag> for struct mir::interpret::Pointer<Tag> {

Diff for: src/librustc/mir/interpret/error.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use ty::{self, Ty, layout};
1616
use ty::layout::{Size, Align, LayoutError};
1717
use rustc_target::spec::abi::Abi;
1818

19-
use super::{Pointer, InboundsCheck, ScalarMaybeUndef};
19+
use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
2020

2121
use backtrace::Backtrace;
2222

@@ -46,6 +46,7 @@ impl ErrorHandled {
4646
}
4747
}
4848

49+
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
4950
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
5051

5152
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]

Diff for: src/librustc/mir/interpret/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ mod pointer;
2222

2323
pub use self::error::{
2424
EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
25-
FrameInfo, ConstEvalResult, ErrorHandled,
25+
FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
2626
};
2727

28-
pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef};
28+
pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue};
2929

3030
pub use self::allocation::{
3131
InboundsCheck, Allocation, AllocationExtra,

Diff for: src/librustc/mir/interpret/value.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,28 @@
1010

1111
use std::fmt;
1212

13-
use ty::layout::{HasDataLayout, Size};
14-
use ty::subst::Substs;
15-
use hir::def_id::DefId;
13+
use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}};
14+
use crate::hir::def_id::DefId;
1615

1716
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
1817

18+
/// Represents the result of a raw const operation, pre-validation.
19+
#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
20+
pub struct RawConst<'tcx> {
21+
// the value lives here, at offset 0, and that allocation definitely is a `AllocType::Memory`
22+
// (so you can use `AllocMap::unwrap_memory`).
23+
pub alloc_id: AllocId,
24+
pub ty: Ty<'tcx>,
25+
}
26+
1927
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
2028
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
2129
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
2230
pub enum ConstValue<'tcx> {
2331
/// Never returned from the `const_eval` query, but the HIR contains these frequently in order
2432
/// to allow HIR creation to happen for everything before needing to be able to run constant
2533
/// evaluation
34+
/// FIXME: The query should then return a type that does not even have this variant.
2635
Unevaluated(DefId, &'tcx Substs<'tcx>),
2736

2837
/// Used only for types with layout::abi::Scalar ABI and ZSTs

Diff for: src/librustc/ty/query/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use middle::stability::{self, DeprecationEntry};
2727
use middle::lib_features::LibFeatures;
2828
use middle::lang_items::{LanguageItems, LangItem};
2929
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
30-
use mir::interpret::ConstEvalResult;
30+
use mir::interpret::{ConstEvalRawResult, ConstEvalResult};
3131
use mir::mono::CodegenUnit;
3232
use mir;
3333
use mir::interpret::GlobalId;
@@ -309,7 +309,7 @@ define_queries! { <'tcx>
309309
/// validation. Please add a comment to every use site explaining why using `const_eval`
310310
/// isn't sufficient
311311
[] fn const_eval_raw: const_eval_raw_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
312-
-> ConstEvalResult<'tcx>,
312+
-> ConstEvalRawResult<'tcx>,
313313

314314
/// Results of evaluating const items or constants embedded in
315315
/// other items (such as enum variant explicit discriminants).

Diff for: src/librustc_mir/const_eval.rs

+32-24
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ use rustc::util::common::ErrorReported;
3131
use syntax::ast::Mutability;
3232
use syntax::source_map::{Span, DUMMY_SP};
3333

34-
use interpret::{self,
35-
PlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, ConstValue, Pointer,
34+
use crate::interpret::{self,
35+
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
3636
EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
3737
Allocation, AllocId, MemoryKind,
3838
snapshot, RefTracking,
@@ -94,11 +94,12 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
9494
cid: GlobalId<'tcx>,
9595
mir: &'mir mir::Mir<'tcx>,
9696
param_env: ty::ParamEnv<'tcx>,
97-
) -> EvalResult<'tcx, OpTy<'tcx>> {
97+
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
9898
let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
9999
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
100100
}
101101

102+
// FIXME: These two conversion functions are bad hacks. We should just always use allocations.
102103
pub fn op_to_const<'tcx>(
103104
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
104105
op: OpTy<'tcx>,
@@ -144,13 +145,20 @@ pub fn op_to_const<'tcx>(
144145
};
145146
Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
146147
}
148+
pub fn const_to_op<'tcx>(
149+
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
150+
cnst: &ty::Const<'tcx>,
151+
) -> EvalResult<'tcx, OpTy<'tcx>> {
152+
let op = ecx.const_value_to_op(cnst.val)?;
153+
Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? })
154+
}
147155

148156
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
149157
tcx: TyCtxt<'a, 'tcx, 'tcx>,
150158
cid: GlobalId<'tcx>,
151159
mir: Option<&'mir mir::Mir<'tcx>>,
152160
param_env: ty::ParamEnv<'tcx>,
153-
) -> (EvalResult<'tcx, OpTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
161+
) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
154162
// we start out with the best span we have
155163
// and try improving it down the road when more information is available
156164
let span = tcx.def_span(cid.instance.def_id());
@@ -166,7 +174,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
166174
cid: GlobalId<'tcx>,
167175
mir: Option<&'mir mir::Mir<'tcx>>,
168176
param_env: ty::ParamEnv<'tcx>,
169-
) -> EvalResult<'tcx, OpTy<'tcx>> {
177+
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
170178
debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
171179
let tcx = ecx.tcx.tcx;
172180
let mut mir = match mir {
@@ -206,7 +214,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
206214
ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?;
207215

208216
debug!("eval_body_using_ecx done: {:?}", *ret);
209-
Ok(ret.into())
217+
Ok(ret)
210218
}
211219

212220
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
@@ -494,7 +502,7 @@ pub fn const_field<'a, 'tcx>(
494502
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
495503
let result = (|| {
496504
// get the operand again
497-
let op = ecx.const_to_op(value)?;
505+
let op = const_to_op(&ecx, value)?;
498506
// downcast
499507
let down = match variant {
500508
None => op,
@@ -521,7 +529,7 @@ pub fn const_variant_index<'a, 'tcx>(
521529
) -> EvalResult<'tcx, VariantIdx> {
522530
trace!("const_variant_index: {:?}, {:?}", instance, val);
523531
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
524-
let op = ecx.const_to_op(val)?;
532+
let op = const_to_op(&ecx, val)?;
525533
Ok(ecx.read_discriminant(op)?.1)
526534
}
527535

@@ -534,15 +542,17 @@ pub fn error_to_const_error<'a, 'mir, 'tcx>(
534542
ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
535543
}
536544

537-
fn validate_const<'a, 'tcx>(
545+
fn validate_and_turn_into_const<'a, 'tcx>(
538546
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
539-
constant: &'tcx ty::Const<'tcx>,
547+
constant: RawConst<'tcx>,
540548
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
541549
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
542550
let cid = key.value;
543551
let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
544552
let val = (|| {
545-
let op = ecx.const_to_op(constant)?;
553+
let op = ecx.raw_const_to_mplace(constant)?.into();
554+
// FIXME: Once the visitor infrastructure landed, change validation to
555+
// work directly on `MPlaceTy`.
546556
let mut ref_tracking = RefTracking::new(op);
547557
while let Some((op, path)) = ref_tracking.todo.pop() {
548558
ecx.validate_operand(
@@ -552,7 +562,10 @@ fn validate_const<'a, 'tcx>(
552562
/* const_mode */ true,
553563
)?;
554564
}
555-
Ok(constant)
565+
// Now that we validated, turn this into a proper constant
566+
let def_id = cid.instance.def.def_id();
567+
let normalize = tcx.is_static(def_id).is_none() && cid.promoted.is_none();
568+
op_to_const(&ecx, op, normalize)
556569
})();
557570

558571
val.map_err(|error| {
@@ -591,14 +604,14 @@ pub fn const_eval_provider<'a, 'tcx>(
591604
}
592605
}
593606
tcx.const_eval_raw(key).and_then(|val| {
594-
validate_const(tcx, val, key)
607+
validate_and_turn_into_const(tcx, val, key)
595608
})
596609
}
597610

598611
pub fn const_eval_raw_provider<'a, 'tcx>(
599612
tcx: TyCtxt<'a, 'tcx, 'tcx>,
600613
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
601-
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
614+
) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> {
602615
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
603616
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
604617
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
@@ -648,16 +661,11 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
648661
};
649662

650663
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
651-
res.and_then(|op| {
652-
let normalize = tcx.is_static(def_id).is_none() && cid.promoted.is_none();
653-
if !normalize {
654-
// Sanity check: These must always be a MemPlace
655-
match op.op {
656-
Operand::Indirect(_) => { /* all is good */ },
657-
Operand::Immediate(_) => bug!("const eval gave us an Immediate"),
658-
}
659-
}
660-
op_to_const(&ecx, op, normalize)
664+
res.and_then(|place| {
665+
Ok(RawConst {
666+
alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
667+
ty: place.layout.ty
668+
})
661669
}).map_err(|error| {
662670
let err = error_to_const_error(&ecx, error);
663671
// errors in statics are always emitted as fatal errors

Diff for: src/librustc_mir/interpret/eval_context.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -588,18 +588,26 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
588588
Ok(())
589589
}
590590

591-
pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
591+
pub fn const_eval_raw(
592+
&self,
593+
gid: GlobalId<'tcx>,
594+
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
592595
let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
593596
ty::ParamEnv::reveal_all()
594597
} else {
595598
self.param_env
596599
};
597-
self.tcx.const_eval(param_env.and(gid)).map_err(|err| {
600+
// We use `const_eval_raw` here, and get an unvalidated result. That is okay:
601+
// Our result will later be validated anyway, and there seems no good reason
602+
// to have to fail early here. This is also more consistent with
603+
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
604+
let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| {
598605
match err {
599-
ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(),
600-
ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(),
606+
ErrorHandled::Reported => EvalErrorKind::ReferencedConstant,
607+
ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric,
601608
}
602-
})
609+
})?;
610+
self.raw_const_to_mplace(val)
603611
}
604612

605613
pub fn dump_place(&self, place: Place<M::PointerTag>) {

Diff for: src/librustc_mir/interpret/memory.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap};
2828
use syntax::ast::Mutability;
2929

3030
use super::{
31-
Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, InboundsCheck,
31+
Pointer, AllocId, Allocation, GlobalId, AllocationExtra, InboundsCheck,
3232
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
3333
Machine, AllocMap, MayLeak, ScalarMaybeUndef, ErrorHandled,
3434
};
@@ -374,14 +374,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
374374
ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(),
375375
ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(),
376376
}
377-
}).map(|const_val| {
378-
if let ConstValue::ByRef(_, allocation, _) = const_val.val {
379-
// We got tcx memory. Let the machine figure out whether and how to
380-
// turn that into memory with the right pointer tag.
381-
M::adjust_static_allocation(allocation)
382-
} else {
383-
bug!("Matching on non-ByRef static")
384-
}
377+
}).map(|raw_const| {
378+
let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
379+
// We got tcx memory. Let the machine figure out whether and how to
380+
// turn that into memory with the right pointer tag.
381+
M::adjust_static_allocation(allocation)
385382
})
386383
}
387384

Diff for: src/librustc_mir/interpret/operand.rs

+7-20
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
1414
use std::convert::TryInto;
1515

16-
use rustc::{mir, ty};
16+
use rustc::mir;
1717
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
1818

1919
use rustc::mir::interpret::{
@@ -535,19 +535,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
535535
.collect()
536536
}
537537

538-
// Also used e.g. when miri runs into a constant.
539-
pub(super) fn const_value_to_op(
538+
// Used when miri runs into a constant, and by CTFE.
539+
// FIXME: CTFE should use allocations, then we can make this private (embed it into
540+
// `eval_operand`, ideally).
541+
pub(crate) fn const_value_to_op(
540542
&self,
541543
val: ConstValue<'tcx>,
542544
) -> EvalResult<'tcx, Operand<M::PointerTag>> {
543545
trace!("const_value_to_op: {:?}", val);
544546
match val {
545547
ConstValue::Unevaluated(def_id, substs) => {
546548
let instance = self.resolve(def_id, substs)?;
547-
self.global_to_op(GlobalId {
549+
Ok(*OpTy::from(self.const_eval_raw(GlobalId {
548550
instance,
549551
promoted: None,
550-
})
552+
})?))
551553
}
552554
ConstValue::ByRef(id, alloc, offset) => {
553555
// We rely on mutability being set correctly in that allocation to prevent writes
@@ -565,21 +567,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
565567
Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()),
566568
}
567569
}
568-
pub fn const_to_op(
569-
&self,
570-
cnst: &ty::Const<'tcx>,
571-
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
572-
let op = self.const_value_to_op(cnst.val)?;
573-
Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
574-
}
575-
576-
pub(super) fn global_to_op(
577-
&self,
578-
gid: GlobalId<'tcx>
579-
) -> EvalResult<'tcx, Operand<M::PointerTag>> {
580-
let cv = self.const_eval(gid)?;
581-
self.const_value_to_op(cv.val)
582-
}
583570

584571
/// Read discriminant, return the runtime value as well as the variant index.
585572
pub fn read_discriminant(

0 commit comments

Comments
 (0)