@@ -7,6 +7,7 @@ use rustc_hir::{Item, ItemKind};
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
8
use rustc_middle:: lint:: in_external_macro;
9
9
use rustc_middle:: ty:: layout:: LayoutOf ;
10
+ use rustc_middle:: ty:: { Adt , Ty } ;
10
11
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
11
12
use rustc_span:: source_map:: Span ;
12
13
@@ -26,6 +27,15 @@ declare_clippy_lint! {
26
27
/// the overhead is negligible and the boxing is counter-productive. Always
27
28
/// measure the change this lint suggests.
28
29
///
30
+ /// For types that implement `Copy`, the suggestion to `Box` a variant's
31
+ /// data would require removing the trait impl. The types can of course
32
+ /// still be `Clone`, but that is worse ergonomically. Depending on the
33
+ /// use case it may be possible to store the large data in an auxillary
34
+ /// structure (e.g. Arena or ECS).
35
+ ///
36
+ /// The lint will ignore generic types if the layout depends on the
37
+ /// generics, even if the size difference will be large anyway.
38
+ ///
29
39
/// ### Example
30
40
/// ```rust
31
41
/// // Bad
@@ -74,7 +84,7 @@ struct VariantInfo {
74
84
impl_lint_pass ! ( LargeEnumVariant => [ LARGE_ENUM_VARIANT ] ) ;
75
85
76
86
impl < ' tcx > LateLintPass < ' tcx > for LargeEnumVariant {
77
- fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
87
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & Item < ' tcx > ) {
78
88
if in_external_macro ( cx. tcx . sess , item. span ) {
79
89
return ;
80
90
}
@@ -132,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
132
142
let fields = def. variants [ variants_size[ 0 ] . ind ] . data . fields ( ) ;
133
143
variants_size[ 0 ] . fields_size . sort_by ( |a, b| ( a. size . cmp ( & b. size ) ) ) ;
134
144
let mut applicability = Applicability :: MaybeIncorrect ;
135
- if is_copy ( cx, ty) {
145
+ if is_copy ( cx, ty) || maybe_copy ( cx , ty ) {
136
146
diag. span_note (
137
147
item. ident . span ,
138
148
"boxing a variant would require the type no longer be `Copy`" ,
@@ -176,3 +186,13 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
176
186
}
177
187
}
178
188
}
189
+
190
+ fn maybe_copy < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
191
+ if let Adt ( _def, substs) = ty. kind ( )
192
+ && substs. types ( ) . next ( ) . is_some ( )
193
+ && let Some ( copy_trait) = cx. tcx . lang_items ( ) . copy_trait ( )
194
+ {
195
+ return cx. tcx . non_blanket_impls_for_ty ( copy_trait, ty) . next ( ) . is_some ( ) ;
196
+ }
197
+ false
198
+ }
0 commit comments