diff options
author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2023-05-17 19:11:53 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-17 19:11:53 +0530 |
commit | 828caa80a942e9e923b75e4806da93c6e85f9752 (patch) | |
tree | a2ca1d67699dd7764109d37be32acec05f3562d1 | |
parent | c2ccc855e74aec03e434405eca3c247ee2432e53 (diff) | |
parent | e7a2f52ba163a47e751b6e6d666b52c2acdd0949 (diff) | |
download | rust-828caa80a942e9e923b75e4806da93c6e85f9752.tar.gz |
Rollup merge of #110930 - b-naber:normalize-elaborate-drops, r=cjgillot
Don't expect normalization to succeed in elaborate_drops
Fixes https://github.com/rust-lang/rust/issues/110682
This was exposed through the changes in https://github.com/rust-lang/rust/pull/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.~
-rw-r--r-- | compiler/rustc_mir_dataflow/src/elaborate_drops.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_mir_transform/src/inline.rs | 27 | ||||
-rw-r--r-- | tests/ui/drop/issue-110682.rs | 92 |
3 files changed, 119 insertions, 1 deletions
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 2e68c794356..18895072c3b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -276,6 +276,7 @@ where assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); let field_ty = tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); + (tcx.mk_place_field(base_place, field, field_ty), subpath) }) .collect() diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ece20d8d3e6..12f955d46bd 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -7,6 +7,7 @@ use rustc_index::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; @@ -168,7 +169,7 @@ impl<'tcx> Inliner<'tcx> { let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); self.check_codegen_attributes(callsite, callee_attrs)?; self.check_mir_is_available(caller_body, &callsite.callee)?; - let callee_body = self.tcx.instance_mir(callsite.callee.def); + let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?; self.check_mir_body(callsite, callee_body, callee_attrs)?; if !self.tcx.consider_optimizing(|| { @@ -1128,3 +1129,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } } } + +#[instrument(skip(tcx), level = "debug")] +fn try_instance_mir<'tcx>( + tcx: TyCtxt<'tcx>, + instance: InstanceDef<'tcx>, +) -> Result<&'tcx Body<'tcx>, &'static str> { + match instance { + ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() { + ty::Adt(def, substs) => { + let fields = def.all_fields(); + for field in fields { + let field_ty = field.ty(tcx, substs); + if field_ty.has_param() && field_ty.has_projections() { + return Err("cannot build drop shim for polymorphic type"); + } + } + + Ok(tcx.instance_mir(instance)) + } + _ => Ok(tcx.instance_mir(instance)), + }, + _ => Ok(tcx.instance_mir(instance)), + } +} diff --git a/tests/ui/drop/issue-110682.rs b/tests/ui/drop/issue-110682.rs new file mode 100644 index 00000000000..35f9c7e8d9b --- /dev/null +++ b/tests/ui/drop/issue-110682.rs @@ -0,0 +1,92 @@ +// build-pass +// compile-flags: -Zmir-opt-level=3 + +use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::ptr; + +pub trait BitRegister {} + +macro_rules! register { + ($($t:ty),+ $(,)?) => { $( + impl BitRegister for $t { + } + )* }; +} + +register!(u8, u16, u32); + +pub trait BitStore: Sized + Debug { + /// The register type that the implementor describes. + type Mem: BitRegister + Into<Self>; +} + +macro_rules! store { + ($($t:ty),+ $(,)?) => { $( + impl BitStore for $t { + type Mem = Self; + } + )+ }; +} + +store!(u8, u16, u32,); + +#[repr(C)] +pub struct BitVec<T> +where + T: BitStore, +{ + /// Region pointer describing the live portion of the owned buffer. + pointer: ptr::NonNull<T>, + /// Allocated capacity, in elements `T`, of the owned buffer. + capacity: usize, +} + +impl<T> BitVec<T> +where + T: BitStore, +{ + pub fn new() -> Self { + let pointer = ptr::NonNull::<T>::new(ptr::null_mut()).unwrap(); + + BitVec { pointer, capacity: 10 } + } + + pub fn clear(&mut self) { + unsafe { + self.set_len(0); + } + } + + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) {} + + fn with_vec<F, R>(&mut self, func: F) -> R + where + F: FnOnce(&mut ManuallyDrop<Vec<T::Mem>>) -> R, + { + let cap = self.capacity; + let elts = 10; + let mut vec = ManuallyDrop::new(unsafe { Vec::from_raw_parts(ptr::null_mut(), elts, cap) }); + let out = func(&mut vec); + + out + } +} + +impl<T> Drop for BitVec<T> +where + T: BitStore, +{ + #[inline] + fn drop(&mut self) { + // The buffer elements do not have destructors. + self.clear(); + // Run the `Vec` destructor to deƤllocate the buffer. + self.with_vec(|vec| unsafe { ManuallyDrop::drop(vec) }); + } +} + +fn main() { + let bitvec = BitVec::<u32>::new(); +} |