@@ -42,19 +42,7 @@ struct CallSite<'tcx> {
42
42
43
43
impl < ' tcx > MirPass < ' tcx > for Inline {
44
44
fn is_enabled ( & self , sess : & rustc_session:: Session ) -> bool {
45
- if let Some ( enabled) = sess. opts . unstable_opts . inline_mir {
46
- return enabled;
47
- }
48
-
49
- match sess. mir_opt_level ( ) {
50
- 0 | 1 => false ,
51
- 2 => {
52
- ( sess. opts . optimize == OptLevel :: Default
53
- || sess. opts . optimize == OptLevel :: Aggressive )
54
- && sess. opts . incremental == None
55
- }
56
- _ => true ,
57
- }
45
+ InlinerConfig :: new ( sess) . is_ok ( )
58
46
}
59
47
60
48
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
@@ -69,6 +57,67 @@ impl<'tcx> MirPass<'tcx> for Inline {
69
57
}
70
58
}
71
59
60
+ impl Inline {
61
+ pub fn is_enabled_and_needs_mir_inliner_callees ( sess : & rustc_session:: Session ) -> bool {
62
+ match InlinerConfig :: new ( sess) {
63
+ Ok ( config) => config. inline_local_fns ,
64
+ Err ( _) => false ,
65
+ }
66
+ }
67
+ }
68
+
69
+ struct InlinerConfig {
70
+ /// Inline functions with `#[inline(always)]` attribute
71
+ inline_fns_with_inline_always_hint : bool ,
72
+ /// Inline functions with `#[inline]` attribute
73
+ inline_fns_with_inline_hint : bool ,
74
+ /// Inline functions without `#[inline]` attribute
75
+ /// Inline functions with `#[inline(always)]` attribute
76
+ inline_fns_without_hint : bool ,
77
+ /// Inline function from current crate (much heavier during incremental compilation)
78
+ inline_local_fns : bool ,
79
+ }
80
+
81
+ impl InlinerConfig {
82
+ fn new ( sess : & rustc_session:: Session ) -> Result < InlinerConfig , InliningIsDisabled > {
83
+ match sess. opts . unstable_opts . inline_mir {
84
+ Some ( true ) => return Ok ( InlinerConfig :: full ( ) ) ,
85
+ Some ( false ) => return Err ( InliningIsDisabled ) ,
86
+ None => { }
87
+ }
88
+ match sess. mir_opt_level ( ) {
89
+ 0 | 1 => Err ( InliningIsDisabled ) ,
90
+ 2 => {
91
+ let optimize = sess. opts . optimize ;
92
+ if optimize == OptLevel :: Default || optimize == OptLevel :: Aggressive {
93
+ let is_non_incremental = sess. opts . incremental == None ;
94
+ Ok ( InlinerConfig {
95
+ inline_fns_with_inline_always_hint : true ,
96
+ inline_fns_with_inline_hint : is_non_incremental,
97
+ inline_fns_without_hint : is_non_incremental,
98
+ inline_local_fns : is_non_incremental,
99
+ } )
100
+ } else {
101
+ Err ( InliningIsDisabled )
102
+ }
103
+ }
104
+ _ => Ok ( InlinerConfig :: full ( ) ) ,
105
+ }
106
+ }
107
+
108
+ fn full ( ) -> InlinerConfig {
109
+ InlinerConfig {
110
+ inline_fns_with_inline_always_hint : true ,
111
+ inline_fns_with_inline_hint : true ,
112
+ inline_fns_without_hint : true ,
113
+ inline_local_fns : true ,
114
+ }
115
+ }
116
+ }
117
+
118
+ #[ derive( Debug ) ]
119
+ struct InliningIsDisabled ;
120
+
72
121
fn inline < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) -> bool {
73
122
let def_id = body. source . def_id ( ) . expect_local ( ) ;
74
123
@@ -91,6 +140,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
91
140
let mut this = Inliner {
92
141
tcx,
93
142
param_env,
143
+ config : InlinerConfig :: new ( tcx. sess ) . unwrap_or_else ( |_| InlinerConfig :: full ( ) ) ,
94
144
codegen_fn_attrs : tcx. codegen_fn_attrs ( def_id) ,
95
145
history : Vec :: new ( ) ,
96
146
changed : false ,
@@ -103,6 +153,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
103
153
struct Inliner < ' tcx > {
104
154
tcx : TyCtxt < ' tcx > ,
105
155
param_env : ParamEnv < ' tcx > ,
156
+ config : InlinerConfig ,
106
157
/// Caller codegen attributes.
107
158
codegen_fn_attrs : & ' tcx CodegenFnAttrs ,
108
159
/// Stack of inlined instances.
@@ -352,11 +403,35 @@ impl<'tcx> Inliner<'tcx> {
352
403
if let InlineAttr :: Never = callee_attrs. inline {
353
404
return Err ( "never inline hint" ) ;
354
405
}
406
+ match callee_attrs. inline {
407
+ InlineAttr :: Never => return Err ( "never inline hint" ) ,
408
+ InlineAttr :: Always => {
409
+ if !self . config . inline_fns_with_inline_always_hint {
410
+ return Err ( "inliner is configured to ignore #[inline(always)] functions" ) ;
411
+ }
412
+ }
413
+ InlineAttr :: Hint => {
414
+ if !self . config . inline_fns_with_inline_hint {
415
+ return Err ( "inliner is configured to ignore #[inline] functions" ) ;
416
+ }
417
+ }
418
+ _ => {
419
+ if !self . config . inline_fns_without_hint {
420
+ return Err ( "inliner is configured to ignore functions without #[inline]" ) ;
421
+ }
422
+ }
423
+ }
424
+
425
+ let callee_is_local = callsite. callee . def_id ( ) . is_local ( ) ;
426
+
427
+ if callee_is_local && !self . config . inline_local_fns {
428
+ return Err ( "inliner is configured to ignore local functions" ) ;
429
+ }
355
430
356
431
// Only inline local functions if they would be eligible for cross-crate
357
432
// inlining. This is to ensure that the final crate doesn't have MIR that
358
433
// reference unexported symbols
359
- if callsite . callee . def_id ( ) . is_local ( ) {
434
+ if callee_is_local {
360
435
let is_generic = callsite. callee . substs . non_erasable_generics ( ) . next ( ) . is_some ( ) ;
361
436
if !is_generic && !callee_attrs. requests_inline ( ) {
362
437
return Err ( "not exported" ) ;
0 commit comments