Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cc9057d

Browse files
committedDec 9, 2024
Auto merge of rust-lang#130909 - saethlin:infer-nounwind, r=<try>
Infer nounwind and use it in MIR opts r? `@ghost` Sinking this into `layout::fn_can_unwind` yields bigger MIR diffs. That's something to try tweaking. But also, this analysis reduces incrementality because call sites depend on callee bodies. So I've currently disabled it when incremental is enabled. That's another tweak I want to try.
2 parents f6cb952 + 5bf6851 commit cc9057d

28 files changed

+109
-46
lines changed
 

‎compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
870870
});
871871
sess.time("MIR_effect_checking", || {
872872
for def_id in tcx.hir().body_owners() {
873-
tcx.ensure().has_ffi_unwind_calls(def_id);
873+
tcx.ensure().mir_flags(def_id);
874874

875875
// If we need to codegen, ensure that we emit all errors from
876876
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering

‎compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ provide! { tcx, def_id, other, cdata,
348348
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
349349
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
350350
cross_crate_inlinable => { table_direct }
351+
mir_flags => { table_direct }
351352

352353
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
353354
is_private_dep => { cdata.private_dep }

‎compiler/rustc_metadata/src/rmeta/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2525
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2626
use rustc_middle::middle::lib_features::FeatureStability;
2727
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
28+
use rustc_middle::mir::MirFlags;
2829
use rustc_middle::ty::fast_reject::SimplifiedType;
2930
use rustc_middle::ty::{
3031
self, DeducedParamAttrs, ParameterizedOverTcx, Ty, TyCtxt, UnusedGenericParams,
@@ -401,6 +402,7 @@ define_tables! {
401402
// individually instead of `DefId`s.
402403
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
403404
cross_crate_inlinable: Table<DefIndex, bool>,
405+
mir_flags: Table<DefIndex, MirFlags>,
404406

405407
- optional:
406408
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,

‎compiler/rustc_metadata/src/rmeta/table.rs

+21
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ impl IsDefault for UnusedGenericParams {
5353
}
5454
}
5555

56+
impl IsDefault for MirFlags {
57+
fn is_default(&self) -> bool {
58+
*self == Self::default()
59+
}
60+
}
61+
5662
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
5763
/// Used mainly for Lazy positions and lengths.
5864
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
@@ -291,6 +297,21 @@ impl FixedSizeEncoding for AttrFlags {
291297
}
292298
}
293299

300+
impl FixedSizeEncoding for MirFlags {
301+
type ByteArray = [u8; 1];
302+
303+
#[inline]
304+
fn from_bytes(b: &[u8; 1]) -> Self {
305+
MirFlags::from_bits_truncate(b[0])
306+
}
307+
308+
#[inline]
309+
fn write_to_bytes(self, b: &mut [u8; 1]) {
310+
debug_assert!(!self.is_default());
311+
b[0] = self.bits();
312+
}
313+
}
314+
294315
impl FixedSizeEncoding for bool {
295316
type ByteArray = [u8; 1];
296317

‎compiler/rustc_middle/src/mir/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,15 @@ impl DefLocation {
17931793
}
17941794
}
17951795

1796+
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
1797+
pub struct MirFlags(u8);
1798+
bitflags::bitflags! {
1799+
impl MirFlags: u8 {
1800+
const IS_NOUNWIND = 1 << 0;
1801+
const HAS_FFI_UNWIND_CALLS = 1 << 1;
1802+
}
1803+
}
1804+
17961805
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
17971806
#[cfg(target_pointer_width = "64")]
17981807
mod size_asserts {

‎compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ trivial! {
293293
rustc_middle::middle::resolve_bound_vars::ResolvedArg,
294294
rustc_middle::middle::stability::DeprecationEntry,
295295
rustc_middle::mir::ConstQualifs,
296+
rustc_middle::mir::MirFlags,
296297
rustc_middle::mir::interpret::AllocId,
297298
rustc_middle::mir::interpret::CtfeProvenance,
298299
rustc_middle::mir::interpret::ErrorHandled,

‎compiler/rustc_middle/src/query/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use crate::middle::lib_features::LibFeatures;
5656
use crate::middle::privacy::EffectiveVisibilities;
5757
use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
5858
use crate::middle::stability::{self, DeprecationEntry};
59+
use crate::mir::MirFlags;
5960
use crate::mir::interpret::{
6061
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
6162
EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
@@ -1547,9 +1548,10 @@ rustc_queries! {
15471548
desc { "checking if a crate is `#![profiler_runtime]`" }
15481549
separate_provide_extern
15491550
}
1550-
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
1551-
desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key) }
1552-
cache_on_disk_if { true }
1551+
query mir_flags(key: DefId) -> MirFlags {
1552+
desc { |tcx| "stashing some local properties of `{}` before the body is stolen", tcx.def_path_str(key) }
1553+
cache_on_disk_if { key.is_local() }
1554+
separate_provide_extern
15531555
}
15541556
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
15551557
fatal_cycle

‎compiler/rustc_middle/src/ty/context.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use crate::metadata::ModChild;
6464
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
6565
use crate::middle::{resolve_bound_vars, stability};
6666
use crate::mir::interpret::{self, Allocation, ConstAllocation};
67-
use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
67+
use crate::mir::{Body, Local, MirFlags, Place, PlaceElem, ProjectionKind, Promoted};
6868
use crate::query::plumbing::QuerySystem;
6969
use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt};
7070
use crate::thir::Thir;
@@ -3206,6 +3206,14 @@ impl<'tcx> TyCtxt<'tcx> {
32063206
}
32073207
}
32083208

3209+
pub fn is_nounwind(self, def_id: DefId) -> bool {
3210+
self.mir_flags(def_id).contains(MirFlags::IS_NOUNWIND)
3211+
}
3212+
3213+
pub fn has_ffi_unwind_calls(self, def_id: DefId) -> bool {
3214+
self.mir_flags(def_id).contains(MirFlags::HAS_FFI_UNWIND_CALLS)
3215+
}
3216+
32093217
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
32103218
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
32113219
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()

‎compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ trivially_parameterized_over_tcx! {
9898
rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
9999
rustc_index::bit_set::BitSet<u32>,
100100
rustc_index::bit_set::FiniteBitSet<u32>,
101+
rustc_middle::mir::MirFlags,
101102
rustc_session::cstore::ForeignModule,
102103
rustc_session::cstore::LinkagePreference,
103104
rustc_session::cstore::NativeLib,

‎compiler/rustc_mir_transform/src/ffi_unwind_calls.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_abi::ExternAbi;
2-
use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId};
2+
use rustc_hir::def_id::LOCAL_CRATE;
33
use rustc_middle::mir::*;
44
use rustc_middle::query::{LocalCrate, Providers};
55
use rustc_middle::ty::{self, TyCtxt, layout};
@@ -11,17 +11,10 @@ use tracing::debug;
1111
use crate::errors;
1212

1313
// Check if the body of this def_id can possibly leak a foreign unwind into Rust code.
14-
fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
15-
debug!("has_ffi_unwind_calls({local_def_id:?})");
14+
pub(crate) fn has_ffi_unwind_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
15+
let def_id = body.source.def_id();
1616

17-
// Only perform check on functions because constants cannot call FFI functions.
18-
let def_id = local_def_id.to_def_id();
19-
let kind = tcx.def_kind(def_id);
20-
if !kind.is_fn_like() {
21-
return false;
22-
}
23-
24-
let body = &*tcx.mir_built(local_def_id).borrow();
17+
debug!("has_ffi_unwind_calls({def_id:?})");
2518

2619
let body_ty = tcx.type_of(def_id).skip_binder();
2720
let body_abi = match body_ty.kind() {
@@ -112,7 +105,7 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrate
112105
}
113106

114107
for def_id in tcx.hir().body_owners() {
115-
if tcx.has_ffi_unwind_calls(def_id) {
108+
if tcx.has_ffi_unwind_calls(def_id.into()) {
116109
// Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls`
117110
// MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception
118111
// can enter Rust through these sites.
@@ -143,5 +136,5 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrate
143136
}
144137

145138
pub(crate) fn provide(providers: &mut Providers) {
146-
*providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers };
139+
*providers = Providers { required_panic_strategy, ..*providers };
147140
}

‎compiler/rustc_mir_transform/src/instsimplify.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
283283
_ => bug!("unexpected body ty: {:?}", body_ty),
284284
};
285285

286-
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) {
286+
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi)
287+
|| (self.tcx.sess.opts.incremental.is_none() && self.tcx.is_nounwind(def_id))
288+
{
287289
*unwind = UnwindAction::Unreachable;
288290
}
289291
}

‎compiler/rustc_mir_transform/src/lib.rs

+31-5
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use rustc_hir::def_id::LocalDefId;
2626
use rustc_index::IndexVec;
2727
use rustc_middle::mir::{
2828
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
29-
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK,
30-
SourceInfo, Statement, StatementKind, TerminatorKind,
29+
MirFlags, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
30+
START_BLOCK, SourceInfo, Statement, StatementKind, TerminatorKind,
3131
};
3232
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
3333
use rustc_middle::util::Providers;
@@ -217,6 +217,7 @@ pub fn provide(providers: &mut Providers) {
217217
promoted_mir,
218218
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
219219
coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
220+
mir_flags,
220221
..providers.queries
221222
};
222223
}
@@ -410,9 +411,6 @@ fn mir_promoted(
410411
_ => ConstQualifs::default(),
411412
};
412413

