Skip to content

Commit 9fdd6cd

Browse files
committed
Infer nounwind and use it in MIR opts
1 parent 0df0662 commit 9fdd6cd

31 files changed

+112
-49
lines changed

compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
890890
});
891891
sess.time("MIR_effect_checking", || {
892892
tcx.hir().par_body_owners(|def_id| {
893-
tcx.ensure().has_ffi_unwind_calls(def_id);
893+
tcx.ensure().mir_flags(def_id);
894894

895895
// If we need to codegen, ensure that we emit all errors from
896896
// `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
@@ -347,6 +347,7 @@ provide! { tcx, def_id, other, cdata,
347347
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
348348
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
349349
cross_crate_inlinable => { table_direct }
350+
mir_flags => { table_direct }
350351

351352
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
352353
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,
@@ -400,6 +401,7 @@ define_tables! {
400401
// individually instead of `DefId`s.
401402
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
402403
cross_crate_inlinable: Table<DefIndex, bool>,
404+
mir_flags: Table<DefIndex, MirFlags>,
403405

404406
- optional:
405407
attributes: Table<DefIndex, LazyArray<hir::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
@@ -1796,6 +1796,15 @@ impl DefLocation {
17961796
}
17971797
}
17981798

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

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ trivial! {
285285
rustc_middle::middle::resolve_bound_vars::ResolvedArg,
286286
rustc_middle::middle::stability::DeprecationEntry,
287287
rustc_middle::mir::ConstQualifs,
288+
rustc_middle::mir::MirFlags,
288289
rustc_middle::mir::interpret::AllocId,
289290
rustc_middle::mir::interpret::CtfeProvenance,
290291
rustc_middle::mir::interpret::ErrorHandled,

compiler/rustc_middle/src/query/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use crate::middle::lib_features::LibFeatures;
5454
use crate::middle::privacy::EffectiveVisibilities;
5555
use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
5656
use crate::middle::stability::{self, DeprecationEntry};
57+
use crate::mir::MirFlags;
5758
use crate::mir::interpret::{
5859
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
5960
EvalToValTreeResult, GlobalId, LitToConstInput,
@@ -1662,9 +1663,10 @@ rustc_queries! {
16621663
desc { "checking if a crate is `#![profiler_runtime]`" }
16631664
separate_provide_extern
16641665
}
1665-
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
1666-
desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key) }
1667-
cache_on_disk_if { true }
1666+
query mir_flags(key: DefId) -> MirFlags {
1667+
desc { |tcx| "stashing some local properties of `{}` before the body is stolen", tcx.def_path_str(key) }
1668+
cache_on_disk_if { key.is_local() }
1669+
separate_provide_extern
16681670
}
16691671
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
16701672
fatal_cycle

compiler/rustc_middle/src/ty/context.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use crate::metadata::ModChild;
6565
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
6666
use crate::middle::{resolve_bound_vars, stability};
6767
use crate::mir::interpret::{self, Allocation, ConstAllocation};
68-
use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
68+
use crate::mir::{Body, Local, MirFlags, Place, PlaceElem, ProjectionKind, Promoted};
6969
use crate::query::plumbing::QuerySystem;
7070
use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt};
7171
use crate::thir::Thir;
@@ -3220,6 +3220,14 @@ impl<'tcx> TyCtxt<'tcx> {
32203220
}
32213221
}
32223222

3223+
pub fn is_nounwind(self, def_id: DefId) -> bool {
3224+
self.mir_flags(def_id).contains(MirFlags::IS_NOUNWIND)
3225+
}
3226+
3227+
pub fn has_ffi_unwind_calls(self, def_id: DefId) -> bool {
3228+
self.mir_flags(def_id).contains(MirFlags::HAS_FFI_UNWIND_CALLS)
3229+
}
3230+
32233231
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
32243232
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
32253233
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::DenseBitSet<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
@@ -306,7 +306,9 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
306306
_ => bug!("unexpected body ty: {:?}", body_ty),
307307
};
308308

309-
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) {
309+
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi)
310+
|| (self.tcx.sess.opts.incremental.is_none() && self.tcx.is_nounwind(def_id))
311+
{
310312
*unwind = UnwindAction::Unreachable;
311313
}
312314
}

