Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't build drop shim for polymorphic types #110930

Merged
merged 3 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_mir_dataflow/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
27 changes: 26 additions & 1 deletion compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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(|| {
Expand Down Expand Up @@ -1124,3 +1125,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) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want to do this in a more generalized way. I believe the normalization in move_paths_for_fields is the only place where building drop shims can go wrong, so rejecting those types here should be sufficient (though this change feels a little hacky).

Rejecting these here seemed preferable to me compared to making changes in the shim/drop elaboration code.

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)),
}
}
92 changes: 92 additions & 0 deletions tests/ui/drop/issue-110682.rs
Original file line number Diff line number Diff line change
@@ -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();
}