-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MIR validation for unwind out from nounwind functions + fixes to make validation pass #113124
Conversation
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
☔ The latest upstream changes (presumably #113429) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm not sure about the nop-landing-pads change |
resume_block | ||
// Find the resume block | ||
let Some(resume_block) = body.basic_blocks.iter_enumerated().find(|(_bb, block)| { | ||
matches!(block.terminator().kind, TerminatorKind::Resume) && block.statements.is_empty() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we ever have a resume
terminator with statements?
- if yes, we may need to create an empty resume block for this pass;
- if no, the
block.statements.is_empty()
would be better as an assertion + comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the answer is yes, and the empty resume block is indeed needed for this pass. I'll need to use a different way to skip the empty resume block creation for nounwind functions.
&mut body, | ||
&[], | ||
Some(MirPhase::Runtime(RuntimePhase::Optimized)), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be in generator.rs
, where we construct this MIR? Where you run AbortUnwindingCalls
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validator wants to know about layouts, and the layouts require the lowering of resume
, so a cycle can be created if validation is performed in generator.rs
.
This comment has been minimized.
This comment has been minimized.
// Update the body's def to become the drop glue. | ||
let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); | ||
body.source.instance = InstanceDef::DropGlue(drop_in_place, Some(gen_ty)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added these lines so that AbortUnwindingCalls
will use the ABI of drop_in_place instead of the resume function, but apparently this breaks the validation.
Currently body.source
for the generator drop MIR contains that of the generator, which I don't think is correct, but I don't know what causes the validation to fail so I couldn't fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the failure message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's failing in the CI.
##[error]error: internal compiler error: broken MIR in DropGlue(DefId(2:2150 ~ core[a05a]::ptr::drop_in_place), Some([async fn body@fake-test-src-base/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs:57:5: 61:6])) (after phase change to runtime-optimized) at bb1[2]:
Field projection `PlaceRef { local: _1, projection: [Deref, Downcast(None, 3)] }.0` specified type `std::pin::Pin<std::boxed::Box<dyn std::future::Future<Output = std::result::Result<<SaveUser<'_> as StorageRequestReturnType>::Output, <InMemoryStorage as Storage>::Error>>>>`, but actual type is `std::pin::Pin<std::boxed::Box<dyn std::future::Future<Output = std::result::Result<<SaveUser<'_> as StorageRequestReturnType>::Output, <S as Storage>::Error>>>>`
--> fake-test-src-base/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs:60:18
LL | .await;
| ^
|
= note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:380:30
= note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:380:30
0: <rustc_errors::HandlerInner>::emit_diagnostic
1: <rustc_errors::Handler>::delay_span_bug::<rustc_span::span_encoding::Span, alloc::string::String>
2: <rustc_const_eval::transform::validate::TypeChecker>::fail::<alloc::string::String>
3: <rustc_const_eval::transform::validate::TypeChecker as rustc_middle::mir::visit::Visitor>::visit_projection_elem
4: <rustc_const_eval::transform::validate::TypeChecker as rustc_middle::mir::visit::Visitor>::visit_place
5: <rustc_const_eval::transform::validate::TypeChecker as rustc_middle::mir::visit::Visitor>::visit_terminator
6: <rustc_const_eval::transform::validate::Validator as rustc_middle::mir::MirPass>::run_pass
8: rustc_mir_transform::shim::make_shim
9: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::mir_shims::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 8]>>
9: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::mir_shims::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 8]>>
10: <rustc_query_impl::query_impl::mir_shims::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_middle::ty::instance::InstanceDef)>>::call_once
11: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::DefaultCache<rustc_middle::ty::instance::InstanceDef, rustc_middle::query::erase::Erased<[u8; 8]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, false>
12: rustc_query_impl::query_impl::mir_shims::get_query_non_incr::__rust_end_short_backtrace
14: rustc_monomorphize::collector::collect_used_items
15: rustc_monomorphize::collector::collect_items_rec
16: rustc_monomorphize::collector::collect_items_rec
17: rustc_monomorphize::collector::collect_items_rec
17: rustc_monomorphize::collector::collect_items_rec
18: rustc_monomorphize::collector::collect_items_rec
19: <core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::par_for_each_in<alloc::vec::Vec<rustc_middle::mir::mono::MonoItem>, rustc_monomorphize::collector::collect_crate_mono_items::{closure#1}::{closure#0}>::{closure#0}::{closure#0}> as core::ops::function::FnOnce<()>>::call_once
20: std::panicking::try::<(), core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::par_for_each_in<alloc::vec::Vec<rustc_middle::mir::mono::MonoItem>, rustc_monomorphize::collector::collect_crate_mono_items::{closure#1}::{closure#0}>::{closure#0}::{closure#0}>>
21: rustc_data_structures::sync::par_for_each_in::<alloc::vec::Vec<rustc_middle::mir::mono::MonoItem>, rustc_monomorphize::collector::collect_crate_mono_items::{closure#1}::{closure#0}>
22: <rustc_session::session::Session>::time::<(), rustc_monomorphize::collector::collect_crate_mono_items::{closure#1}>
23: rustc_monomorphize::collector::collect_crate_mono_items
24: rustc_monomorphize::partitioning::collect_and_partition_mono_items
25: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::collect_and_partition_mono_items::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 24]>>
26: <rustc_query_impl::query_impl::collect_and_partition_mono_items::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, ())>>::call_once
27: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::SingleCache<rustc_middle::query::erase::Erased<[u8; 24]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, false>
28: rustc_query_impl::query_impl::collect_and_partition_mono_items::get_query_non_incr::__rust_end_short_backtrace
29: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
30: <rustc_session::session::Session>::time::<alloc::boxed::Box<dyn core::any::Any>, rustc_interface::passes::start_codegen::{closure#0}>
31: rustc_interface::passes::start_codegen
32: <rustc_middle::ty::context::GlobalCtxt>::enter::<<rustc_interface::queries::Queries>::ongoing_codegen::{closure#0}, core::result::Result<alloc::boxed::Box<dyn core::any::Any>, rustc_span::ErrorGuaranteed>>
33: <rustc_interface::queries::Queries>::ongoing_codegen
35: rustc_span::set_source_map::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}::{closure#0}>
36: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::set::<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
37: std::sys_common::backtrace::__rust_begin_short_backtrace::<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
38: std::panicking::try::<core::result::Result<(), rustc_span::ErrorGuaranteed>, core::panic::unwind_safe::AssertUnwindSafe<<std::thread::Builder>::spawn_unchecked_<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#1}::{closure#0}>>
38: std::panicking::try::<core::result::Result<(), rustc_span::ErrorGuaranteed>, core::panic::unwind_safe::AssertUnwindSafe<<std::thread::Builder>::spawn_unchecked_<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#1}::{closure#0}>>
39: <<std::thread::Builder>::spawn_unchecked_<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#1} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
40: std::sys::unix::thread::Thread::new::thread_start
41: <unknown>
42: <unknown>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What am I supposed to do with this? remove the line and add a fixme?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This MIR body will exactly become the drop glue, so you can keep that line as-is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Digged into the ICE and the failure is caused by validator not considering the subst of the generator when determining the type. Adding a ty::EarlyBinder::bind(...).instantiate(self.tcx, args)
fix the issue.
☔ The latest upstream changes (presumably #113591) made this pull request unmergeable. Please resolve the merge conflicts. |
r=me after rebase |
This comment has been minimized.
This comment has been minimized.
Otherwise the file name generated for generator_drop will become core.ptr-drop_in_place.[generator@<FILEPATH>_<NUMBERS>].generator_drop.0.mir instead of main-{closure#0}.generator_drop.0.mir which breaks a mir-opt test.
@bors r+ |
☀️ Test successful - checks-actions |
Finished benchmarking commit (ff55fa3): comparison URL. Overall result: ✅ improvements - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 637.108s -> 634.223s (-0.45%) |
Validation introduced in rust-lang#113124 allows UnwindAction::Continue and TerminatorKind::Resume to occur only in functions with ABI that can unwind. The function ABI depends on the panic strategy, which can vary across crates. Usually MIR is built and validated in the same crate. The coroutine drop glue thus far was an exception. As a result validation could fail when mixing different panic strategies. Avoid the problem by executing AbortUnwindingCalls along with the validation.
Fix coroutine validation for mixed panic strategy Validation introduced in rust-lang#113124 allows `UnwindAction::Continue` and `TerminatorKind::Resume` to occur only in functions with ABI that can unwind. The function ABI depends on the panic strategy, which can vary across crates. Usually MIR is built and validated in the same crate. The coroutine drop glue thus far was an exception. As a result validation could fail when mixing different panic strategies. Avoid the problem by executing `AbortUnwindingCalls` along with the validation. Fixes rust-lang#116953.
Rollup merge of rust-lang#118422 - tmiasko:mix, r=compiler-errors Fix coroutine validation for mixed panic strategy Validation introduced in rust-lang#113124 allows `UnwindAction::Continue` and `TerminatorKind::Resume` to occur only in functions with ABI that can unwind. The function ABI depends on the panic strategy, which can vary across crates. Usually MIR is built and validated in the same crate. The coroutine drop glue thus far was an exception. As a result validation could fail when mixing different panic strategies. Avoid the problem by executing `AbortUnwindingCalls` along with the validation. Fixes rust-lang#116953.
Validation introduced in rust-lang#113124 allows UnwindAction::Continue and TerminatorKind::Resume to occur only in functions with ABI that can unwind. The function ABI depends on the panic strategy, which can vary across crates. Usually MIR is built and validated in the same crate. The coroutine drop glue thus far was an exception. As a result validation could fail when mixing different panic strategies. Avoid the problem by executing AbortUnwindingCalls along with the validation.
Validation introduced in rust-lang#113124 allows UnwindAction::Continue and TerminatorKind::Resume to occur only in functions with ABI that can unwind. The function ABI depends on the panic strategy, which can vary across crates. Usually MIR is built and validated in the same crate. The coroutine drop glue thus far was an exception. As a result validation could fail when mixing different panic strategies. Avoid the problem by executing AbortUnwindingCalls along with the validation. (cherry picked from commit 5161b22)
@Nilstrieb This is the MIR validation you asked in #112403 (comment).
Two passes need to be fixed to get the validation to pass:
RemoveNoopLandingPads
currently unconditionally introduce a resume block (even there is none to begin with!), changed to not do thatassert
which may unwind, and its drop elaboration also introduces many newUnwindAction
s, so in this case run the AbortUnwindingCalls after the transformation.I believe this PR should also fix Rust-for-Linux/linux#1016, cc @ojeda
r? @Nilstrieb