Skip to content

Commit 7858dc2

Browse files
committed
Auto merge of #63497 - eddyb:miri-subst, r=oli-obk
rustc_mir: fix miri substitution/"universe" discipline. Alternative to #61041, based on @RalfJung's own attempt at it. I haven't done a full audit, but I believe everything is fixed now. Fixes #61432. Closes #61336, as a drive-by fix (for a subset of #43408, that is already special-cased). r? @oli-obk / @RalfJung cc @varkor @yodaldevoid
2 parents d8d99ba + 96fc989 commit 7858dc2

File tree

11 files changed

+159
-76
lines changed

11 files changed

+159
-76
lines changed

src/librustc_mir/interpret/cast.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc::ty::{self, Ty, TypeAndMut};
1+
use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
22
use rustc::ty::layout::{self, TyLayout, Size};
33
use rustc::ty::adjustment::{PointerCast};
44
use syntax::ast::FloatTy;
@@ -36,15 +36,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3636
// The src operand does not matter, just its type
3737
match src.layout.ty.sty {
3838
ty::FnDef(def_id, substs) => {
39+
// All reifications must be monomorphic, bail out otherwise.
40+
if src.layout.ty.needs_subst() {
41+
throw_inval!(TooGeneric);
42+
}
43+
3944
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
4045
bug!("reifying a fn ptr that requires const arguments");
4146
}
42-
let instance = ty::Instance::resolve(
43-
*self.tcx,
44-
self.param_env,
45-
def_id,
46-
substs,
47-
).ok_or_else(|| err_inval!(TooGeneric))?;
47+
let instance = self.resolve(def_id, substs)?;
4848
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
4949
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
5050
}
@@ -67,7 +67,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6767
// The src operand does not matter, just its type
6868
match src.layout.ty.sty {
6969
ty::Closure(def_id, substs) => {
70-
let substs = self.subst_and_normalize_erasing_regions(substs)?;
70+
// All reifications must be monomorphic, bail out otherwise.
71+
if src.layout.ty.needs_subst() {
72+
throw_inval!(TooGeneric);
73+
}
74+
7175
let instance = ty::Instance::resolve_closure(
7276
*self.tcx,
7377
def_id,

src/librustc_mir/interpret/eval_context.rs

+29-60
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc::mir;
99
use rustc::ty::layout::{
1010
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
1111
};
12-
use rustc::ty::subst::{Subst, SubstsRef};
12+
use rustc::ty::subst::SubstsRef;
1313
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
1414
use rustc::ty::query::TyCtxtAt;
1515
use rustc_data_structures::indexed_vec::IndexVec;
@@ -291,41 +291,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
291291
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
292292
}
293293

294-
pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
295-
&self,
296-
substs: T,
297-
) -> InterpResult<'tcx, T> {
298-
match self.stack.last() {
299-
Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions(
300-
frame.instance.substs,
301-
self.param_env,
302-
&substs,
303-
)),
304-
None => if substs.needs_subst() {
305-
throw_inval!(TooGeneric)
306-
} else {
307-
Ok(substs)
308-
},
309-
}
310-
}
311-
312-
pub(super) fn resolve(
313-
&self,
314-
def_id: DefId,
315-
substs: SubstsRef<'tcx>
316-
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
317-
trace!("resolve: {:?}, {:#?}", def_id, substs);
318-
trace!("param_env: {:#?}", self.param_env);
319-
let substs = self.subst_and_normalize_erasing_regions(substs)?;
320-
trace!("substs: {:#?}", substs);
321-
ty::Instance::resolve(
322-
*self.tcx,
323-
self.param_env,
324-
def_id,
325-
substs,
326-
).ok_or_else(|| err_inval!(TooGeneric).into())
327-
}
328-
329294
pub fn load_mir(
330295
&self,
331296
instance: ty::InstanceDef<'tcx>,
@@ -349,34 +314,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
349314
}
350315
}
351316

352-
pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
317+
/// Call this on things you got out of the MIR (so it is as generic as the current
318+
/// stack frame), to bring it into the proper environment for this interpreter.
319+
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
353320
&self,
354-
t: T,
355-
) -> InterpResult<'tcx, T> {
356-
match self.stack.last() {
357-
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
358-
None => if t.needs_subst() {
359-
throw_inval!(TooGeneric)
360-
} else {
361-
Ok(t)
362-
},
363-
}
321+
value: T,
322+
) -> T {
323+
self.tcx.subst_and_normalize_erasing_regions(
324+
self.frame().instance.substs,
325+
self.param_env,
326+
&value,
327+
)
364328
}
365329

