Skip to content

Commit 876a72a

Browse files
committed
Auto merge of #66677 - wesleywiser:fix_const_prop_alloc_id_ice, r=oli-obk
[const prop] Fix "alloc id without corresponding allocation" ICE r? @oli-obk
2 parents b5f265e + 32e78ca commit 876a72a

File tree

10 files changed

+78
-36
lines changed

10 files changed

+78
-36
lines changed

src/librustc/mir/interpret/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
458458
}
459459
}
460460

461-
#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
461+
#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable, Hash)]
462462
pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> {
463463
Scalar(Scalar<Tag, Id>),
464464
Undef,

src/librustc_mir/interpret/intern.rs

+30-21
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,34 @@
33
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
44
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
55
6-
use rustc::ty::{Ty, self};
7-
use rustc::mir::interpret::{InterpResult, ErrorHandled};
8-
use rustc::hir;
96
use super::validity::RefTracking;
10-
use rustc_data_structures::fx::FxHashSet;
7+
use rustc::hir;
8+
use rustc::mir::interpret::{ErrorHandled, InterpResult};
9+
use rustc::ty::{self, Ty};
10+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1111

1212
use syntax::ast::Mutability;
1313

1414
use super::{
15-
ValueVisitor, MemoryKind, AllocId, MPlaceTy, Scalar,
15+
AllocId, Allocation, InterpCx, Machine, MemoryKind, MPlaceTy, Scalar, ValueVisitor,
1616
};
17-
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
1817

19-
struct InternVisitor<'rt, 'mir, 'tcx> {
18+
pub trait CompileTimeMachine<'mir, 'tcx> =
19+
Machine<
20+
'mir,
21+
'tcx,
22+
MemoryKinds = !,
23+
PointerTag = (),
24+
ExtraFnVal = !,
25+
FrameExtra = (),
26+
MemoryExtra = (),
27+
AllocExtra = (),
28+
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
29+
>;
30+
31+
struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
2032
/// The ectx from which we intern.
21-
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
33+
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
2234
/// Previously encountered safe references.
2335
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
2436
/// A list of all encountered allocations. After type-based interning, we traverse this list to
@@ -58,18 +70,15 @@ struct IsStaticOrFn;
5870
/// `immutable` things might become mutable if `ty` is not frozen.
5971
/// `ty` can be `None` if there is no potential interior mutability
6072
/// to account for (e.g. for vtables).
61-
fn intern_shallow<'rt, 'mir, 'tcx>(
62-
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
73+
fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
74+
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
6375
leftover_allocations: &'rt mut FxHashSet<AllocId>,
6476
mode: InternMode,
6577
alloc_id: AllocId,
6678
mutability: Mutability,
6779
ty: Option<Ty<'tcx>>,
6880
) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
69-
trace!(
70-
"InternVisitor::intern {:?} with {:?}",
71-
alloc_id, mutability,
72-
);
81+
trace!("InternVisitor::intern {:?} with {:?}", alloc_id, mutability,);
7382
// remove allocation
7483
let tcx = ecx.tcx;
7584
let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
@@ -130,7 +139,7 @@ fn intern_shallow<'rt, 'mir, 'tcx>(
130139
Ok(None)
131140
}
132141

133-
impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
142+
impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> {
134143
fn intern_shallow(
135144
&mut self,
136145
alloc_id: AllocId,
@@ -148,15 +157,15 @@ impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
148157
}
149158
}
150159

151-
impl<'rt, 'mir, 'tcx>
152-
ValueVisitor<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
160+
impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>
161+
ValueVisitor<'mir, 'tcx, M>
153162
for
154-
InternVisitor<'rt, 'mir, 'tcx>
163+
InternVisitor<'rt, 'mir, 'tcx, M>
155164
{
156165
type V = MPlaceTy<'tcx>;
157166

158167
#[inline(always)]
159-
fn ecx(&self) -> &CompileTimeEvalContext<'mir, 'tcx> {
168+
fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
160169
&self.ecx
161170
}
162171

@@ -265,8 +274,8 @@ for
265274
}
266275
}
267276

268-
pub fn intern_const_alloc_recursive(
269-
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
277+
pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
278+
ecx: &mut InterpCx<'mir, 'tcx, M>,
270279
// The `mutability` of the place, ignoring the type.
271280
place_mut: Option<hir::Mutability>,
272281
ret: MPlaceTy<'tcx>,

src/librustc_mir/interpret/operand.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_macros::HashStable;
2727
/// operations and fat pointers. This idea was taken from rustc's codegen.
2828
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
2929
/// defined on `Immediate`, and do not have to work with a `Place`.
30-
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
30+
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)]
3131
pub enum Immediate<Tag=(), Id=AllocId> {
3232
Scalar(ScalarMaybeUndef<Tag, Id>),
3333
ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
@@ -104,7 +104,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
104104
/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
105105
/// or still in memory. The latter is an optimization, to delay reading that chunk of
106106
/// memory and to avoid having to store arbitrary-sized data here.
107-
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
107+
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)]
108108
pub enum Operand<Tag=(), Id=AllocId> {
109109
Immediate(Immediate<Tag, Id>),
110110
Indirect(MemPlace<Tag, Id>),
@@ -134,7 +134,7 @@ impl<Tag> Operand<Tag> {
134134
}
135135
}
136136

