Skip to content

Commit 53d9f64

Browse files
committed
Do not lint if only has MaybeUninit fields
1 parent 9058b04 commit 53d9f64

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
lines changed

clippy_lints/src/incorrect_impls.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use clippy_utils::{
22
diagnostics::{span_lint_and_sugg, span_lint_and_then},
33
get_parent_node, is_res_lang_ctor, last_path_segment, path_res,
4-
ty::implements_trait,
4+
ty::{implements_trait, is_type_lang_item},
55
};
6+
use itertools::Itertools;
67
use rustc_errors::Applicability;
78
use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
89
use rustc_hir_analysis::hir_ty_to_ty;
910
use rustc_lint::{LateContext, LateLintPass};
10-
use rustc_middle::ty::EarlyBinder;
11+
use rustc_middle::ty::{self, EarlyBinder};
1112
use rustc_session::{declare_lint_pass, declare_tool_lint};
1213
use rustc_span::{sym, symbol::kw};
1314

@@ -19,6 +20,14 @@ declare_clippy_lint! {
1920
/// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing
2021
/// `self` in `Clone`'s implementation. Anything else is incorrect.
2122
///
23+
/// ### Known issues
24+
/// While anything other than `*self` is *technically* incorrect, it can often be done as an
25+
/// optimization, like in the case of `MaybeUninit` for example. Returning a new `MaybeUninit`
26+
/// is both faster and as correct as `memcpy`ing the original. If this is not the case however,
27+
/// the lint's advice should almost always be applied.
28+
///
29+
/// Note: This lint ignores `Clone` implementations on types that are just `MaybeUninit`.
30+
///
2231
/// ### Example
2332
/// ```rust,ignore
2433
/// #[derive(Eq, PartialEq)]
@@ -47,7 +56,7 @@ declare_clippy_lint! {
4756
/// ```
4857
#[clippy::version = "1.72.0"]
4958
pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
50-
correctness,
59+
complexity,
5160
"manual implementation of `Clone` on a `Copy` type"
5261
}
5362
declare_clippy_lint! {
@@ -140,7 +149,31 @@ impl LateLintPass<'_> for IncorrectImpls {
140149
copy_def_id,
141150
&[],
142151
)
152+
&& let ty::Adt(def, substs) = hir_ty_to_ty(cx.tcx, imp.self_ty).kind()
143153
{
154+
let fields = def.all_fields().collect_vec();
155+
// Necessary as `all` returns true on an empty iterator
156+
if !fields.is_empty()
157+
&& fields.iter().all(|field| {
158+
let ty = field.ty(cx.tcx, substs);
159+
160+
match ty.kind() {
161+
// `MaybeUninit<T>`
162+
ty::Adt(_, _) if is_type_lang_item(cx, ty, LangItem::MaybeUninit) => true,
163+
// `[MaybeUninit<T>; N]`
164+
ty::Array(inner_ty, _) | ty::Slice(inner_ty)
165+
if is_type_lang_item(cx, *inner_ty, LangItem::MaybeUninit) =>
166+
{
167+
true
168+
},
169+
// Other cases are likely pretty rare.
170+
_ => false,
171+
}
172+
})
173+
{
174+
return;
175+
}
176+
144177
if impl_item.ident.name == sym::clone {
145178
if block.stmts.is_empty()
146179
&& let Some(expr) = block.expr

tests/ui/incorrect_clone_impl_on_copy_type.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,14 @@ impl<A: Copy> Clone for Uwu<A> {
9595
}
9696

9797
impl<A: std::fmt::Debug + Copy + Clone> Copy for Uwu<A> {}
98+
99+
// do not lint if type has only `MaybeUninit` fields
100+
struct G([std::mem::MaybeUninit<u32>; 100]);
101+
102+
impl Clone for G {
103+
fn clone(&self) -> Self {
104+
todo!()
105+
}
106+
}
107+
108+
impl Copy for G {}

tests/ui/incorrect_clone_impl_on_copy_type.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,14 @@ impl<A: Copy> Clone for Uwu<A> {
105105
}
106106

107107
impl<A: std::fmt::Debug + Copy + Clone> Copy for Uwu<A> {}
108+
109+
// do not lint if type has only `MaybeUninit` fields
110+
struct G([std::mem::MaybeUninit<u32>; 100]);
111+
112+
impl Clone for G {
113+
fn clone(&self) -> Self {
114+
todo!()
115+
}
116+
}
117+
118+
impl Copy for G {}

tests/ui/incorrect_clone_impl_on_copy_type.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | | Self(self.0)
77
LL | | }
88
| |_____^ help: change this to: `{ *self }`
99
|
10-
= note: `#[deny(clippy::incorrect_clone_impl_on_copy_type)]` on by default
10+
= note: `-D clippy::incorrect-clone-impl-on-copy-type` implied by `-D warnings`
1111

1212
error: incorrect implementation of `clone_from` on a `Copy` type
1313
--> $DIR/incorrect_clone_impl_on_copy_type.rs:14:5

0 commit comments

Comments
 (0)