Skip to content

Commit 33d2d93

Browse files
committed
mentioned items: also handle closure-to-fn-ptr coercions
1 parent 2eda95b commit 33d2d93

File tree

6 files changed

+99
-1
lines changed

6 files changed

+99
-1
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,8 @@ pub enum MentionedItem<'tcx> {
324324
source_ty: Ty<'tcx>,
325325
target_ty: Ty<'tcx>,
326326
},
327-
// FIXME: do we have to add closures?
327+
/// A closure that is coerced to a function pointer.
328+
Closure(DefId, GenericArgsRef<'tcx>),
328329
}
329330

330331
/// The lowered representation of a single function.

compiler/rustc_mir_transform/src/mentioned_items.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,22 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
7474
span,
7575
});
7676
}
77+
// Similarly, record closures that are turned into function pointers.
78+
mir::Rvalue::Cast(
79+
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
80+
ref operand,
81+
_,
82+
) => {
83+
let span = self.body.source_info(location).span;
84+
let source_ty = operand.ty(self.body, self.tcx);
85+
match *source_ty.kind() {
86+
ty::Closure(def_id, args) => {
87+
self.mentioned_items
88+
.push(Spanned { node: MentionedItem::Closure(def_id, args), span });
89+
}
90+
_ => bug!(),
91+
}
92+
}
7793
// Function pointer casts are already handled by `visit_constant` above.
7894
_ => {}
7995
}

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,12 @@ fn visit_mentioned_item<'tcx>(
17201720
create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output);
17211721
}
17221722
}
1723+
MentionedItem::Closure(def_id, args) => {
1724+
let instance = Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
1725+
if should_codegen_locally(tcx, &instance) {
1726+
output.push(create_fn_mono_item(tcx, instance, span));
1727+
}
1728+
}
17231729
}
17241730
}
17251731

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-closure.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:8:19
6+
|
7+
= 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)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-closure.rs:16:17
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn not_called::<i32>`
16+
--> $DIR/collect-in-dead-closure.rs:23:33
17+
|
18+
LL | let _closure: fn() = || not_called::<T>();
19+
| ^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0080`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-closure.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:8:19
6+
|
7+
= 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)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-closure.rs:16:17
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn not_called::<i32>`
16+
--> $DIR/collect-in-dead-closure.rs:23:33
17+
|
18+
LL | let _closure: fn() = || not_called::<T>();
19+
| ^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0080`.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@revisions: noopt opt
2+
//@ build-fail
3+
//@[opt] compile-flags: -O
4+
//! This fails without optimizations, so it should also fail with optimizations.
5+
6+
struct Fail<T>(T);
7+
impl<T> Fail<T> {
8+
const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
9+
}
10+
11+
// This function is not actually called, but it is mentioned in a closure that is coerced to a
12+
// function pointer in dead code in a function that is called. Make sure we still find this error.
13+
#[inline(never)]
14+
fn not_called<T>() {
15+
if false {
16+
let _ = Fail::<T>::C;
17+
}
18+
}
19+
20+
#[inline(never)]
21+
fn called<T>() {
22+
if false {
23+
let _closure: fn() = || not_called::<T>();
24+
}
25+
}
26+
27+
pub fn main() {
28+
called::<i32>();
29+
}

0 commit comments

Comments
 (0)