about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-11 01:37:55 +0100
committerGitHub <noreply@github.com>2024-02-11 01:37:55 +0100
commitfd287d2e88fc7c5a85e544fb2c37223575a53cae (patch)
treeb9785009fdc3ffe7a45e168b52c1bb75b911f27d
parente525bc9592392e8a06e2f277deed4b59f40eaf61 (diff)
parenta4fbd01af28449de087efae8ecfa05e2264b3601 (diff)
downloadrust-fd287d2e88fc7c5a85e544fb2c37223575a53cae.tar.gz
rust-fd287d2e88fc7c5a85e544fb2c37223575a53cae.zip
Rollup merge of #120773 - Enselic:copy-vs-move, r=oli-obk
large_assignments: Allow moves into functions

Moves into functions are typically implemented with pointer passing
rather than memcpy's at the llvm-ir level, so allow moves into
functions.

Part of the "Differentiate between Operand::Move and Operand::Copy" step of https://github.com/rust-lang/rust/issues/83518.

r? `@oli-obk` (who I think is still E-mentor?)
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--tests/ui/lint/large_assignments/box_rc_arc_allowed.rs29
-rw-r--r--tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs38
-rw-r--r--tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr (renamed from tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr)16
-rw-r--r--tests/ui/lint/large_assignments/large_future.rs2
-rw-r--r--tests/ui/lint/large_assignments/move_into_box_rc_arc.rs38
-rw-r--r--tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr15
-rw-r--r--tests/ui/lint/large_assignments/move_into_fn.rs22
-rw-r--r--tests/ui/lint/large_assignments/move_into_fn.stderr15
9 files changed, 147 insertions, 38 deletions
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 3376af98653..149e4c2cb08 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -666,7 +666,15 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         debug!(?def_id, ?fn_span);
 
         for arg in args {
-            if let Some(too_large_size) = self.operand_size_if_too_large(limit, &arg.node) {
+            // Moving args into functions is typically implemented with pointer
+            // passing at the llvm-ir level and not by memcpy's. So always allow
+            // moving args into functions.
+            let operand: &mir::Operand<'tcx> = &arg.node;
+            if let mir::Operand::Move(_) = operand {
+                continue;
+            }
+
+            if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
                 self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
             };
         }
diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
deleted file mode 100644
index 33113642023..00000000000
--- a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#![deny(large_assignments)]
-#![feature(large_assignments)]
-#![move_size_limit = "1000"]
-// build-fail
-// only-x86_64
-
-// edition:2018
-// compile-flags: -Zmir-opt-level=0
-
-use std::{sync::Arc, rc::Rc};
-
-fn main() {
-    let _ = Arc::new([0; 9999]); // OK!
-    let _ = Box::new([0; 9999]); // OK!
-    let _ = Rc::new([0; 9999]); // OK!
-    let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments
-}
-
-struct NotBox {
-    data: [u8; 9999],
-}
-
-impl NotBox {
-    fn new(data: [u8; 9999]) -> Self {
-        Self {
-            data, //~ ERROR large_assignments
-        }
-    }
-}
diff --git a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs
new file mode 100644
index 00000000000..866a4d10ff5
--- /dev/null
+++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs
@@ -0,0 +1,38 @@
+#![deny(large_assignments)]
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+// build-fail
+// only-64bit
+
+// edition:2018
+// compile-flags: -Zmir-opt-level=1
+
+use std::{sync::Arc, rc::Rc};
+
+fn main() {
+    let data = [0; 9999];
+
+    // Looking at --emit mir, we can see that all parameters below are passed by
+    // copy. But it requires at least mir-opt-level=1.
+    let _ = Arc::new(data); // OK!
+    let _ = Box::new(data); // OK!
+    let _ = Rc::new(data); // OK!
+
+    // Looking at --emit llvm-ir, we can see that a memcpy is involved in the
+    // parameter passing. So we want the lint to trigger here.
+    let _ = NotBox::new(data); //~ ERROR large_assignments
+}
+
+struct NotBox {
+    data: [u8; 9999],
+}
+
+impl NotBox {
+    fn new(data: [u8; 9999]) -> Self {
+        // Looking at --emit llvm-ir, we can see that a memcpy is involved.
+        // So we want the lint to trigger here.
+        Self { //~ ERROR large_assignments
+            data,
+        }
+    }
+}
diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr
index fefb3a9621b..6e42328a111 100644
--- a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr
+++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr
@@ -1,21 +1,23 @@
 error: moving 9999 bytes
