Skip to content

Commit b50c1b2

Browse files
committed
Make const_eval_raw query return just an AllocId
1 parent 39852ca commit b50c1b2

18 files changed

+97
-64
lines changed

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> {

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)]

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,

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

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).

src/librustc_mir/const_eval.rs

+24-22
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,13 @@ 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: This thing is a bad hack. We should get rid of it. Ideally constants are always
103+
// in an allocation.
102104
pub fn op_to_const<'tcx>(
103105
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
104106
op: OpTy<'tcx>,
@@ -150,7 +152,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
150152
cid: GlobalId<'tcx>,
151153
mir: Option<&'mir mir::Mir<'tcx>>,
152154
param_env: ty::ParamEnv<'tcx>,
153-
) -> (EvalResult<'tcx, OpTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
155+
) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
154156
// we start out with the best span we have
155157
// and try improving it down the road when more information is available
156158
let span = tcx.def_span(cid.instance.def_id());
@@ -166,7 +168,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
166168
cid: GlobalId<'tcx>,
167169
mir: Option<&'mir mir::Mir<'tcx>>,
168170
param_env: ty::ParamEnv<'tcx>,
169-
) -> EvalResult<'tcx, OpTy<'tcx>> {
171+
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
170172
debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
171173
let tcx = ecx.tcx.tcx;
172174
let mut mir = match mir {
@@ -206,7 +208,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
206208
ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?;
207209

208210
debug!("eval_body_using_ecx done: {:?}", *ret);
209-
Ok(ret.into())
211+
Ok(ret)
210212
}
211213

212214
impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
@@ -534,15 +536,17 @@ pub fn error_to_const_error<'a, 'mir, 'tcx>(
534536
ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
535537
}
536538

537-
fn validate_const<'a, 'tcx>(
539+
fn validate_and_turn_into_const<'a, 'tcx>(
538540
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
539-
constant: &'tcx ty::Const<'tcx>,
541+
constant: RawConst<'tcx>,
540542
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
541543
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
542544
let cid = key.value;
543545
let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
544546
let val = (|| {
545-
let op = ecx.const_to_op(constant)?;
547+
let op = ecx.raw_const_to_mplace(constant)?.into();
548+
// FIXME: Once the visitor infrastructure landed, change validation to
549+
// work directly on `MPlaceTy`.
546550
let mut ref_tracking = RefTracking::new(op);
547551
while let Some((op, path)) = ref_tracking.todo.pop() {
548552
ecx.validate_operand(
@@ -552,7 +556,10 @@ fn validate_const<'a, 'tcx>(
552556
/* const_mode */ true,
553557
)?;
554558
}
555-
Ok(constant)
559+
// Now that we validated, turn this into a proper constant
560+
let def_id = cid.instance.def.def_id();
561+
let normalize = tcx.is_static(def_id).is_none() && cid.promoted.is_none();
562+
op_to_const(&ecx, op, normalize)
556563
})();
557564

558565
val.map_err(|error| {
@@ -591,14 +598,14 @@ pub fn const_eval_provider<'a, 'tcx>(
591598
}
592599
}
593600
tcx.const_eval_raw(key).and_then(|val| {
594-
validate_const(tcx, val, key)
601+
validate_and_turn_into_const(tcx, val, key)
595602
})
596603
}
597604

598605
pub fn const_eval_raw_provider<'a, 'tcx>(
599606
tcx: TyCtxt<'a, 'tcx, 'tcx>,
600607
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
601-
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
608+
) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> {
602609
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
603610
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
604611
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
@@ -648,16 +655,11 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
648655
};
649656

650657
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)
658+
res.and_then(|place| {
659+
Ok(RawConst {
660+
alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
661+
ty: place.layout.ty
662+
})
661663
}).map_err(|error| {
662664
let err = error_to_const_error(&ecx, error);
663665
// errors in statics are always emitted as fatal errors

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

src/librustc_mir/interpret/operand.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
536536
}
537537

538538
// Also used e.g. when miri runs into a constant.
539-
pub(super) fn const_value_to_op(
539+
// FIXME: Can we avoid converting with ConstValue and Const? We should be using RawConst.
540+
fn const_value_to_op(
540541
&self,
541542
val: ConstValue<'tcx>,
542543
) -> EvalResult<'tcx, Operand<M::PointerTag>> {

src/librustc_mir/interpret/place.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@ use rustc::mir;
2020
use rustc::ty::{self, Ty};
2121
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
2222

23-
use rustc::mir::interpret::{
24-
GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
25-
};
2623
use super::{
24+
GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
2725
EvalContext, Machine, AllocMap, AllocationExtra,
28-
Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
26+
RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
2927
};
3028

3129
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -981,6 +979,19 @@ where
981979
Ok(OpTy { op, layout: place.layout })
982980
}
983981

982+
pub fn raw_const_to_mplace(
983+
&self,
984+
raw: RawConst<'tcx>,
985+
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
986+
// This must be an allocation in `tcx`
987+
assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
988+
let layout = self.layout_of(raw.ty)?;
989+
Ok(MPlaceTy::from_aligned_ptr(
990+
Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(),
991+
layout,
992+
))
993+
}
994+
984995
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
985996
/// Also return some more information so drop doesn't have to run the same code twice.
986997
pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)

src/librustc_mir/transform/const_prop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
309309
eval_promoted(this.tcx, cid, this.mir, this.param_env)
310310
})?;
311311
trace!("evaluated promoted {:?} to {:?}", promoted, res);
312-
Some((res, source_info.span))
312+
Some((res.into(), source_info.span))
313313
},
314314
_ => None,
315315
}

