Don't inline functions with unsized args

This commit is contained in:
Jakob Degen 2023-05-10 03:23:07 -07:00
parent fe76e14955
commit 60cc72cf7b
3 changed files with 77 additions and 3 deletions

View File

@ -168,6 +168,18 @@ fn try_inlining(
) -> Result<std::ops::Range<BasicBlock>, &'static str> {
let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
self.check_codegen_attributes(callsite, callee_attrs)?;
let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
for arg in args {
if !arg.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) {
// We do not allow inlining functions with unsized params. Inlining these functions
// could create unsized locals, which are unsound and being phased out.
return Err("Call has unsized argument");
}
}
self.check_mir_is_available(caller_body, &callsite.callee)?;
let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
self.check_mir_body(callsite, callee_body, callee_attrs)?;
@ -189,9 +201,6 @@ fn try_inlining(
// Check call signature compatibility.
// Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE.
let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
let output_type = callee_body.return_ty();
if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
trace!(?output_type, ?destination_ty);

View File

@ -0,0 +1,50 @@
- // MIR for `caller` before Inline
+ // MIR for `caller` after Inline
fn caller(_1: Box<[i32]>) -> () {
debug x => _1; // in scope 0 at $DIR/unsized_argument.rs:+0:11: +0:12
let mut _0: (); // return place in scope 0 at $DIR/unsized_argument.rs:+0:26: +0:26
let _2: (); // in scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15
let mut _3: std::boxed::Box<[i32]>; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14
let mut _4: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
let mut _5: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
let mut _6: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
let mut _7: *const [i32]; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14
bb0: {
StorageLive(_2); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15
StorageLive(_3); // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14
_3 = move _1; // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14
_7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15
_2 = callee(move (*_7)) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15
// mir::Constant
// + span: $DIR/unsized_argument.rs:9:5: 9:11
// + literal: Const { ty: fn([i32]) {callee}, val: Value(<ZST>) }
}
bb1: {
StorageDead(_3); // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
StorageDead(_2); // scope 0 at $DIR/unsized_argument.rs:+1:15: +1:16
_0 = const (); // scope 0 at $DIR/unsized_argument.rs:+0:26: +2:2
return; // scope 0 at $DIR/unsized_argument.rs:+2:2: +2:2
}
bb2 (cleanup): {
resume; // scope 0 at $DIR/unsized_argument.rs:+0:1: +2:2
}
bb3: {
_4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
// mir::Constant
// + span: $DIR/unsized_argument.rs:9:14: 9:15
// + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) }
}
bb4 (cleanup): {
_6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate]; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15
// mir::Constant
// + span: $DIR/unsized_argument.rs:9:14: 9:15
// + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) }
}
}

View File

@ -0,0 +1,15 @@
// needs-unwind
#![feature(unsized_fn_params)]
#[inline(always)]
fn callee(y: [i32]) {}
// EMIT_MIR unsized_argument.caller.Inline.diff
fn caller(x: Box<[i32]>) {
callee(*x);
}
fn main() {
let b = Box::new([1]);
caller(b);
}