@@ -7,6 +7,7 @@ use rustc_hir::{Item, ItemKind};
77use rustc_lint:: { LateContext , LateLintPass } ;
88use rustc_middle:: lint:: in_external_macro;
99use rustc_middle:: ty:: layout:: LayoutOf ;
10+ use rustc_middle:: ty:: { Adt , Ty } ;
1011use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
1112use rustc_span:: source_map:: Span ;
1213
@@ -26,6 +27,15 @@ declare_clippy_lint! {
2627 /// the overhead is negligible and the boxing is counter-productive. Always
2728 /// measure the change this lint suggests.
2829 ///
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+ ///
2939 /// ### Example
3040 /// ```rust
3141 /// // Bad
@@ -74,7 +84,7 @@ struct VariantInfo {
7484impl_lint_pass ! ( LargeEnumVariant => [ LARGE_ENUM_VARIANT ] ) ;
7585
7686impl < ' 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 > ) {
7888 if in_external_macro ( cx. tcx . sess , item. span ) {
7989 return ;
8090 }
@@ -132,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
132142 let fields = def. variants [ variants_size[ 0 ] . ind ] . data . fields ( ) ;
133143 variants_size[ 0 ] . fields_size . sort_by ( |a, b| ( a. size . cmp ( & b. size ) ) ) ;
134144 let mut applicability = Applicability :: MaybeIncorrect ;
135- if is_copy ( cx, ty) {
145+ if is_copy ( cx, ty) || maybe_copy ( cx , ty ) {
136146 diag. span_note (
137147 item. ident . span ,
138148 "boxing a variant would require the type no longer be `Copy`" ,
@@ -176,3 +186,13 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
176186 }
177187 }
178188}
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