137-
#[derive(Copy, Clone, Debug, PartialEq)]
137+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
138138
pub struct OpTy<'tcx, Tag=()> {
139139
op: Operand<Tag>, // Keep this private; it helps enforce invariants.
140140
pub layout: TyLayout<'tcx>,

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2828
#![feature(range_is_empty)]
2929
#![feature(stmt_expr_attributes)]
3030
#![feature(bool_to_option)]
31+
#![feature(trait_alias)]
3132

3233
#![recursion_limit="256"]
3334

src/librustc_mir/transform/const_prop.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::interpret::{
3030
self, InterpCx, ScalarMaybeUndef, Immediate, OpTy,
3131
StackPopCleanup, LocalValue, LocalState, AllocId, Frame,
3232
Allocation, MemoryKind, ImmTy, Pointer, Memory, PlaceTy,
33-
Operand as InterpOperand,
33+
Operand as InterpOperand, intern_const_alloc_recursive,
3434
};
3535
use crate::const_eval::error_to_const_error;
3636
use crate::transform::{MirPass, MirSource};
@@ -647,9 +647,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
647647
}
648648

649649
fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
650-
if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
651-
return true;
652-
} else if self.tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
650+
let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
651+
652+
if mir_opt_level == 0 {
653653
return false;
654654
}
655655

@@ -659,6 +659,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
659659
interpret::Operand::Immediate(Immediate::ScalarPair(ScalarMaybeUndef::Scalar(l),
660660
ScalarMaybeUndef::Scalar(r))) =>
661661
l.is_bits() && r.is_bits(),
662+
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
663+
intern_const_alloc_recursive(
664+
&mut self.ecx,
665+
None,
666+
op.assert_mem_place()
667+
).expect("failed to intern alloc");
668+
true
669+
},
662670
_ => false
663671
}
664672
}

src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ fn main() {
2323
// START rustc.main.ConstProp.after.mir
2424
// bb0: {
2525
// ...
26-
// _4 = const Scalar(AllocId(1).0x0) : &i32;
27-
// _3 = const Scalar(AllocId(1).0x0) : &i32;
28-
// _2 = const Value(Scalar(AllocId(1).0x0)) : *const i32;
26+
// _4 = const main::FOO;
27+
// _3 = _4;
28+
// _2 = move _3 as *const i32 (Misc);
2929
// ...
3030
// _1 = move _2 as usize (Misc);
3131
// ...

src/test/mir-opt/const_prop/ref_deref.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn main() {
1414
// START rustc.main.ConstProp.after.mir
1515
// bb0: {
1616
// ...
17-
// _2 = const Scalar(AllocId(0).0x0) : &i32;
17+
// _2 = &(promoted[0]: i32);
1818
// _1 = const 4i32;
1919
// ...
2020
// }

src/test/mir-opt/const_prop/reify_fn_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn main() {
1616
// START rustc.main.ConstProp.after.mir
1717
// bb0: {
1818
// ...
19-
// _3 = const main;
19+
// _3 = const main as fn() (Pointer(ReifyFnPointer));
2020
// _2 = move _3 as usize (Misc);
2121
// ...
2222
// _1 = move _2 as *const fn() (Misc);

src/test/mir-opt/const_prop/slice_len.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ fn main() {
2424
// START rustc.main.ConstProp.after.mir
2525
// bb0: {
2626
// ...
27-
// _4 = const Scalar(AllocId(0).0x0) : &[u32; 3];
28-
// _3 = const Scalar(AllocId(0).0x0) : &[u32; 3];
27+
// _4 = &(promoted[0]: [u32; 3]);
28+
// _3 = _4;
2929
// _2 = move _3 as &[u32] (Pointer(Unsize));
3030
// ...
3131
// _6 = const 1usize;

src/test/ui/consts/issue-66345.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-pass
2+
// compile-flags: -Z mir-opt-level=3
3+
4+
// Checks that the compiler does not ICE when passing references to field of by-value struct
5+
// with -Z mir-opt-level=3
6+
7+
fn do_nothing(_: &()) {}
8+
9+
pub struct Foo {
10+
bar: (),
11+
}
12+
13+
pub fn by_value_1(foo: Foo) {
14+
do_nothing(&foo.bar);
15+
}
16+
17+
pub fn by_value_2<T>(foo: Foo) {
18+
do_nothing(&foo.bar);
19+
}
20+
21+
fn main() {
22+
by_value_1(Foo { bar: () });
23+
by_value_2::<()>(Foo { bar: () });
24+
}

0 commit comments

Comments
 (0)