Skip to content

Commit 828caa8

Browse files
authored
Rollup merge of #110930 - b-naber:normalize-elaborate-drops, r=cjgillot
Don't expect normalization to succeed in elaborate_drops Fixes #110682 This was exposed through the changes in #109247, which causes more things to be inlined. Inlining can happen before monomorphization, so we can't expect normalization to succeed. In the elaborate_drops analysis we currently have [this call](https://github.com/rust-lang/rust/blob/033aa092ab23ba14cdad27073c5e37ba0eddb428/compiler/rustc_mir_dataflow/src/elaborate_drops.rs#L278) to `normalize_erasing_regions`, which ICEs when normalization fails. The types are used to infer [whether the type needs a drop](https://github.com/rust-lang/rust/blob/033aa092ab23ba14cdad27073c5e37ba0eddb428/compiler/rustc_mir_dataflow/src/elaborate_drops.rs#L374), where `needs_drop` itself [uses `try_normalize_erasing_regions`](https://github.com/rust-lang/rust/blob/033aa092ab23ba14cdad27073c5e37ba0eddb428/compiler/rustc_middle/src/ty/util.rs#L1121). ~[`instance_mir`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.instance_mir) isn't explicit about whether it expects the instances corresponding to the `InstanceDef`s to be monomorphized (though I think in all other contexts the function is used post-monomorphization), so the use of `instance_mir` in inlining doesn't necessarily seem wrong to me.~
2 parents c2ccc85 + e7a2f52 commit 828caa8

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed

compiler/rustc_mir_dataflow/src/elaborate_drops.rs

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ where
276276
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
277277
let field_ty =
278278
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
279+
279280
(tcx.mk_place_field(base_place, field, field_ty), subpath)
280281
})
281282
.collect()

compiler/rustc_mir_transform/src/inline.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_index::Idx;
77
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
88
use rustc_middle::mir::visit::*;
99
use rustc_middle::mir::*;
10+
use rustc_middle::ty::TypeVisitableExt;
1011
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
1112
use rustc_session::config::OptLevel;
1213
use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
@@ -168,7 +169,7 @@ impl<'tcx> Inliner<'tcx> {
168169
let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
169170
self.check_codegen_attributes(callsite, callee_attrs)?;
170171
self.check_mir_is_available(caller_body, &callsite.callee)?;
171-
let callee_body = self.tcx.instance_mir(callsite.callee.def);
172+
let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
172173
self.check_mir_body(callsite, callee_body, callee_attrs)?;
173174

174175
if !self.tcx.consider_optimizing(|| {
@@ -1128,3 +1129,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
11281129
}
11291130
}
11301131
}
1132+
1133+
#[instrument(skip(tcx), level = "debug")]
1134+
fn try_instance_mir<'tcx>(
1135+
tcx: TyCtxt<'tcx>,
1136+
instance: InstanceDef<'tcx>,
1137+
) -> Result<&'tcx Body<'tcx>, &'static str> {
1138+
match instance {
1139+
ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() {
1140+
ty::Adt(def, substs) => {
1141+
let fields = def.all_fields();
1142+
for field in fields {
1143+
let field_ty = field.ty(tcx, substs);
1144+
if field_ty.has_param() && field_ty.has_projections() {
1145+
return Err("cannot build drop shim for polymorphic type");
1146+
}
1147+
}
1148+
1149+
Ok(tcx.instance_mir(instance))
1150+
}
1151+
_ => Ok(tcx.instance_mir(instance)),
1152+
},
1153+
_ => Ok(tcx.instance_mir(instance)),
1154+
}
1155+
}

tests/ui/drop/issue-110682.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// build-pass
2+
// compile-flags: -Zmir-opt-level=3
3+
4+
use std::fmt::Debug;
5+
use std::mem::ManuallyDrop;
6+
use std::ptr;
7+
8+
pub trait BitRegister {}
9+
10+
macro_rules! register {
11+
($($t:ty),+ $(,)?) => { $(
12+
impl BitRegister for $t {
13+
}
14+
)* };
15+
}
16+
17+
register!(u8, u16, u32);
18+
19+
pub trait BitStore: Sized + Debug {
20+
/// The register type that the implementor describes.
21+
type Mem: BitRegister + Into<Self>;
22+
}
23+
24+
macro_rules! store {
25+
($($t:ty),+ $(,)?) => { $(
26+
impl BitStore for $t {
27+
type Mem = Self;
28+
}
29+
)+ };
30+
}
31+
32+
store!(u8, u16, u32,);
33+
34+
#[repr(C)]
35+
pub struct BitVec<T>
36+
where
37+
T: BitStore,
38+
{
39+
/// Region pointer describing the live portion of the owned buffer.
40+
pointer: ptr::NonNull<T>,
41+
/// Allocated capacity, in elements `T`, of the owned buffer.
42+
capacity: usize,
43+
}
44+
45+
impl<T> BitVec<T>
46+
where
47+
T: BitStore,
48+
{
49+
pub fn new() -> Self {
50+
let pointer = ptr::NonNull::<T>::new(ptr::null_mut()).unwrap();
51+
52+
BitVec { pointer, capacity: 10 }
53+
}
54+
55+
pub fn clear(&mut self) {
56+
unsafe {
57+
self.set_len(0);
58+
}
59+
}
60+
61+
#[inline]
62+
pub unsafe fn set_len(&mut self, new_len: usize) {}
63+
64+
fn with_vec<F, R>(&mut self, func: F) -> R
65+
where
66+
F: FnOnce(&mut ManuallyDrop<Vec<T::Mem>>) -> R,
67+
{
68+
let cap = self.capacity;
69+
let elts = 10;
70+
let mut vec = ManuallyDrop::new(unsafe { Vec::from_raw_parts(ptr::null_mut(), elts, cap) });
71+
let out = func(&mut vec);
72+
73+
out
74+
}
75+
}
76+
77+
impl<T> Drop for BitVec<T>
78+
where
79+
T: BitStore,
80+
{
81+
#[inline]
82+
fn drop(&mut self) {
83+
// The buffer elements do not have destructors.
84+
self.clear();
85+
// Run the `Vec` destructor to deällocate the buffer.
86+
self.with_vec(|vec| unsafe { ManuallyDrop::drop(vec) });
87+
}
88+
}
89+
90+
fn main() {
91+
let bitvec = BitVec::<u32>::new();
92+
}

0 commit comments

Comments
 (0)