mentioned items: also handle closure-to-fn-ptr coercions

This commit is contained in:
Ralf Jung 2024-03-17 13:42:54 +01:00
parent 347ca50bc8
commit f1ec494c32
6 changed files with 99 additions and 1 deletions

View File

@ -324,7 +324,8 @@ pub enum MentionedItem<'tcx> {
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
},
// FIXME: do we have to add closures?
/// A closure that is coerced to a function pointer.
Closure(DefId, GenericArgsRef<'tcx>),
}
/// The lowered representation of a single function.

View File

@ -74,6 +74,22 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
span,
});
}
// Similarly, record closures that are turned into function pointers.
mir::Rvalue::Cast(
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
ref operand,
_,
) => {
let span = self.body.source_info(location).span;
let source_ty = operand.ty(self.body, self.tcx);
match *source_ty.kind() {
ty::Closure(def_id, args) => {
self.mentioned_items
.push(Spanned { node: MentionedItem::Closure(def_id, args), span });
}
_ => bug!(),
}
}
// Function pointer casts are already handled by `visit_constant` above.
_ => {}
}

View File

@ -1727,6 +1727,12 @@ fn visit_mentioned_item<'tcx>(
create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output);
}
}
MentionedItem::Closure(def_id, args) => {
let instance = Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
if should_codegen_locally(tcx, &instance) {
output.push(create_fn_mono_item(tcx, instance, span));
}
}
}
}

View File

@ -0,0 +1,23 @@
error[E0080]: evaluation of `Fail::<i32>::C` failed
--> $DIR/collect-in-dead-closure.rs:8:19
|
LL | const C: () = panic!();
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:8:19
|
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
note: erroneous constant encountered
--> $DIR/collect-in-dead-closure.rs:16:17
|
LL | let _ = Fail::<T>::C;
| ^^^^^^^^^^^^
note: the above error was encountered while instantiating `fn not_called::<i32>`
--> $DIR/collect-in-dead-closure.rs:23:33
|
LL | let _closure: fn() = || not_called::<T>();
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View File

@ -0,0 +1,23 @@
error[E0080]: evaluation of `Fail::<i32>::C` failed
--> $DIR/collect-in-dead-closure.rs:8:19
|
LL | const C: () = panic!();
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:8:19
|
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
note: erroneous constant encountered
--> $DIR/collect-in-dead-closure.rs:16:17
|
LL | let _ = Fail::<T>::C;
| ^^^^^^^^^^^^
note: the above error was encountered while instantiating `fn not_called::<i32>`
--> $DIR/collect-in-dead-closure.rs:23:33
|
LL | let _closure: fn() = || not_called::<T>();
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View File

@ -0,0 +1,29 @@
//@revisions: noopt opt
//@ build-fail
//@[opt] compile-flags: -O
//! This fails without optimizations, so it should also fail with optimizations.
struct Fail<T>(T);
impl<T> Fail<T> {
const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
}
// This function is not actually called, but it is mentioned in a closure that is coerced to a
// function pointer in dead code in a function that is called. Make sure we still find this error.
#[inline(never)]
fn not_called<T>() {
if false {
let _ = Fail::<T>::C;
}
}
#[inline(never)]
fn called<T>() {
if false {
let _closure: fn() = || not_called::<T>();
}
}
pub fn main() {
called::<i32>();
}