366-
fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>(
330+
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
331+
pub(super) fn resolve(
367332
&self,
368-
t: T,
333+
def_id: DefId,
369334
substs: SubstsRef<'tcx>
370-
) -> InterpResult<'tcx, T> {
371-
// miri doesn't care about lifetimes, and will choke on some crazy ones
372-
// let's simply get rid of them
373-
let substituted = t.subst(*self.tcx, substs);
374-
375-
if substituted.needs_subst() {
376-
throw_inval!(TooGeneric)
377-
}
378-
379-
Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
335+
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
336+
trace!("resolve: {:?}, {:#?}", def_id, substs);
337+
trace!("param_env: {:#?}", self.param_env);
338+
trace!("substs: {:#?}", substs);
339+
ty::Instance::resolve(
340+
*self.tcx,
341+
self.param_env,
342+
def_id,
343+
substs,
344+
).ok_or_else(|| err_inval!(TooGeneric).into())
380345
}
381346

382347
pub fn layout_of_local(
@@ -391,7 +356,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
391356
None => {
392357
let layout = crate::interpret::operand::from_known_layout(layout, || {
393358
let local_ty = frame.body.local_decls[local].ty;
394-
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
359+
let local_ty = self.tcx.subst_and_normalize_erasing_regions(
360+
frame.instance.substs,
361+
self.param_env,
362+
&local_ty,
363+
);
395364
self.layout_of(local_ty)
396365
})?;
397366
if let Some(state) = frame.locals.get(local) {

src/librustc_mir/interpret/operand.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
522522
Move(ref place) =>
523523
self.eval_place_to_op(place, layout)?,
524524

525-
Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?,
525+
Constant(ref constant) => {
526+
let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal);
527+
self.eval_const_to_op(val, layout)?
528+
}
526529
};
527530
trace!("{:?}: {:?}", mir_op, *op);
528531
Ok(op)
@@ -540,6 +543,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
540543

541544
// Used when the miri-engine runs into a constant and for extracting information from constants
542545
// in patterns via the `const_eval` module
546+
/// The `val` and `layout` are assumed to already be in our interpreter
547+
/// "universe" (param_env).
543548
crate fn eval_const_to_op(
544549
&self,
545550
val: &'tcx ty::Const<'tcx>,
@@ -552,7 +557,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
552557
// Early-return cases.
553558
match val.val {
554559
ConstValue::Param(_) =>
555-
// FIXME(oli-obk): try to monomorphize
556560
throw_inval!(TooGeneric),
557561
ConstValue::Unevaluated(def_id, substs) => {
558562
let instance = self.resolve(def_id, substs)?;
@@ -565,7 +569,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
565569
}
566570
// Other cases need layout.
567571
let layout = from_known_layout(layout, || {
568-
self.layout_of(self.monomorphize(val.ty)?)
572+
self.layout_of(val.ty)
569573
})?;
570574
let op = match val.val {
571575
ConstValue::ByRef { alloc, offset } => {

src/librustc_mir/interpret/place.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,11 @@ where
640640
// their layout on return.
641641
PlaceTy {
642642
place: *return_place,
643-
layout: self
644-
.layout_of(self.monomorphize(self.frame().body.return_ty())?)?,
643+
layout: self.layout_of(
644+
self.subst_from_frame_and_normalize_erasing_regions(
645+
self.frame().body.return_ty()
646+
)
647+
)?,
645648
}
646649
}
647650
None => throw_unsup!(InvalidNullPointerUsage),

src/librustc_mir/interpret/step.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
254254
}
255255

256256
NullaryOp(mir::NullOp::SizeOf, ty) => {
257-
let ty = self.monomorphize(ty)?;
257+
let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
258258
let layout = self.layout_of(ty)?;
259259
assert!(!layout.is_unsized(),
260260
"SizeOf nullary MIR operator called for unsized type");

src/librustc_mir/interpret/traits.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc::ty::{self, Ty, Instance};
1+
use rustc::ty::{self, Ty, Instance, TypeFoldable};
22
use rustc::ty::layout::{Size, Align, LayoutOf};
33
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
44

@@ -20,6 +20,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2020

2121
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
2222

23+
// All vtables must be monomorphic, bail out otherwise.
24+
if ty.needs_subst() || poly_trait_ref.needs_subst() {
25+
throw_inval!(TooGeneric);
26+
}
27+
2328
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
2429
// This means we guarantee that there are no duplicate vtables, we will
2530
// always use the same vtable for the same (Type, Trait) combination.
@@ -77,7 +82,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7782
for (i, method) in methods.iter().enumerate() {
7883
if let Some((def_id, substs)) = *method {
7984
// resolve for vtable: insert shims where needed
80-
let substs = self.subst_and_normalize_erasing_regions(substs)?;
8185
let instance = ty::Instance::resolve_for_vtable(
8286
*self.tcx,
8387
self.param_env,

src/librustc_typeck/collect.rs

+14
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,20 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
900900
let parent_id = tcx.hir().get_parent_item(hir_id);
901901
Some(tcx.hir().local_def_id(parent_id))
902902
}
903+
// FIXME(#43408) enable this in all cases when we get lazy normalization.
904+
Node::AnonConst(&anon_const) => {
905+
// HACK(eddyb) this provides the correct generics when the workaround
906+
// for a const parameter `AnonConst` is being used elsewhere, as then
907+
// there won't be the kind of cyclic dependency blocking #43408.
908+
let expr = &tcx.hir().body(anon_const.body).value;
909+
let icx = ItemCtxt::new(tcx, def_id);
910+
if AstConv::const_param_def_id(&icx, expr).is_some() {
911+
let parent_id = tcx.hir().get_parent_item(hir_id);
912+
Some(tcx.hir().local_def_id(parent_id))
913+
} else {
914+
None
915+
}
916+
}
903917
Node::Expr(&hir::Expr {
904918
node: hir::ExprKind::Closure(..),
905919
..
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-pass
2+
3+
#![feature(const_generics)]
4+
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
5+
6+
fn promote<const N: i32>() {
7+
// works:
8+
//
9+
// let n = N;
10+
// &n;
11+
12+
&N;
13+
}
14+
15+
fn main() {
16+
promote::<0>();
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
2+
--> $DIR/issue-61432.rs:3:12
3+
|
4+
LL | #![feature(const_generics)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub struct Foo<A, B>(A, B);
2+
3+
impl<A, B> Foo<A, B> {
4+
const HOST_SIZE: usize = std::mem::size_of::<B>();
5+
6+
pub fn crash() -> bool {
7+
[5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE`
8+
//~^ the size for values of type `A` cannot be known
9+
//~| the size for values of type `B` cannot be known
10+
}
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0599]: no associated item named `HOST_SIZE` found for type `Foo<A, B>` in the current scope
2+
--> $DIR/too_generic_eval_ice.rs:7:19
3+
|
4+
LL | pub struct Foo<A, B>(A, B);
5+
| --------------------------- associated item `HOST_SIZE` not found for this
6+
...
7+
LL | [5; Self::HOST_SIZE] == [6; 0]
8+
| ^^^^^^^^^ associated item not found in `Foo<A, B>`
9+
|
10+
= note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied:
11+
`A : std::marker::Sized`
12+
`B : std::marker::Sized`
13+
14+
error[E0277]: the size for values of type `A` cannot be known at compilation time
15+
--> $DIR/too_generic_eval_ice.rs:7:13
16+
|
17+
LL | [5; Self::HOST_SIZE] == [6; 0]
18+
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
19+
|
20+
= help: the trait `std::marker::Sized` is not implemented for `A`
21+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
22+
= help: consider adding a `where A: std::marker::Sized` bound
23+
note: required by `Foo`
24+
--> $DIR/too_generic_eval_ice.rs:1:1
25+
|
26+
LL | pub struct Foo<A, B>(A, B);
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
29+
error[E0277]: the size for values of type `B` cannot be known at compilation time
30+
--> $DIR/too_generic_eval_ice.rs:7:13
31+
|
32+
LL | [5; Self::HOST_SIZE] == [6; 0]
33+
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
34+
|
35+
= help: the trait `std::marker::Sized` is not implemented for `B`
36+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
37+
= help: consider adding a `where B: std::marker::Sized` bound
38+
note: required by `Foo`
39+
--> $DIR/too_generic_eval_ice.rs:1:1
40+
|
41+
LL | pub struct Foo<A, B>(A, B);
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
43+
44+
error: aborting due to 3 previous errors
45+
46+
Some errors have detailed explanations: E0277, E0599.
47+
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)