Auto merge of rust-lang/rust#143167 - Mark-Simulacrum:inline-mark-nou… · rust-lang/rust@209ede6 (original) (raw)
`@@ -115,6 +115,7 @@ trait Inliner<'tcx> {
`
115
115
``
116
116
`/// Has the caller body been changed?
`
117
117
`fn changed(self) -> bool;
`
``
118
`+
fn set_changed(&mut self);
`
118
119
``
119
120
`/// Should inlining happen for a given callee?
`
120
121
`fn should_inline_for_callee(&self, def_id: DefId) -> bool;
`
`@@ -187,6 +188,10 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
`
187
188
`self.changed
`
188
189
`}
`
189
190
``
``
191
`+
fn set_changed(&mut self) {
`
``
192
`+
self.changed = true;
`
``
193
`+
}
`
``
194
+
190
195
`fn should_inline_for_callee(&self, def_id: DefId) -> bool {
`
191
196
`ForceInline::should_run_pass_for_callee(self.tcx(), def_id)
`
192
197
`}
`
`@@ -334,6 +339,10 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> {
`
334
339
`self.changed
`
335
340
`}
`
336
341
``
``
342
`+
fn set_changed(&mut self) {
`
``
343
`+
self.changed = true;
`
``
344
`+
}
`
``
345
+
337
346
`fn should_inline_for_callee(&self, _: DefId) -> bool {
`
338
347
`true
`
339
348
`}
`
`@@ -529,10 +538,35 @@ fn process_blocks<'tcx, I: Inliner<'tcx>>(
`
529
538
`let span = trace_span!("process_blocks", %callsite.callee, ?bb);
`
530
539
`let _guard = span.enter();
`
531
540
``
532
``
`-
match try_inlining(inliner, caller_body, &callsite) {
`
``
541
`+
let mut unwind_unreachable = Err("did not reach analysis");
`
``
542
`+
match try_inlining(inliner, caller_body, &callsite, &mut unwind_unreachable) {
`
533
543
`Err(reason) => {
`
534
544
`debug!("not-inlined {} [{}]", callsite.callee, reason);
`
535
545
` inliner.on_inline_failure(&callsite, reason);
`
``
546
+
``
547
`+
match unwind_unreachable {
`
``
548
`+
Ok(()) => {
`
``
549
`+
if let Some(TerminatorKind::Call { unwind, .. }) =
`
``
550
`+
caller_body[callsite.block].terminator.as_mut().map(|v| &mut v.kind)
`
``
551
`+
{
`
``
552
`+
inliner.set_changed();
`
``
553
`+
tracing::info!("marked {} unwind unreachable", callsite.callee);
`
``
554
`+
*unwind = UnwindAction::Unreachable;
`
``
555
`+
} else {
`
``
556
`+
bug!(
`
``
557
`+
"unexpected terminator: {:?}",
`
``
558
`+
caller_body[callsite.block].terminator
`
``
559
`+
);
`
``
560
`+
}
`
``
561
`+
}
`
``
562
`+
Err(reason) => {
`
``
563
`+
tracing::info!(
`
``
564
`+
"not marking unwind unreachable {}: {}",
`
``
565
`+
callsite.callee,
`
``
566
`+
reason
`
``
567
`+
);
`
``
568
`+
}
`
``
569
`+
}
`
536
570
`}
`
537
571
`Ok(new_blocks) => {
`
538
572
`debug!("inlined {}", callsite.callee);
`
`@@ -595,17 +629,69 @@ fn resolve_callsite<'tcx, I: Inliner<'tcx>>(
`
595
629
`None
`
596
630
`}
`
597
631
``
``
632
`+
/// Ok indicates yes, Err(reason) otherwise.
`
``
633
`+
fn should_mark_nounwind<'tcx>(_tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Result<(), &'static str> {
`
``
634
`+
// Unwinds can only start at certain terminators.
`
``
635
`+
for block in body.basic_blocks.iter() {
`
``
636
`+
let unwind = match block.terminator().kind {
`
``
637
`+
// These never unwind.
`
``
638
`+
TerminatorKind::Goto { .. }
`
``
639
`+
| TerminatorKind::SwitchInt { .. }
`
``
640
`+
| TerminatorKind::UnwindTerminate(_)
`
``
641
`+
| TerminatorKind::Return
`
``
642
`+
| TerminatorKind::Unreachable
`
``
643
`+
| TerminatorKind::CoroutineDrop
`
``
644
`+
| TerminatorKind::FalseEdge { .. }
`
``
645
`+
| TerminatorKind::FalseUnwind { .. } => continue,
`
``
646
+
``
647
`+
// Resume will continue unwinding, but if there's no other unwinding terminator it
`
``
648
`+
// will never be reached.
`
``
649
`+
TerminatorKind::UnwindResume => continue,
`
``
650
+
``
651
`+
TerminatorKind::Yield { .. } => {
`
``
652
`+
return Err("impl limitation: yield");
`
``
653
`+
}
`
``
654
+
``
655
`+
TerminatorKind::Drop { unwind, .. }
`
``
656
`+
| TerminatorKind::Call { unwind, .. }
`
``
657
`+
| TerminatorKind::Assert { unwind, .. } => unwind,
`
``
658
+
``
659
`+
TerminatorKind::InlineAsm { .. } => return Err("inlineasm"),
`
``
660
+
``
661
`+
TerminatorKind::TailCall { .. } => {
`
``
662
`+
return Err("impl limitation: tail call");
`
``
663
`+
}
`
``
664
`+
};
`
``
665
+
``
666
`+
match unwind {
`
``
667
`+
UnwindAction::Continue => return Err("unwind: continue"),
`
``
668
`+
// cannot unwind
`
``
669
`+
UnwindAction::Unreachable => {}
`
``
670
`+
// cannot unwind either -- will terminate instead
`
``
671
`+
UnwindAction::Terminate(_) => {}
`
``
672
`+
UnwindAction::Cleanup(_) => return Err("unwind: cleanup"),
`
``
673
`+
}
`
``
674
`+
}
`
``
675
+
``
676
`+
// If we didn't find an unwinding terminator, the function cannot unwind.
`
``
677
`+
Ok(())
`
``
678
`+
}
`
``
679
+
598
680
`/// Attempts to inline a callsite into the caller body. When successful returns basic blocks
`
599
681
`/// containing the inlined body. Otherwise returns an error describing why inlining didn't take
`
600
682
`/// place.
`
601
683
`fn try_inlining<'tcx, I: Inliner<'tcx>>(
`
602
684
`inliner: &I,
`
603
685
`caller_body: &mut Body<'tcx>,
`
604
686
`callsite: &CallSite<'tcx>,
`
``
687
`+
unwind: &mut Result<(), &'static str>,
`
605
688
`) -> Result<std::ops::Range, &'static str> {
`
606
689
`let tcx = inliner.tcx();
`
607
690
`check_mir_is_available(inliner, caller_body, callsite.callee)?;
`
608
691
``
``
692
`+
let callee_body = try_instance_mir(tcx, callsite.callee.def)?;
`
``
693
`+
*unwind = should_mark_nounwind(tcx, callee_body);
`
``
694
+
609
695
`let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
`
610
696
` check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?;
`
611
697
`check_codegen_attributes(inliner, callsite, callee_attrs)?;
`
`@@ -622,7 +708,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
`
622
708
`}
`
623
709
`}
`
624
710
``
625
``
`-
let callee_body = try_instance_mir(tcx, callsite.callee.def)?;
`
626
711
` check_inline::is_inline_valid_on_body(tcx, callee_body)?;
`
627
712
` inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?;
`
628
713
``