Skip to content

Commit fe895f6

Browse files
committed
Use approx_ty_size for large_enum_variant
1 parent 09e4659 commit fe895f6

File tree

5 files changed

+163
-54
lines changed

5 files changed

+163
-54
lines changed

clippy_lints/src/large_enum_variant.rs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
//! lint when there is a large size difference between variants on an enum
22
33
use clippy_utils::source::snippet_with_applicability;
4-
use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
4+
use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
55
use rustc_errors::Applicability;
66
use rustc_hir::{Item, ItemKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_middle::lint::in_external_macro;
9-
use rustc_middle::ty::layout::LayoutOf;
109
use rustc_middle::ty::{Adt, Ty};
1110
use rustc_session::{declare_tool_lint, impl_lint_pass};
1211
use rustc_span::source_map::Span;
@@ -92,26 +91,24 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
9291
}
9392
if let ItemKind::Enum(ref def, _) = item.kind {
9493
let ty = cx.tcx.type_of(item.def_id);
95-
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
94+
let (adt, subst) = match ty.kind() {
95+
Adt(adt, subst) => (adt, subst),
96+
_ => panic!("already checked whether this is an enum"),
97+
};
9698
if adt.variants().len() <= 1 {
9799
return;
98100
}
99-
let mut variants_size: Vec<VariantInfo> = Vec::new();
101+
let mut variants_size: Vec<VariantInfo> = Vec::with_capacity(adt.variants().len());
100102
for (i, variant) in adt.variants().iter().enumerate() {
101-
let mut fields_size = Vec::new();
102-
for (i, f) in variant.fields.iter().enumerate() {
103-
let ty = cx.tcx.type_of(f.did);
104-
// don't lint variants which have a field of generic type.
105-
match cx.layout_of(ty) {
106-
Ok(l) => {
107-
let fsize = l.size.bytes();
108-
fields_size.push(FieldInfo { ind: i, size: fsize });
109-
},
110-
Err(_) => {
111-
return;
112-
},
113-
}
114-
}
103+
let fields_size = variant
104+
.fields
105+
.iter()
106+
.enumerate()
107+
.map(|(i, f)| FieldInfo {
108+
ind: i,
109+
size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
110+
})
111+
.collect::<Vec<_>>();
115112
let size: u64 = fields_size.iter().map(|info| info.size).sum();
116113

117114
variants_size.push(VariantInfo {
@@ -134,11 +131,18 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
134131
|diag| {
135132
diag.span_label(
136133
def.variants[variants_size[0].ind].span,
137-
&format!("this variant is {} bytes", variants_size[0].size),
134+
&format!("this variant contains at least {} bytes", variants_size[0].size),
138135
);
139136
diag.span_note(
140137
def.variants[variants_size[1].ind].span,
141-
&format!("and the second-largest variant is {} bytes:", variants_size[1].size),
138+
&if variants_size[1].fields_size.is_empty() {
139+
"and the second-largest variant carries no data at all".to_owned()
140+
} else {
141+
format!(
142+
"and the second-largest variant contains at least {} bytes:",
143+
variants_size[1].size
144+
)
145+
},
142146
);
143147

144148
let fields = def.variants[variants_size[0].ind].data.fields();

tests/ui/large_enum_variant.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,30 @@ impl<T: Copy> Clone for SomeGenericPossiblyCopyEnum<T> {
130130

131131
impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
132132

133+
enum LargeEnumWithGenerics<T> {
134+
Small,
135+
Large((T, [u8; 512])),
136+
}
137+
138+
struct Foo<T> {
139+
foo: T,
140+
}
141+
142+
enum WithGenerics {
143+
Large([Foo<u64>; 64]),
144+
Small(u8),
145+
}
146+
147+
enum PossiblyLargeEnumWithConst<const U: usize> {
148+
SmallBuffer([u8; 4]),
149+
MightyBuffer([u16; U]),
150+
}
151+
152+
enum LargeEnumOfConst {
153+
Ok,
154+
Error(PossiblyLargeEnumWithConst<256>),
155+
}
156+
133157
fn main() {
134158
large_enum_variant!();
135159
}

tests/ui/large_enum_variant.stderr

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ error: large size difference between variants
22
--> $DIR/large_enum_variant.rs:12:5
33
|
44
LL | B([i32; 8000]),
5-
| ^^^^^^^^^^^^^^ this variant is 32000 bytes
5+
| ^^^^^^^^^^^^^^ this variant contains at least 32000 bytes
66
|
77
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
8-
note: and the second-largest variant is 4 bytes:
8+
note: and the second-largest variant contains at least 4 bytes:
99
--> $DIR/large_enum_variant.rs:11:5
1010
|
1111
LL | A(i32),
@@ -19,9 +19,9 @@ error: large size difference between variants
1919
--> $DIR/large_enum_variant.rs:36:5
2020
|
2121
LL | ContainingLargeEnum(LargeEnum),
22-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 32004 bytes
2323
|
24-
note: and the second-largest variant is 8 bytes:
24+
note: and the second-largest variant contains at least 8 bytes:
2525
--> $DIR/large_enum_variant.rs:35:5
2626
|
2727
LL | VariantOk(i32, u32),
@@ -35,9 +35,9 @@ error: large size difference between variants
3535
--> $DIR/large_enum_variant.rs:40:5
3636
|
3737
LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
38-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 70004 bytes
3939
|
40-
note: and the second-largest variant is 8 bytes:
40+
note: and the second-largest variant contains at least 8 bytes:
4141
--> $DIR/large_enum_variant.rs:42:5
4242
|
4343
LL | StructLikeLittle { x: i32, y: i32 },
@@ -51,9 +51,9 @@ error: large size difference between variants
5151
--> $DIR/large_enum_variant.rs:47:5
5252
|
5353
LL | StructLikeLarge { x: [i32; 8000], y: i32 },
54-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 32004 bytes
5555
|
56-
note: and the second-largest variant is 8 bytes:
56+
note: and the second-largest variant contains at least 8 bytes:
5757
--> $DIR/large_enum_variant.rs:46:5
5858
|
5959
LL | VariantOk(i32, u32),
@@ -67,9 +67,9 @@ error: large size difference between variants
6767
--> $DIR/large_enum_variant.rs:52:5
6868
|
6969
LL | StructLikeLarge2 { x: [i32; 8000] },
70-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 32000 bytes
7171
|
72-
note: and the second-largest variant is 8 bytes:
72+
note: and the second-largest variant contains at least 8 bytes:
7373
--> $DIR/large_enum_variant.rs:51:5
7474
|
7575
LL | VariantOk(i32, u32),
@@ -83,9 +83,9 @@ error: large size difference between variants
8383
--> $DIR/large_enum_variant.rs:68:5
8484
|
8585
LL | B([u8; 1255]),
86-
| ^^^^^^^^^^^^^ this variant is 1255 bytes
86+
| ^^^^^^^^^^^^^ this variant contains at least 1255 bytes
8787
|
88-
note: and the second-largest variant is 200 bytes:
88+
note: and the second-largest variant contains at least 200 bytes:
8989
--> $DIR/large_enum_variant.rs:69:5
9090
|
9191
LL | C([u8; 200]),
@@ -99,9 +99,9 @@ error: large size difference between variants
9999
--> $DIR/large_enum_variant.rs:74:5
100100
|
101101
LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
102-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
102+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 70128 bytes
103103
|
104-
note: and the second-largest variant is 8 bytes:
104+
note: and the second-largest variant contains at least 8 bytes:
105105
--> $DIR/large_enum_variant.rs:73:5
106106
|
107107
LL | VariantOk(i32, u32),
@@ -115,9 +115,9 @@ error: large size difference between variants
115115
--> $DIR/large_enum_variant.rs:79:5
116116
|
117117
LL | B(Struct2),
118-
| ^^^^^^^^^^ this variant is 32000 bytes
118+
| ^^^^^^^^^^ this variant contains at least 32000 bytes
119119
|
120-
note: and the second-largest variant is 4 bytes:
120+
note: and the second-largest variant contains at least 4 bytes:
121121
--> $DIR/large_enum_variant.rs:78:5
122122
|
123123
LL | A(Struct<()>),
@@ -127,13 +127,45 @@ help: consider boxing the large fields to reduce the total size of the enum
127127
LL | B(Box<Struct2>),
128128
| ~~~~~~~~~~~~
129129

130+
error: large size difference between variants
131+
--> $DIR/large_enum_variant.rs:84:5
132+
|
133+
LL | B(Struct2),
134+
| ^^^^^^^^^^ this variant contains at least 32000 bytes
135+
|
136+
note: and the second-largest variant contains at least 0 bytes:
137+
--> $DIR/large_enum_variant.rs:83:5
138+
|
139+
LL | A(T),
140+
| ^^^^
141+
help: consider boxing the large fields to reduce the total size of the enum
142+
|
143+
LL | B(Box<Struct2>),
144+
| ~~~~~~~~~~~~
145+
146+
error: large size difference between variants
147+
--> $DIR/large_enum_variant.rs:89:5
148+
|
149+
LL | B(Struct2),
150+
| ^^^^^^^^^^ this variant contains at least 32000 bytes
151+
|
152+
note: and the second-largest variant contains at least 4 bytes:
153+
--> $DIR/large_enum_variant.rs:88:5
154+
|
155+
LL | A(Struct<T>),
156+
| ^^^^^^^^^^^^
157+
help: consider boxing the large fields to reduce the total size of the enum
158+
|
159+
LL | B(Box<Struct2>),
160+
| ~~~~~~~~~~~~
161+
130162
error: large size difference between variants
131163
--> $DIR/large_enum_variant.rs:104:5
132164
|
133165
LL | B([u128; 4000]),
134-
| ^^^^^^^^^^^^^^^ this variant is 64000 bytes
166+
| ^^^^^^^^^^^^^^^ this variant contains at least 64000 bytes
135167
|
136-
note: and the second-largest variant is 1 bytes:
168+
note: and the second-largest variant contains at least 1 bytes:
137169
--> $DIR/large_enum_variant.rs:103:5
138170
|
139171
LL | A(bool),
@@ -153,9 +185,9 @@ error: large size difference between variants
153185
--> $DIR/large_enum_variant.rs:109:5
154186
|
155187
LL | B([u128; 4000]),
156-
| ^^^^^^^^^^^^^^^ this variant is 64000 bytes
188+
| ^^^^^^^^^^^^^^^ this variant contains at least 64000 bytes
157189
|
158-
note: and the second-largest variant is 1 bytes:
190+
note: and the second-largest variant contains at least 1 bytes:
159191
--> $DIR/large_enum_variant.rs:108:5
160192
|
161193
LL | A(bool),
@@ -175,9 +207,9 @@ error: large size difference between variants
175207
--> $DIR/large_enum_variant.rs:122:5
176208
|
177209
LL | B([u64; 4000]),
178-
| ^^^^^^^^^^^^^^ this variant is 32000 bytes
210+
| ^^^^^^^^^^^^^^ this variant contains at least 32000 bytes
179211
|
180-
note: and the second-largest variant is 1 bytes:
212+
note: and the second-largest variant contains at least 1 bytes:
181213
--> $DIR/large_enum_variant.rs:121:5
182214
|
183215
LL | A(bool, std::marker::PhantomData<T>),
@@ -193,5 +225,53 @@ help: consider boxing the large fields to reduce the total size of the enum
193225
LL | B([u64; 4000]),
194226
| ^^^^^^^^^^^^^^
195227

196-
error: aborting due to 11 previous errors
228+
error: large size difference between variants
229+
--> $DIR/large_enum_variant.rs:135:5
230+
|
231+
LL | Large((T, [u8; 512])),
232+
| ^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 512 bytes
233+
|
234+
note: and the second-largest variant carries no data at all
235+
--> $DIR/large_enum_variant.rs:134:5
236+
|
237+
LL | Small,
238+
| ^^^^^
239+
help: consider boxing the large fields to reduce the total size of the enum
240+
|
241+
LL | Large(Box<(T, [u8; 512])>),
242+
| ~~~~~~~~~~~~~~~~~~~
243+
244+
error: large size difference between variants
245+
--> $DIR/large_enum_variant.rs:143:5
246+
|
247+
LL | Large([Foo<u64>; 64]),
248+
| ^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 512 bytes
249+
|
250+
note: and the second-largest variant contains at least 1 bytes:
251+
--> $DIR/large_enum_variant.rs:144:5
252+
|
253+
LL | Small(u8),
254+
| ^^^^^^^^^
255+
help: consider boxing the large fields to reduce the total size of the enum
256+
|
257+
LL | Large(Box<[Foo<u64>; 64]>),
258+
| ~~~~~~~~~~~~~~~~~~~
259+
260+
error: large size difference between variants
261+
--> $DIR/large_enum_variant.rs:154:5
262+
|
263+
LL | Error(PossiblyLargeEnumWithConst<256>),
264+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant contains at least 514 bytes
265+
|
266+
note: and the second-largest variant carries no data at all
267+
--> $DIR/large_enum_variant.rs:153:5
268+
|
269+
LL | Ok,
270+
| ^^
271+
help: consider boxing the large fields to reduce the total size of the enum
272+
|
273+
LL | Error(Box<PossiblyLargeEnumWithConst<256>>),
274+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
275+
276+
error: aborting due to 16 previous errors
197277

tests/ui/result_large_err.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::result_large_err)]
2+
#![allow(clippy::large_enum_variant)]
23

34
pub fn small_err() -> Result<(), u128> {
45
Ok(())

0 commit comments

Comments
 (0)