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 7a4aba2

Browse files
committedSep 27, 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 58420a0 + e0da778 commit 7a4aba2

28 files changed

+123
-52
lines changed
 

‎compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
808808
});
809809
sess.time("MIR_effect_checking", || {
810810
for def_id in tcx.hir().body_owners() {
811-
tcx.ensure().has_ffi_unwind_calls(def_id);
811+
tcx.ensure().mir_flags(def_id);
812812

813813
// If we need to codegen, ensure that we emit all errors from
814814
// `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
@@ -352,6 +352,7 @@ provide! { tcx, def_id, other, cdata,
352352
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
353353
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
354354
cross_crate_inlinable => { table_direct }
355+
mir_flags => { table_direct }
355356

356357
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
357358
is_private_dep => { cdata.private_dep }

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

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2424
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2525
use rustc_middle::middle::lib_features::FeatureStability;
2626
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
27+
use rustc_middle::mir::MirFlags;
2728
use rustc_middle::ty::fast_reject::SimplifiedType;
2829
use rustc_middle::ty::{
2930
self, DeducedParamAttrs, ParameterizedOverTcx, ReprOptions, Ty, TyCtxt, UnusedGenericParams,
@@ -404,6 +405,7 @@ define_tables! {
404405
// individually instead of `DefId`s.
405406
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
406407
cross_crate_inlinable: Table<DefIndex, bool>,
408+
mir_flags: Table<DefIndex, MirFlags>,
407409

408410
- optional:
409411
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,

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

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

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

294+
impl FixedSizeEncoding for MirFlags {
295+
type ByteArray = [u8; 1];
296+
297+
#[inline]
298+
fn from_bytes(b: &[u8; 1]) -> Self {
299+
MirFlags::from_bits_truncate(b[0])
300+
}
301+
302+
#[inline]
303+
fn write_to_bytes(self, b: &mut [u8; 1]) {
304+
debug_assert!(!self.is_default());
305+
b[0] = self.bits();
306+
}
307+
}
308+
288309
impl FixedSizeEncoding for bool {
289310
type ByteArray = [u8; 1];
290311

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

+9
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,15 @@ impl DefLocation {
17811781
}
17821782
}
17831783

1784+
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
1785+
pub struct MirFlags(u8);
1786+
bitflags::bitflags! {
1787+
impl MirFlags: u8 {
1788+
const IS_NOUNWIND = 1 << 0;
1789+
const HAS_FFI_UNWIND_CALLS = 1 << 1;
1790+
}
1791+
}
1792+
17841793
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
17851794
#[cfg(target_pointer_width = "64")]
17861795
mod size_asserts {

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

+1
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ trivial! {
289289
rustc_middle::middle::resolve_bound_vars::ResolvedArg,
290290
rustc_middle::middle::stability::DeprecationEntry,
291291
rustc_middle::mir::ConstQualifs,
292+
rustc_middle::mir::MirFlags,
292293
rustc_middle::mir::interpret::AllocId,
293294
rustc_middle::mir::interpret::CtfeProvenance,
294295
rustc_middle::mir::interpret::ErrorHandled,

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

+4-2
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, LitToConstError, LitToConstInput,
@@ -1501,9 +1502,10 @@ rustc_queries! {
15011502
desc { "checking if a crate is `#![profiler_runtime]`" }
15021503
separate_provide_extern
15031504
}
1504-
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
1505-
desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key) }
1505+
query mir_flags(key: DefId) -> MirFlags {
1506+
desc { |tcx| "stashing some local properties of `{}` before the body is stolen", tcx.def_path_str(key) }
15061507
cache_on_disk_if { true }
1508+
separate_provide_extern
15071509
}
15081510
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
15091511
fatal_cycle

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use crate::metadata::ModChild;
6666
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
6767
use crate::middle::{resolve_bound_vars, stability};
6868
use crate::mir::interpret::{self, Allocation, ConstAllocation};
69-
use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
69+
use crate::mir::{Body, Local, MirFlags, Place, PlaceElem, ProjectionKind, Promoted};
7070
use crate::query::plumbing::QuerySystem;
7171
use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt};
7272
use crate::thir::Thir;
@@ -3180,6 +3180,14 @@ impl<'tcx> TyCtxt<'tcx> {
31803180
}
31813181
}
31823182

3183+
pub fn is_nounwind(self, def_id: DefId) -> bool {
3184+
self.mir_flags(def_id).contains(MirFlags::IS_NOUNWIND)
3185+
}
3186+
3187+
pub fn has_ffi_unwind_calls(self, def_id: DefId) -> bool {
3188+
self.mir_flags(def_id).contains(MirFlags::HAS_FFI_UNWIND_CALLS)
3189+
}
3190+
31833191
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
31843192
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
31853193
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
@@ -96,6 +96,7 @@ trivially_parameterized_over_tcx! {
9696
rustc_hir::definitions::DefKey,
9797
rustc_index::bit_set::BitSet<u32>,
9898
rustc_index::bit_set::FiniteBitSet<u32>,
99+
rustc_middle::mir::MirFlags,
99100
rustc_session::cstore::ForeignModule,
100101
rustc_session::cstore::LinkagePreference,
101102
rustc_session::cstore::NativeLib,

‎compiler/rustc_mir_transform/src/ffi_unwind_calls.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId};
1+
use rustc_hir::def_id::LOCAL_CRATE;
22
use rustc_middle::mir::*;
33
use rustc_middle::query::{LocalCrate, Providers};
44
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() {
@@ -108,7 +101,7 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrate
108101
}
109102

110103
for def_id in tcx.hir().body_owners() {
111-
if tcx.has_ffi_unwind_calls(def_id) {
104+
if tcx.has_ffi_unwind_calls(def_id.into()) {
112105
// Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls`
113106
// MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception
114107
// can enter Rust through these sites.
@@ -139,5 +132,5 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrate
139132
}
140133

141134
pub(crate) fn provide(providers: &mut Providers) {
142-
*providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers };
135+
*providers = Providers { required_panic_strategy, ..*providers };
143136
}

‎compiler/rustc_mir_transform/src/instsimplify.rs

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

329-
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) {
329+
if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi)
330+
|| (self.tcx.sess.opts.incremental.is_none() && self.tcx.is_nounwind(def_id))
331+
{
330332
*unwind = UnwindAction::Unreachable;
331333
}
332334
}

‎compiler/rustc_mir_transform/src/lib.rs

+33-4
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;
@@ -135,6 +135,7 @@ pub fn provide(providers: &mut Providers) {
135135
promoted_mir,
136136
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
137137
coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
138+
mir_flags,
138139
..providers.queries
139140
};
140141
}
@@ -331,14 +332,15 @@ fn mir_promoted(
331332
_ => ConstQualifs::default(),
332333
};
333334

334-
// the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run.
335-
tcx.ensure_with_value().has_ffi_unwind_calls(def);
335+
tcx.ensure_with_value().mir_flags(def);
336336

337337
// the `by_move_body` query uses the raw mir, so make sure it is run.
338338
if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
339339
tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
340340
}
341341

342+
tcx.ensure_with_value().mir_flags(def);
343+
342344
let mut body = tcx.mir_built(def).steal();
343345
if let Some(error_reported) = const_qualifs.tainted_by_errors {
344346
body.tainted_by_errors = Some(error_reported);
@@ -361,6 +363,33 @@ fn mir_promoted(
361363
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
362364
}
363365

366+
fn mir_flags<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> MirFlags {
367+
let mut flags = MirFlags::default();
368+
if !tcx.is_mir_available(local_def_id) {
369+
return flags;
370+
}
371+
372+
// Only perform check on functions because constants cannot call FFI functions.
373+
let kind = tcx.def_kind(local_def_id);
374+
if !kind.is_fn_like() {
375+
return flags;
376+
}
377+
378+
let body = &*tcx.mir_built(local_def_id).borrow();
379+
380+
if is_nounwind(body) {
381+
flags.insert(MirFlags::IS_NOUNWIND);
382+
}
383+
if ffi_unwind_calls::has_ffi_unwind_calls(tcx, body) {
384+
flags.insert(MirFlags::HAS_FFI_UNWIND_CALLS);
385+
}
386+
flags
387+
}
388+
389+
fn is_nounwind<'tcx>(body: &Body<'tcx>) -> bool {
390+
body.basic_blocks.iter().all(|block| block.terminator().unwind().is_none())
391+
}
392+
364393
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
365394
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
366395
tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))

‎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/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
}
1212

1313
bb1: {
14-
_1 = noop() -> [return: bb2, unwind continue];
14+
_1 = noop() -> [return: bb2, unwind unreachable];
1515
}
1616

1717
bb2: {
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.