413-
// the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run.
414-
tcx.ensure_with_value().has_ffi_unwind_calls(def);
415-
416414
// the `by_move_body` query uses the raw mir, so make sure it is run.
417415
if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
418416
tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
@@ -440,6 +438,33 @@ fn mir_promoted(
440438
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
441439
}
442440

441+
fn mir_flags<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> MirFlags {
442+
let mut flags = MirFlags::default();
443+
// Only perform check on functions because constants cannot call FFI functions.
444+
let kind = tcx.def_kind(local_def_id);
445+
if !kind.is_fn_like() {
446+
return flags;
447+
}
448+
449+
if !tcx.mir_keys(()).contains(&local_def_id) {
450+
return flags;
451+
}
452+
453+
let body = &*tcx.mir_promoted(local_def_id).0.borrow();
454+
455+
if is_nounwind(body) {
456+
flags.insert(MirFlags::IS_NOUNWIND);
457+
}
458+
if ffi_unwind_calls::has_ffi_unwind_calls(tcx, body) {
459+
flags.insert(MirFlags::HAS_FFI_UNWIND_CALLS);
460+
}
461+
flags
462+
}
463+
464+
fn is_nounwind<'tcx>(body: &Body<'tcx>) -> bool {
465+
body.basic_blocks.iter().all(|block| block.terminator().unwind().is_none())
466+
}
467+
443468
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
444469
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
445470
tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
@@ -488,6 +513,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
488513
if pm::should_run_pass(tcx, &inline::Inline) {
489514
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
490515
}
516+
tcx.ensure_with_value().mir_flags(def);
491517
}
492518