src/test/ui/consts/const-err4.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ union Foo {
1616

1717
enum Bar {
1818
Boo = [unsafe { Foo { b: () }.a }; 4][3],
19-
//~^ ERROR evaluation of constant value failed
19+
//~^ ERROR it is undefined behavior to use this value
2020
}
2121

2222
fn main() {

src/test/ui/consts/const-err4.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
error[E0080]: evaluation of constant value failed
1+
error[E0080]: it is undefined behavior to use this value
22
--> $DIR/const-err4.rs:18:11
33
|
44
LL | Boo = [unsafe { Foo { b: () }.a }; 4][3],
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain bits
6+
|
7+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
68

79
error: aborting due to previous error
810

src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn main() {
3737
//~^ ERROR it is undefined behavior to use this value
3838

3939
const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
40-
//~^ ERROR any use of this value will cause an error
40+
//~^ ERROR it is undefined behavior to use this value
4141

4242
const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 };
4343
//~^ ERROR any use of this value will cause an error
@@ -52,7 +52,7 @@ fn main() {
5252
//~^ ERROR it is undefined behavior to use this value
5353

5454
const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
55-
//~^ ERROR any use of this value will cause an error
55+
//~^ ERROR it is undefined behavior to use this value
5656

5757
const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 };
5858
//~^ ERROR any use of this value will cause an error

src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin
4040
|
4141
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4242

43-
error: any use of this value will cause an error
43+
error[E0080]: it is undefined behavior to use this value
4444
--> $DIR/const-pointer-values-in-various-types.rs:39:5
4545
|
4646
LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
47-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain bits
48+
|
49+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4850

4951
error: any use of this value will cause an error
5052
--> $DIR/const-pointer-values-in-various-types.rs:42:5
@@ -78,11 +80,13 @@ LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int
7880
|
7981
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
8082

81-
error: any use of this value will cause an error
83+
error[E0080]: it is undefined behavior to use this value
8284
--> $DIR/const-pointer-values-in-various-types.rs:54:5
8385
|
8486
LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
85-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
87+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain bits
88+
|
89+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
8690

8791
error: any use of this value will cause an error
8892
--> $DIR/const-pointer-values-in-various-types.rs:57:5

src/test/ui/consts/const-eval/union-const-eval-field.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const fn read_field2() -> Field2 {
3434
}
3535

3636
const fn read_field3() -> Field3 {
37-
const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR any use of this value
37+
const FIELD3: Field3 = unsafe { UNION.field3 };
38+
//~^ ERROR it is undefined behavior to use this value
3839
FIELD3
3940
}
4041

Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
error: any use of this value will cause an error
1+
error[E0080]: it is undefined behavior to use this value
22
--> $DIR/union-const-eval-field.rs:37:5
33
|
4-
LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR any use of this value
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
4+
LL | const FIELD3: Field3 = unsafe { UNION.field3 };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain bits
66
|
7-
= note: #[deny(const_err)] on by default
7+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
88

99
error: aborting due to previous error
1010

11+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)