-  --> $DIR/box_rc_arc_allowed.rs:16:25
+  --> $DIR/copy_into_box_rc_arc.rs:23:25
    |
-LL |     let _ = NotBox::new([0; 9999]);
-   |                         ^^^^^^^^^ value moved from here
+LL |     let _ = NotBox::new(data);
+   |                         ^^^^ value moved from here
    |
    = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
 note: the lint level is defined here
-  --> $DIR/box_rc_arc_allowed.rs:1:9
+  --> $DIR/copy_into_box_rc_arc.rs:1:9
    |
 LL | #![deny(large_assignments)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: moving 9999 bytes
-  --> $DIR/box_rc_arc_allowed.rs:26:13
+  --> $DIR/copy_into_box_rc_arc.rs:34:9
    |
-LL |             data,
-   |             ^^^^ value moved from here
+LL | /         Self {
+LL | |             data,
+LL | |         }
+   | |_________^ value moved from here
    |
    = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
 
diff --git a/tests/ui/lint/large_assignments/large_future.rs b/tests/ui/lint/large_assignments/large_future.rs
index 834746fa97e..a69ff356c6b 100644
--- a/tests/ui/lint/large_assignments/large_future.rs
+++ b/tests/ui/lint/large_assignments/large_future.rs
@@ -2,7 +2,7 @@
 #![cfg_attr(attribute, feature(large_assignments))]
 #![cfg_attr(attribute, move_size_limit = "1000")]
 // build-fail
-// only-x86_64
+// only-64bit
 // revisions: attribute option
 // [option]compile-flags: -Zmove-size-limit=1000
 
diff --git a/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs b/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs
new file mode 100644
index 00000000000..b7a70dfdda0
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs
@@ -0,0 +1,38 @@
+#![deny(large_assignments)]
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+// build-fail
+// only-64bit
+
+// edition:2018
+// compile-flags: -Zmir-opt-level=0
+
+use std::{sync::Arc, rc::Rc};
+
+fn main() {
+    // Looking at --emit mir, we can see that all parameters below are passed
+    // by move.
+    let _ = Arc::new([0; 9999]); // OK!
+    let _ = Box::new([0; 9999]); // OK!
+    let _ = Rc::new([0; 9999]); // OK!
+
+    // Looking at --emit llvm-ir, we can see that no memcpy is involved in the
+    // parameter passing. Instead, a pointer is passed. This is typically what
+    // we get when moving parameter into functions. So we don't want the lint to
+    // trigger here.
+    let _ = NotBox::new([0; 9999]); // OK (compare with copy_into_box_rc_arc.rs)
+}
+
+struct NotBox {
+    data: [u8; 9999],
+}
+
+impl NotBox {
+    fn new(data: [u8; 9999]) -> Self {
+        Self {
+            // Looking at --emit llvm-ir, we can see that a memcpy is involved.
+            // So we want the lint to trigger here.
+            data, //~ ERROR large_assignments
+        }
+    }
+}
diff --git a/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr
new file mode 100644
index 00000000000..a386de5e5e8
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr
@@ -0,0 +1,15 @@
+error: moving 9999 bytes
+  --> $DIR/move_into_box_rc_arc.rs:35:13
+   |
+LL |             data,
+   |             ^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/move_into_box_rc_arc.rs:1:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/large_assignments/move_into_fn.rs b/tests/ui/lint/large_assignments/move_into_fn.rs
new file mode 100644
index 00000000000..359705bfc03
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_fn.rs
@@ -0,0 +1,22 @@
+// build-fail
+
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+#![deny(large_assignments)]
+#![allow(unused)]
+
+// Note: This type does not implement Copy.
+struct Data([u8; 9999]);
+
+fn main() {
+    // Looking at llvm-ir output, we can see a memcpy'd into Data, so we want
+    // the lint to trigger here.
+    let data = Data([100; 9999]); //~ ERROR large_assignments
+
+    // Looking at llvm-ir output, we can see that there is no memcpy involved in
+    // this function call. Instead, just a pointer is passed to the function. So
+    // the lint shall not trigger here.
+    take_data(data);
+}
+
+fn take_data(data: Data) {}
diff --git a/tests/ui/lint/large_assignments/move_into_fn.stderr b/tests/ui/lint/large_assignments/move_into_fn.stderr
new file mode 100644
index 00000000000..92a0489e472
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_fn.stderr
@@ -0,0 +1,15 @@
+error: moving 9999 bytes
+  --> $DIR/move_into_fn.rs:14:16
+   |
+LL |     let data = Data([100; 9999]);
+   |                ^^^^^^^^^^^^^^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/move_into_fn.rs:5:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+