Skip to content

Commit 622821a

Browse files
committed
Increase the precision of the exportable MIR check
1 parent 7820972 commit 622821a

17 files changed

+195
-124
lines changed

compiler/rustc_mir_transform/src/inline.rs

+61-10
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ impl<'tcx> Inliner<'tcx> {
184184

185185
self.check_mir_is_available(caller_body, &callsite.callee)?;
186186
let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
187+
self.check_mir_is_exportable(&callsite.callee, callee_attrs, callee_body)?;
187188
self.check_mir_body(callsite, callee_body, callee_attrs)?;
188189

189190
if !self.tcx.consider_optimizing(|| {
@@ -353,6 +354,44 @@ impl<'tcx> Inliner<'tcx> {
353354
None
354355
}
355356

357+
fn check_mir_is_exportable(
358+
&self,
359+
callee: &Instance<'tcx>,
360+
callee_attrs: &CodegenFnAttrs,
361+
callee_body: &Body<'tcx>,
362+
) -> Result<(), &'static str> {
363+
if !callee.def_id().is_local() {
364+
return Ok(());
365+
}
366+
if self.tcx.is_constructor(callee.def_id()) {
367+
return Ok(());
368+
}
369+
if callee_attrs.requests_inline() {
370+
return Ok(());
371+
}
372+
let is_generic = callee.substs.non_erasable_generics().next().is_some();
373+
if is_generic {
374+
return Ok(());
375+
}
376+
377+
// So now we are trying to inline a function from another crate which is not inline and is
378+
// not a generic. This might work. But if this pulls in a symbol from the other crater, we
379+
// will fail to link.
380+
// So this is our heuritic for handling this:
381+
// If this function has any calls in it, that might reference an internal symbol.
382+
// If this function contains a pointer constant, that might be a reference to an internal
383+
// static.
384+
// So if either of those conditions are met, we cannot inline this.
385+
if self.tcx.mir_inliner_callees(callee.def).is_empty()
386+
&& !contains_pointer_constant(callee_body)
387+
{
388+
debug!("Has no calls and no pointer constants, must be exportable");
389+
return Ok(());
390+
}
391+
392+
Err("not exported")
393+
}
394+
356395
/// Returns an error if inlining is not possible based on codegen attributes alone. A success
357396
/// indicates that inlining decision should be based on other criteria.
358397
fn check_codegen_attributes(
@@ -364,16 +403,6 @@ impl<'tcx> Inliner<'tcx> {
364403
return Err("never inline hint");
365404
}
366405

367-
// Only inline local functions if they would be eligible for cross-crate
368-
// inlining. This is to ensure that the final crate doesn't have MIR that
369-
// reference unexported symbols
370-
if callsite.callee.def_id().is_local() {
371-
let is_generic = callsite.callee.substs.non_erasable_generics().next().is_some();
372-
if !is_generic && !callee_attrs.requests_inline() {
373-
return Err("not exported");
374-
}
375-
}
376-
377406
if callsite.fn_sig.c_variadic() {
378407
return Err("C variadic");
379408
}
@@ -1147,3 +1176,25 @@ fn try_instance_mir<'tcx>(
11471176
_ => Ok(tcx.instance_mir(instance)),
11481177
}
11491178
}
1179+
1180+
fn contains_pointer_constant(body: &Body<'_>) -> bool {
1181+
let mut finder = ConstFinder { found: false };
1182+
finder.visit_body(body);
1183+
finder.found
1184+
}
1185+
1186+
struct ConstFinder {
1187+
found: bool,
1188+
}
1189+
1190+
impl Visitor<'_> for ConstFinder {
1191+
fn visit_constant(&mut self, constant: &Constant<'_>, location: Location) {
1192+
debug!("Visiting constant: {:?}", constant.literal);
1193+
if let ConstantKind::Val(_val, ty) = constant.literal {
1194+
if ty.is_any_ptr() || ty.is_fn() {
1195+
self.found = true;
1196+
}
1197+
}
1198+
self.super_constant(constant, location);
1199+
}
1200+
}

tests/codegen-units/item-collection/items-within-generic-items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![deny(dead_code)]
44
#![feature(start)]
55

