@@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
5
5
use rustc_index:: bit_set:: BitSet ;
6
6
use rustc_index:: Idx ;
7
7
use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrFlags , CodegenFnAttrs } ;
8
+ use rustc_middle:: mir:: interpret:: { ConstValue , GlobalAlloc , Scalar } ;
8
9
use rustc_middle:: mir:: visit:: * ;
9
10
use rustc_middle:: mir:: * ;
10
11
use rustc_middle:: ty:: TypeVisitableExt ;
@@ -87,12 +88,19 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
87
88
88
89
let param_env = tcx. param_env_reveal_all_normalized ( def_id) ;
89
90
91
+ let codegen_fn_attrs = tcx. codegen_fn_attrs ( def_id) ;
92
+
93
+ let is_exported = tcx. is_constructor ( def_id. into ( ) )
94
+ || tcx. generics_of ( def_id) . requires_monomorphization ( tcx)
95
+ || codegen_fn_attrs. requests_inline ( ) ;
96
+
90
97
let mut this = Inliner {
91
98
tcx,
92
99
param_env,
93
- codegen_fn_attrs : tcx . codegen_fn_attrs ( def_id ) ,
100
+ codegen_fn_attrs,
94
101
history : Vec :: new ( ) ,
95
102
changed : false ,
103
+ is_exported,
96
104
} ;
97
105
let blocks = START_BLOCK ..body. basic_blocks . next_index ( ) ;
98
106
this. process_blocks ( body, blocks) ;
@@ -112,6 +120,7 @@ struct Inliner<'tcx> {
112
120
history : Vec < DefId > ,
113
121
/// Indicates that the caller body has been modified.
114
122
changed : bool ,
123
+ is_exported : bool ,
115
124
}
116
125
117
126
impl < ' tcx > Inliner < ' tcx > {
@@ -190,7 +199,9 @@ impl<'tcx> Inliner<'tcx> {
190
199
191
200
self . check_mir_is_available ( caller_body, & callsite. callee ) ?;
192
201
let callee_body = try_instance_mir ( self . tcx , callsite. callee . def ) ?;
193
- self . check_mir_is_exportable ( & callsite. callee , callee_attrs, callee_body) ?;
202
+ if self . is_exported {
203
+ self . check_mir_is_exportable ( & callsite. callee , callee_attrs, callee_body) ?;
204
+ }
194
205
self . check_mir_body ( callsite, callee_body, callee_attrs) ?;
195
206
196
207
if !self . tcx . consider_optimizing ( || {
@@ -382,15 +393,19 @@ impl<'tcx> Inliner<'tcx> {
382
393
return Ok ( ( ) ) ;
383
394
}
384
395
385
- // So now we are trying to inline a function from another crate which is not inline and is
386
- // not a generic. This might work. But if this pulls in a symbol from the other crater, we
387
- // will fail to link.
388
- // So this is our heuritic for handling this:
396
+ // The general situation we need to avoid is this:
397
+ // * We inline a non-exported function into an exported function
398
+ // * The non-exported function pulls a symbol previously determined to be internal into an
399
+ // exported function
400
+ // * Later, we inline the exported function (which is now not exportable) into another crate
401
+ // * Linker error (or ICE)
402
+ //
403
+ // So this is our heuristic for preventing that:
389
404
// If this function has any calls in it, that might reference an internal symbol.
390
405
// If this function contains a pointer constant, that might be a reference to an internal
391
406
// static.
392
407
// So if either of those conditions are met, we cannot inline this.
393
- if !contains_pointer_constant ( callee_body) {
408
+ if !contains_pointer_constant ( self . tcx , callee_body) {
394
409
debug ! ( "Has no pointer constants, must be exportable" ) ;
395
410
return Ok ( ( ) ) ;
396
411
}
@@ -1184,17 +1199,18 @@ fn try_instance_mir<'tcx>(
1184
1199
}
1185
1200
}
1186
1201
1187
- fn contains_pointer_constant ( body : & Body < ' _ > ) -> bool {
1188
- let mut finder = ConstFinder { found : false } ;
1202
+ fn contains_pointer_constant < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) -> bool {
1203
+ let mut finder = ConstFinder { tcx , found : false } ;
1189
1204
finder. visit_body ( body) ;
1190
1205
finder. found
1191
1206
}
1192
1207
1193
- struct ConstFinder {
1208
+ struct ConstFinder < ' tcx > {
1209
+ tcx : TyCtxt < ' tcx > ,
1194
1210
found : bool ,
1195
1211
}
1196
1212
1197
- impl Visitor < ' _ > for ConstFinder {
1213
+ impl < ' tcx > Visitor < ' _ > for ConstFinder < ' tcx > {
1198
1214
fn visit_constant ( & mut self , constant : & Constant < ' _ > , location : Location ) {
1199
1215
debug ! ( "Visiting constant: {:?}" , constant. literal) ;
1200
1216
if let ConstantKind :: Unevaluated ( ..) = constant. literal {
@@ -1203,16 +1219,13 @@ impl Visitor<'_> for ConstFinder {
1203
1219
}
1204
1220
1205
1221
if let ConstantKind :: Val ( val, ty) = constant. literal {
1206
- ty:: tls:: with ( |tcx| {
1207
- let val = tcx. lift ( val) . unwrap ( ) ;
1208
- if let ConstValue :: Scalar ( Scalar :: Ptr ( ptr, _size) ) = val {
1209
- if let Some ( GlobalAlloc :: Static ( _) ) =
1210
- tcx. try_get_global_alloc ( ptr. into_parts ( ) . 0 )
1211
- {
1212
- self . found = true ;
1213
- }
1222
+ if let ConstValue :: Scalar ( Scalar :: Ptr ( ptr, _size) ) = val {
1223
+ if let Some ( GlobalAlloc :: Static ( _) ) =
1224
+ self . tcx . try_get_global_alloc ( ptr. into_parts ( ) . 0 )
1225
+ {
1226
+ self . found = true ;
1214
1227
}
1215
- } ) ;
1228
+ }
1216
1229
1217
1230
if ty. is_fn ( ) {
1218
1231
self . found = true ;
0 commit comments