Skip to content

Commit f1e0ec2

Browse files
committed
Do not lint if only has MaybeUninit fields
1 parent a959061 commit f1e0ec2

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

clippy_lints/src/incorrect_impls.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait};
1+
use clippy_utils::{
2+
diagnostics::span_lint_and_sugg,
3+
get_parent_node, last_path_segment,
4+
ty::{implements_trait, is_type_lang_item},
5+
};
26
use rustc_errors::Applicability;
3-
use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp};
7+
use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
48
use rustc_hir_analysis::hir_ty_to_ty;
59
use rustc_lint::{LateContext, LateLintPass};
6-
use rustc_middle::ty::EarlyBinder;
10+
use rustc_middle::ty::{self, EarlyBinder};
711
use rustc_session::{declare_lint_pass, declare_tool_lint};
812
use rustc_span::{sym, symbol};
913

@@ -15,6 +19,14 @@ declare_clippy_lint! {
1519
/// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing
1620
/// `self` in `Clone`'s implementation. Anything else is incorrect.
1721
///
22+
/// ### Known issues
23+
/// While anything other than `*self` is *technically* incorrect, it can often be done as an
24+
/// optimization, like in the case of `MaybeUninit` for example. Returning a new `MaybeUninit`
25+
/// is both faster and as correct as `memcpy`ing the original. If this is not the case however,
26+
/// the lint's advice should almost always be applied.
27+
///
28+
/// Note: This lint ignores `Clone` implementations on types that are just `MaybeUninit`.
29+
///
1830
/// ### Example
1931
/// ```rust,ignore
2032
/// #[derive(Eq, PartialEq)]
@@ -43,7 +55,7 @@ declare_clippy_lint! {
4355
/// ```
4456
#[clippy::version = "1.72.0"]
4557
pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
46-
correctness,
58+
complexity,
4759
"manual implementation of `Clone` on a `Copy` type"
4860
}
4961
declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]);
@@ -84,6 +96,10 @@ impl LateLintPass<'_> for IncorrectImpls {
8496
copy_def_id,
8597
trait_impl.substs,
8698
)
99+
&& let ty::Adt(def, substs) = hir_ty_to_ty(cx.tcx, imp.self_ty).kind()
100+
&& def
101+
.all_fields()
102+
.all(|field| is_type_lang_item(cx, field.ty(cx.tcx, substs), LangItem::MaybeUninit))
87103
{
88104
if impl_item.ident.name == sym::clone {
89105
if block.stmts.is_empty()

tests/ui/incorrect_clone_impl_on_copy_type.rs

+11
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([MaybeUninit<u32>; 100]);
111+
112+
impl Clone for G {
113+
fn clone(&self) -> Self {
114+
todo!()
115+
}
116+
}
117+
118+
impl Copy for G {}

0 commit comments

Comments
 (0)