6+
#[inline(never)]
67
fn generic_fn<T>(a: T) -> (T, i32) {
78
//~ MONO_ITEM fn generic_fn::nested_fn
89
fn nested_fn(a: i32) -> i32 {

tests/codegen/call-metadata.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub fn test() {
1212
}
1313

1414
#[no_mangle]
15+
#[inline(never)]
1516
fn some_true() -> Option<bool> {
1617
Some(true)
1718
}

tests/codegen/cold-call-declare-and-call.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// CHECK: call coldcc void @this_should_never_happen(i16
1010

1111
#[no_mangle]
12+
#[inline(never)]
1213
pub extern "rust-cold" fn this_should_never_happen(x: u16) {}
1314

1415
pub fn do_things(x: u16) {

tests/codegen/drop.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Drop for SomeUniqueName {
1111
}
1212
}
1313

14+
#[inline(never)]
1415
pub fn possibly_unwinding() {
1516
}
1617

tests/codegen/personality_lifetimes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ impl Drop for S {
1313
}
1414
}
1515

16+
#[inline(never)]
1617
fn might_unwind() {
1718
}
1819

tests/codegen/target-cpu-on-functions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pub extern "C" fn exported() {
1515

1616
// CHECK-LABEL: ; target_cpu_on_functions::not_exported
1717
// CHECK-NEXT: ; Function Attrs:
18-
// CHECK-NEXT: define {{.*}}() {{.*}} #0
18+
// CHECK-NEXT: define {{.*}}() {{.*}} #1
19+
#[inline(never)]
1920
fn not_exported() {}
2021

2122
// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}"

tests/codegen/tune-cpu-on-functions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pub extern fn exported() {
1515

1616
// CHECK-LABEL: ; tune_cpu_on_functions::not_exported
1717
// CHECK-NEXT: ; Function Attrs:
18-
// CHECK-NEXT: define {{.*}}() {{.*}} #0
18+
// CHECK-NEXT: define {{.*}}() {{.*}} #1
19+
#[inline(never)]
1920
fn not_exported() {}
2021

2122
// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}"

tests/mir-opt/dest-prop/union.main.DestinationPropagation.diff

+4-15
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,19 @@
44
fn main() -> () {
55
let mut _0: (); // return place in scope 0 at $DIR/union.rs:+0:11: +0:11
66
let _1: main::Un; // in scope 0 at $DIR/union.rs:+5:9: +5:11
7-
let mut _2: u32; // in scope 0 at $DIR/union.rs:+5:23: +5:28
8-
let mut _3: u32; // in scope 0 at $DIR/union.rs:+7:10: +7:26
97
scope 1 {
108
debug un => _1; // in scope 1 at $DIR/union.rs:+5:9: +5:11
119
scope 2 {
1210
}
13-
scope 3 (inlined std::mem::drop::<u32>) { // at $DIR/union.rs:16:5: 16:27
14-
debug _x => _3; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
11+
scope 4 (inlined std::mem::drop::<u32>) { // at $DIR/union.rs:16:5: 16:27
12+
debug _x => const 1_u32; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
1513
}
1614
}
15+
scope 3 (inlined val) { // at $DIR/union.rs:14:23: 14:28
16+
}
1717

1818
bb0: {
1919
StorageLive(_1); // scope 0 at $DIR/union.rs:+5:9: +5:11
20-
StorageLive(_2); // scope 0 at $DIR/union.rs:+5:23: +5:28
21-
_2 = val() -> bb1; // scope 0 at $DIR/union.rs:+5:23: +5:28
22-
// mir::Constant
23-
// + span: $DIR/union.rs:14:23: 14:26
24-
// + literal: Const { ty: fn() -> u32 {val}, val: Value(<ZST>) }
25-
}
26-
27-
bb1: {
28-
StorageDead(_2); // scope 0 at $DIR/union.rs:+5:29: +5:30
29-
StorageLive(_3); // scope 1 at $DIR/union.rs:+7:10: +7:26
30-
StorageDead(_3); // scope 1 at $DIR/union.rs:+7:26: +7:27
3120
StorageDead(_1); // scope 0 at $DIR/union.rs:+8:1: +8:2
3221
return; // scope 0 at $DIR/union.rs:+8:2: +8:2
3322
}

tests/mir-opt/inline/issue_106141.outer.Inline.diff

+9-32
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,29 @@
44
fn outer() -> usize {
55
let mut _0: usize; // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
66
+ scope 1 (inlined inner) { // at $DIR/issue_106141.rs:3:5: 3:12
7-
+ let mut _1: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25
8-
+ let mut _2: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
9-
+ let mut _3: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
107
+ scope 2 {
118
+ debug buffer => const _; // in scope 2 at $DIR/issue_106141.rs:12:9: 12:15
9+
+ let _1: usize; // in scope 2 at $DIR/issue_106141.rs:13:9: 13:14
1210
+ scope 3 {
13-
+ debug index => _0; // in scope 3 at $DIR/issue_106141.rs:13:9: 13:14
11+
+ debug index => _1; // in scope 3 at $DIR/issue_106141.rs:13:9: 13:14
12+
+ }
13+
+ scope 4 (inlined index) { // at $DIR/issue_106141.rs:13:17: 13:24
1414
+ }
1515
+ }
1616
+ }
1717

1818
bb0: {
1919
- _0 = inner() -> bb1; // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
20-
+ StorageLive(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
21-
+ _1 = const _; // scope 1 at $DIR/issue_106141.rs:12:18: 12:25
22-
// mir::Constant
20+
- // mir::Constant
2321
- // + span: $DIR/issue_106141.rs:3:5: 3:10
2422
- // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) }
25-
+ // + span: $DIR/issue_106141.rs:12:18: 12:25
26-
+ // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) }
27-
+ _0 = index() -> bb1; // scope 2 at $DIR/issue_106141.rs:13:17: 13:24
28-
+ // mir::Constant
29-
+ // + span: $DIR/issue_106141.rs:13:17: 13:22
30-
+ // + literal: Const { ty: fn() -> usize {index}, val: Value(<ZST>) }
23+
+ StorageLive(_1); // scope 2 at $DIR/issue_106141.rs:13:9: 13:14
24+
+ goto -> bb1; // scope 2 at $DIR/issue_106141.rs:13:17: 13:24
3125
}
3226

3327
bb1: {
34-
+ StorageLive(_3); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
35-
+ _2 = Lt(_0, const 1_usize); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
36-
+ assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
37-
+ }
38-
+
39-
+ bb2: {
40-
+ _3 = (*_1)[_0]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
41-
+ switchInt(move _3) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
42-
+ }
43-
+
44-
+ bb3: {
45-
+ _0 = const 0_usize; // scope 3 at $DIR/issue_106141.rs:17:9: 17:10
46-
+ goto -> bb4; // scope 3 at $DIR/issue_106141.rs:14:5: 18:6
47-
+ }
48-
+
49-
+ bb4: {
50-
+ StorageDead(_3); // scope 3 at $DIR/issue_106141.rs:18:5: 18:6
51-
+ StorageDead(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
52-
return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
28+
- return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
29+
+ goto -> bb1; // scope 4 at $DIR/issue_106141.rs:7:5: 7:12
5330
}
5431
}
5532

tests/mir-opt/inline/issue_78442.bar.Inline.diff

+27-33
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,55 @@
88
let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
99
let _4: fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
1010
let mut _5: (); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
11-
+ scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue_78442.rs:11:5: 11:17
11+
+ scope 1 (inlined hide_foo) { // at $DIR/issue_78442.rs:11:5: 11:15
12+
+ }
13+
+ scope 2 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue_78442.rs:11:5: 11:17
14+
+ scope 3 (inlined foo) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
15+
+ }
1216
+ }
1317

1418
bb0: {
1519
StorageLive(_2); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
1620
StorageLive(_3); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
1721
StorageLive(_4); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
1822
- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
19-
+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
20-
// mir::Constant
21-
// + span: $DIR/issue_78442.rs:11:5: 11:13
22-
// + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
23-
}
24-
25-
bb1: {
23+
- // mir::Constant
24+
- // + span: $DIR/issue_78442.rs:11:5: 11:13
25+
- // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
26+
- }
27+
-
28+
- bb1: {
2629
_3 = &_4; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
2730
StorageLive(_5); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
2831
_5 = (); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
2932
- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
3033
- // mir::Constant
3134
- // + span: $DIR/issue_78442.rs:11:5: 11:15
3235
- // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
33-
+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
34-
}
35-
36-
bb2: {
37-
- StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
38-
- StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
39-
- StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
40-
- StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
41-
- _0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
36+
- }
37+
-
38+
- bb2: {
39+
StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
40+
StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
41+
StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
42+
StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
43+
_0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
4244
- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
43-
+ return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
45+
+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
4446
}
4547

4648
- bb3: {
47-
- return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
48-
+ bb3 (cleanup): {
49-
+ drop(_1) -> [return: bb4, unwind terminate]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
49+
+ bb1: {
50+
return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
5051
}
5152

52-
bb4 (cleanup): {
53+
- bb4 (cleanup): {
5354
- drop(_1) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
54-
+ resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
55-
}
56-
55+
- }
56+
-
5757
- bb5 (cleanup): {
58-
- resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
59-
+ bb5: {
60-
+ StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
61-
+ StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
62-
+ StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
63-
+ StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
64-
+ _0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
65-
+ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
58+
+ bb2 (cleanup): {
59+
resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
6660
}
6761
}
6862

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `outer` before Inline
2+
+ // MIR for `outer` after Inline
3+
4+
fn outer() -> u8 {
5+
let mut _0: u8; // return place in scope 0 at $DIR/private_helper.rs:+0:19: +0:21
6+
-
7+
- bb0: {
8+
- _0 = helper() -> bb1; // scope 0 at $DIR/private_helper.rs:+1:5: +1:13
9+
- // mir::Constant
10+
- // + span: $DIR/private_helper.rs:7:5: 7:11
11+
- // + literal: Const { ty: fn() -> u8 {helper}, val: Value(<ZST>) }
12+
+ scope 1 (inlined helper) { // at $DIR/private_helper.rs:7:5: 7:13
13+
}
14+
15+
- bb1: {
16+
+ bb0: {
17+
+ _0 = const 123_u8; // scope 1 at $DIR/private_helper.rs:11:5: 11:8
18+
return; // scope 0 at $DIR/private_helper.rs:+2:2: +2:2
19+
}
20+
}
21+
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile-flags: -Zmir-opt-level=2 -Zinline-mir
2+
3+
#![crate_type = "lib"]
4+
5+
// EMIT_MIR private_helper.outer.Inline.diff
6+
pub fn outer() -> u8 {
7+
helper()
8+
}
9+
10+
fn helper() -> u8 {
11+
123
12+
}

0 commit comments

Comments
 (0)