compiler/rustc_mir_transform/src/lib.rs

+31-5
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use rustc_hir::def_id::LocalDefId;
2727
use rustc_index::IndexVec;
2828
use rustc_middle::mir::{
2929
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
30-
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK,
31-
SourceInfo, Statement, StatementKind, TerminatorKind,
30+
MirFlags, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
31+
START_BLOCK, SourceInfo, Statement, StatementKind, TerminatorKind,
3232
};
3333
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
3434
use rustc_middle::util::Providers;
@@ -221,6 +221,7 @@ pub fn provide(providers: &mut Providers) {
221221
promoted_mir,
222222
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
223223
coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
224+
mir_flags,
224225
..providers.queries
225226
};
226227
}
@@ -417,9 +418,6 @@ fn mir_promoted(
417418
_ => ConstQualifs::default(),
418419
};
419420

420-
// the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run.
421-
tcx.ensure_with_value().has_ffi_unwind_calls(def);
422-
423421
// the `by_move_body` query uses the raw mir, so make sure it is run.
424422
if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
425423
tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
@@ -450,6 +448,33 @@ fn mir_promoted(
450448
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
451449
}
452450

451+
fn mir_flags<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> MirFlags {
452+
let mut flags = MirFlags::default();
453+
// Only perform check on functions because constants cannot call FFI functions.
454+
let kind = tcx.def_kind(local_def_id);
455+
if !kind.is_fn_like() {
456+
return flags;
457+
}
458+
459+
if !tcx.mir_keys(()).contains(&local_def_id) {
460+
return flags;
461+
}
462+
463+
let body = &*tcx.mir_promoted(local_def_id).0.borrow();
464+
465+
if is_nounwind(body) {
466+
flags.insert(MirFlags::IS_NOUNWIND);
467+
}
468+
if ffi_unwind_calls::has_ffi_unwind_calls(tcx, body) {
469+
flags.insert(MirFlags::HAS_FFI_UNWIND_CALLS);
470+
}
471+
flags
472+
}
473+
474+
fn is_nounwind<'tcx>(body: &Body<'tcx>) -> bool {
475+
body.basic_blocks.iter().all(|block| block.terminator().unwind().is_none())
476+
}
477+
453478
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
454479
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
455480
tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
@@ -500,6 +525,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
500525
{
501526
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
502527
}
528+
tcx.ensure_with_value().mir_flags(def);
503529
}
504530

505531
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/forced.caller.ForceInline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
bb0: {
1111
StorageLive(_1);
12-
- _1 = callee_forced() -> [return: bb1, unwind continue];
12+
- _1 = callee_forced() -> [return: bb1, unwind unreachable];
1313
- }
1414
-
1515
- bb1: {

tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
bb0: {
1111
StorageLive(_2);
12-
- _2 = callee_forced() -> [return: bb1, unwind continue];
12+
- _2 = callee_forced() -> [return: bb1, unwind unreachable];
1313
- }
1414
-
1515
- bb1: {

tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
bb0: {
1111
StorageLive(_1);
12-
- _1 = callee_forced() -> [return: bb1, unwind continue];
12+
- _1 = callee_forced() -> [return: bb1, unwind unreachable];
1313
- }
1414
-
1515
- bb1: {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
StorageLive(_2);
3131
StorageLive(_3);
3232
StorageLive(_4);
33-
- _4 = g() -> [return: bb1, unwind continue];
33+
- _4 = g() -> [return: bb1, unwind unreachable];
3434
+ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
3535
+ _3 = &mut _4;
3636
+ _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: {

0 commit comments

Comments
 (0)