mentioned items: also handle closure-to-fn-ptr coercions
This commit is contained in:
parent
347ca50bc8
commit
f1ec494c32
6 changed files with 99 additions and 1 deletions
|
@ -324,7 +324,8 @@ pub enum MentionedItem<'tcx> {
|
||||||
source_ty: Ty<'tcx>,
|
source_ty: Ty<'tcx>,
|
||||||
target_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.
|
/// The lowered representation of a single function.
|
||||||
|
|
|
@ -74,6 +74,22 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
|
||||||
span,
|
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.
|
// Function pointer casts are already handled by `visit_constant` above.
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1727,6 +1727,12 @@ fn visit_mentioned_item<'tcx>(
|
||||||
create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output);
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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`.
|
|
@ -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`.
|
29
tests/ui/consts/required-consts/collect-in-dead-closure.rs
Normal file
29
tests/ui/consts/required-consts/collect-in-dead-closure.rs
Normal 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>();
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue