Skip to content

Don't inline functions with unsized args #111424

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

Merged
merged 1 commit into from
May 21, 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
15 changes: 12 additions & 3 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,18 @@ impl<'tcx> Inliner<'tcx> {
) -> 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)?;
Expand All @@ -189,9 +201,6 @@ impl<'tcx> Inliner<'tcx> {
// 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);
Expand Down
50 changes: 50 additions & 0 deletions tests/mir-opt/inline/unsized_argument.caller.Inline.diff
Original file line number Diff line number Diff line change
@@ -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>) }
}
}

15 changes: 15 additions & 0 deletions tests/mir-opt/inline/unsized_argument.rs
Original file line number Diff line number Diff line change
@@ -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);
}