about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-03-17 13:42:54 +0100
committerRalf Jung <post@ralfj.de>2024-03-20 11:07:12 +0100
commitf1ec494c322a2eabbba0bf93867170f702e7a05a (patch)
treee225dd8a85d2131df7600ca6d9359d7ac086c41a
parent347ca50bc82734b45ed1834fd3a15ed978aba258 (diff)
downloadrust-f1ec494c322a2eabbba0bf93867170f702e7a05a.tar.gz
rust-f1ec494c322a2eabbba0bf93867170f702e7a05a.zip
mentioned items: also handle closure-to-fn-ptr coercions
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs16
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs6
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.rs29
6 files changed, 99 insertions, 1 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index f7451e4c916..8e9b095028c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -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.
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index 0e0114c9d2c..63f898630ab 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -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.
             _ => {}
         }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 005a2233507..a5ab4ab3d18 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -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));
+            }
+        }
     }
 }
 
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr
new file mode 100644
index 00000000000..40cecaab241
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr
@@ -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`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr
new file mode 100644
index 00000000000..d6298132e1b
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr
@@ -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`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.rs b/tests/ui/consts/required-consts/collect-in-dead-closure.rs
new file mode 100644
index 00000000000..91f52827af4
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.rs
@@ -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>();
+}