about summary refs log tree commit diff
diff options
context:
space:
mode:
authormejrs <>2022-09-28 15:11:27 +0200
committermejrs <>2022-11-29 17:33:50 +0100
commit4ced370f7c03dad99c74ceb4b86a0538b970690a (patch)
treeb9c8dfd78187732b12425fbfde09cc2dc32404e7
parentc372b1470109547e37dcc29ffd4723ac9f66f15d (diff)
downloadrust-4ced370f7c03dad99c74ceb4b86a0538b970690a.tar.gz
rust-4ced370f7c03dad99c74ceb4b86a0538b970690a.zip
Make `missing_copy_implementations` more cautious
-rw-r--r--compiler/rustc_lint/src/builtin.rs34
-rw-r--r--src/test/ui/lint/lint-missing-copy-implementations-allow.rs35
2 files changed, 68 insertions, 1 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 93d81125f48..1ea41098413 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -46,6 +46,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::List;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
@@ -53,7 +54,8 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::{Abi, VariantIdx};
-use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
+use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
+use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -750,10 +752,40 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         if def.has_dtor(cx.tcx) {
             return;
         }
+
+        // If the type contains a raw pointer, it may represent something like a handle,
+        // and recommending Copy might be a bad idea.
+        for field in def.all_fields() {
+            let did = field.did;
+            if cx.tcx.type_of(did).is_unsafe_ptr() {
+                return;
+            }
+        }
         let param_env = ty::ParamEnv::empty();
         if ty.is_copy_modulo_regions(cx.tcx, param_env) {
             return;
         }
+
+        // We shouldn't recommend implementing `Copy` on stateful things,
+        // such as iterators.
+        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) {
+            if cx.tcx.infer_ctxt().enter(|infer_ctxt| {
+                infer_ctxt.type_implements_trait(iter_trait, ty, List::empty(), param_env)
+                    == EvaluationResult::EvaluatedToOk
+            }) {
+                return;
+            }
+        }
+
+        // Default value of clippy::trivially_copy_pass_by_ref
+        const MAX_SIZE: u64 = 256;
+
+        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {
+            if size > MAX_SIZE {
+                return;
+            }
+        }
+
         if can_type_implement_copy(
             cx.tcx,
             param_env,
diff --git a/src/test/ui/lint/lint-missing-copy-implementations-allow.rs b/src/test/ui/lint/lint-missing-copy-implementations-allow.rs
new file mode 100644
index 00000000000..051a905aed6
--- /dev/null
+++ b/src/test/ui/lint/lint-missing-copy-implementations-allow.rs
@@ -0,0 +1,35 @@
+// check-pass
+#![deny(missing_copy_implementations)]
+
+// Don't recommend implementing Copy on something stateful like an iterator.
+pub struct MyIterator {
+    num: u8,
+}
+
+impl Iterator for MyIterator {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!()
+    }
+}
+
+pub struct Handle {
+    inner: *mut (),
+}
+
+pub struct Handle2 {
+    inner: *const (),
+}
+
+pub enum MaybeHandle {
+    Ptr(*mut ()),
+}
+
+pub union UnionHandle {
+    ptr: *mut (),
+}
+
+pub struct Array([u8; 2048]);
+
+fn main() {}