Skip to content

Commit 22e6099

Browse files
committed
Auto merge of rust-lang#74717 - davidtwco:issue-74636-polymorphized-closures-inherited-params, r=oli-obk
mir: add `used_generic_parameters_needs_subst` Fixes rust-lang#74636. This PR adds a `used_generic_parameters_needs_subst` helper function which checks whether a type needs substitution, but only for parameters that the `unused_generic_params` query considers used. This is used in the MIR interpreter to make the check for some pointer casts and for reflection intrinsics more precise. I've opened this as a draft PR because this might not be the approach we want to fix this issue and we have to decide what to do about the reflection case. r? @eddyb cc @lcnr @wesleywiser
2 parents b544b43 + 59e621c commit 22e6099

File tree

7 files changed

+108
-20
lines changed

7 files changed

+108
-20
lines changed

src/librustc_mir/interpret/cast.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
88
use rustc_middle::mir::CastKind;
99
use rustc_middle::ty::adjustment::PointerCast;
1010
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
11-
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
11+
use rustc_middle::ty::{self, Ty, TypeAndMut};
1212
use rustc_span::symbol::sym;
1313
use rustc_target::abi::{Integer, LayoutOf, Variants};
1414

15-
use super::{truncate, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy};
15+
use super::{
16+
truncate, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy,
17+
PlaceTy,
18+
};
1619

1720
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1821
pub fn cast(
@@ -47,9 +50,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4750
match src.layout.ty.kind {
4851
ty::FnDef(def_id, substs) => {
4952
// All reifications must be monomorphic, bail out otherwise.
50-
if src.layout.ty.needs_subst() {
51-
throw_inval!(TooGeneric);
52-
}
53+
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
5354

5455
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
5556
span_bug!(
@@ -89,9 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8990
match src.layout.ty.kind {
9091
ty::Closure(def_id, substs) => {
9192
// All reifications must be monomorphic, bail out otherwise.
92-
if src.layout.ty.needs_subst() {
93-
throw_inval!(TooGeneric);
94-
}
93+
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
9594

9695
let instance = ty::Instance::resolve_closure(
9796
*self.tcx,

src/librustc_mir/interpret/intrinsics.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ use rustc_middle::mir::{
1212
};
1313
use rustc_middle::ty;
1414
use rustc_middle::ty::subst::SubstsRef;
15-
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
15+
use rustc_middle::ty::{Ty, TyCtxt};
1616
use rustc_span::symbol::{sym, Symbol};
1717
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
1818

19-
use super::{CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy};
19+
use super::{
20+
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
21+
};
2022

2123
mod caller_location;
2224
mod type_name;
@@ -54,9 +56,7 @@ crate fn eval_nullary_intrinsic<'tcx>(
5456
let name = tcx.item_name(def_id);
5557
Ok(match name {
5658
sym::type_name => {
57-
if tp_ty.needs_subst() {
58-
throw_inval!(TooGeneric);
59-
}
59+
ensure_monomorphic_enough(tcx, tp_ty)?;
6060
let alloc = type_name::alloc_type_name(tcx, tp_ty);
6161
ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
6262
}
@@ -72,9 +72,7 @@ crate fn eval_nullary_intrinsic<'tcx>(
7272
ConstValue::from_machine_usize(n, &tcx)
7373
}
7474
sym::type_id => {
75-
if tp_ty.needs_subst() {
76-
throw_inval!(TooGeneric);
77-
}
75+
ensure_monomorphic_enough(tcx, tp_ty)?;
7876
ConstValue::from_u64(tcx.type_id_hash(tp_ty))
7977
}
8078
sym::variant_count => {

src/librustc_mir/interpret/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod place;
1212
mod step;
1313
mod terminator;
1414
mod traits;
15+
mod util;
1516
mod validity;
1617
mod visitor;
1718

src/librustc_mir/interpret/traits.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::convert::TryFrom;
22

33
use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
4-
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
4+
use rustc_middle::ty::{self, Instance, Ty};
55
use rustc_target::abi::{Align, LayoutOf, Size};
66

7+
use super::util::ensure_monomorphic_enough;
78
use super::{FnVal, InterpCx, Machine, MemoryKind};
89

910
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -23,9 +24,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2324
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
2425

2526
// All vtables must be monomorphic, bail out otherwise.
26-
if ty.needs_subst() || poly_trait_ref.needs_subst() {
27-
throw_inval!(TooGeneric);
28-
}
27+
ensure_monomorphic_enough(*self.tcx, ty)?;
28+
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
2929

3030
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
3131
// This means we guarantee that there are no duplicate vtables, we will

src/librustc_mir/interpret/util.rs

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use rustc_middle::mir::interpret::InterpResult;
2+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
3+
use std::convert::TryInto;
4+
5+
/// Returns `true` if a used generic parameter requires substitution.
6+
crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
7+
where
8+
T: TypeFoldable<'tcx>,
9+
{
10+
debug!("ensure_monomorphic_enough: ty={:?}", ty);
11+
if !ty.needs_subst() {
12+
return Ok(());
13+
}
14+
15+
struct UsedParamsNeedSubstVisitor<'tcx> {
16+
tcx: TyCtxt<'tcx>,
17+
};
18+
19+
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
20+
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
21+
if !c.needs_subst() {
22+
return false;
23+
}
24+
25+
match c.val {
26+
ty::ConstKind::Param(..) => true,
27+
_ => c.super_visit_with(self),
28+
}
29+
}
30+
31+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
32+
if !ty.needs_subst() {
33+
return false;
34+
}
35+
36+
match ty.kind {
37+
ty::Param(_) => true,
38+
ty::Closure(def_id, substs)
39+
| ty::Generator(def_id, substs, ..)
40+
| ty::FnDef(def_id, substs) => {
41+
let unused_params = self.tcx.unused_generic_params(def_id);
42+
for (index, subst) in substs.into_iter().enumerate() {
43+
let index = index
44+
.try_into()
45+
.expect("more generic parameters than can fit into a `u32`");
46+
let is_used =
47+
unused_params.contains(index).map(|unused| !unused).unwrap_or(true);
48+
// Only recurse when generic parameters in fns, closures and generators
49+
// are used and require substitution.
50+
if is_used && subst.needs_subst() {
51+
// Just in case there are closures or generators within this subst,
52+
// recurse.
53+
if subst.super_visit_with(self) {
54+
// Only return when we find a parameter so the remaining substs
55+
// are not skipped.
56+
return true;
57+
}
58+
}
59+
}
60+
false
61+
}
62+
_ => ty.super_visit_with(self),
63+
}
64+
}
65+
}
66+
67+
let mut vis = UsedParamsNeedSubstVisitor { tcx };
68+
if ty.visit_with(&mut vis) {
69+
throw_inval!(TooGeneric);
70+
} else {
71+
Ok(())
72+
}
73+
}

src/test/ui/issues/issue-74614.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// compile-flags:-Zpolymorphize=on
12
// build-pass
23

34
fn test<T>() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// compile-flags:-Zpolymorphize=on
2+
// build-pass
3+
4+
use std::any::TypeId;
5+
6+
pub fn foo<T: 'static>(_: T) -> TypeId {
7+
TypeId::of::<T>()
8+
}
9+
10+
fn outer<T: 'static>() {
11+
foo(|| ());
12+
}
13+
14+
fn main() {
15+
outer::<u8>();
16+
}

0 commit comments

Comments
 (0)