493519
let (body, _) = tcx.mir_promoted(def);

‎tests/codegen/drop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn droppy() {
2323
// FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
2424
// comment, that's `; call core::ptr::drop_in_place::<drop::SomeUniqueName>`
2525
// for the `v0` mangling, should switch to matching on that once `legacy` is gone.
26-
// CHECK-COUNT-6: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
26+
// CHECK-COUNT-5: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
2727
// CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
2828
// The next line checks for the } that ends the function definition
2929
// CHECK-LABEL: {{^[}]}}

‎tests/codegen/personality_lifetimes.rs

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

1515
#[inline(never)]
16-
fn might_unwind() {}
16+
fn might_unwind() {
17+
panic!()
18+
}
1719

1820
// CHECK-LABEL: @test
1921
#[no_mangle]

‎tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
bb0: {
1212
StorageLive(_1);
13-
_1 = bar::<T>() -> [return: bb1, unwind continue];
13+
_1 = bar::<T>() -> [return: bb1, unwind unreachable];
1414
}
1515

1616
bb1: {

‎tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
StorageLive(_2);
3232
StorageLive(_3);
3333
StorageLive(_4);
34-
- _4 = g() -> [return: bb1, unwind continue];
34+
- _4 = g() -> [return: bb1, unwind unreachable];
3535
+ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
3636
+ _3 = &mut _4;
3737
+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: copy _3 };

‎tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn main() -> () {
2121
StorageLive(_3);
2222
StorageLive(_4);
2323
StorageLive(_5);
24-
_3 = g() -> [return: bb3, unwind continue];
24+
_3 = g() -> [return: bb3, unwind unreachable];
2525
}
2626

2727
bb2: {
@@ -34,10 +34,10 @@ fn main() -> () {
3434
}
3535

3636
bb3: {
37-
_4 = g() -> [return: bb4, unwind continue];
37+
_4 = g() -> [return: bb4, unwind unreachable];
3838
}
3939

4040
bb4: {
41-
_5 = g() -> [return: bb2, unwind continue];
41+
_5 = g() -> [return: bb2, unwind unreachable];
4242
}
4343
}

‎tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn test(_1: &dyn X) -> u32 {
88
bb0: {
99
StorageLive(_2);
1010
_2 = copy _1;
11-
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind continue];
11+
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind unreachable];
1212
}
1313

1414
bb1: {

‎tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool {
1515
_3 = copy _1;
1616
_2 = move _3;
1717
StorageDead(_3);
18-
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind continue];
18+
_0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind unreachable];
1919
}
2020

2121
bb1: {

‎tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
StorageLive(_2);
1616
StorageLive(_3);
1717
StorageLive(_4);
18-
- _4 = hide_foo() -> [return: bb1, unwind: bb4];
18+
- _4 = hide_foo() -> [return: bb1, unwind unreachable];
1919
- }
2020
-
2121
- bb1: {

‎tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
bb0: {
99
StorageLive(_1);
10-
_1 = callee() -> [return: bb1, unwind continue];
10+
_1 = callee() -> [return: bb1, unwind unreachable];
1111
}
1212

1313
bb1: {

‎tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ fn caller() -> () {
55
let _1: ();
66

77
bb0: {
8-
_1 = callee() -> [return: bb1, unwind continue];
8+
_1 = callee() -> [return: bb1, unwind unreachable];
99
}
1010

1111
bb1: {

‎tests/mir-opt/inline/unsized_argument.caller.Inline.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
StorageLive(_3);
1414
_3 = move _1;
1515
_4 = copy (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]);
16-
_2 = callee(move (*_4)) -> [return: bb1, unwind: bb3];
16+
_2 = callee(move (*_4)) -> [return: bb1, unwind unreachable];
1717
}
1818

1919
bb1: {

‎tests/mir-opt/pre-codegen/deref_nested_borrows.src.GVN.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
+ nop;
2121
+ _6 = copy (*_1);
2222
_2 = copy (*_6);
23-
_3 = unknown() -> [return: bb1, unwind continue];
23+
_3 = unknown() -> [return: bb1, unwind unreachable];
2424
}
2525

2626
bb1: {
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.