about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-03 07:34:42 +0000
committerbors <bors@rust-lang.org>2022-09-03 07:34:42 +0000
commit99ab5fe53a421e0ae3f1d922442fb994bcfcaf24 (patch)
tree2762c3ebb906c6f5761cf903545908a0e97bc164
parent30e453215380302b2cc1d4a7a41410e24482e50d (diff)
parent584000a792b1016677fe4e0e78706d14a8034eb2 (diff)
downloadrust-99ab5fe53a421e0ae3f1d922442fb994bcfcaf24.tar.gz
rust-99ab5fe53a421e0ae3f1d922442fb994bcfcaf24.zip
Auto merge of #9400 - lukaslueg:approx_large_enum, r=llogiq
Use `approx_ty_size` for `large_enum_variant`

This builds upon #9373 to use the approximate size of each variant for `large_enum_variant`. This allows us to lint in situations where an `enum` contains generics but is still guaranteed to have a large variant on an at-least basis, e.g. with `(T, [u8; 512])`.

* I've changed the wording from "is ... bytes" to "contains at least" because
  * the size is now an approximate lower bound (e.g. `512` in the example above). The actual size is larger due to `T`, including due to `T`'s memory layout.
  * the discriminant is not taken into account in the message. This comes up with variants like `A(T)`, which are "is at least 0 bytes" otherwise, which may be misleading.
* If the second-largest variant has no fields, there is a special case "carries no data" instead of "is at least 0 bytes".
* A variant like `A(T)` is "at least 0 bytes", which is technically true, yet we don't distinguish between "indeterminate" and truly "ZST".
* The generics-tests that were there before now lint while they didn't lint before. AFAICS this is correct.

I guess the above is correct-ish. However, I use the `SubstsRef` that I got via `cx.tcx.type_of(item.def_id)` to solve for generics in the variants. Is this even applicable, since we start from an - [ ] `ItemKind`?

changelog: none
-rw-r--r--clippy_lints/src/large_enum_variant.rs96
-rw-r--r--src/docs/large_enum_variant.txt7
-rw-r--r--tests/ui/large_enum_variant.rs24
-rw-r--r--tests/ui/large_enum_variant.stderr256
-rw-r--r--tests/ui/result_large_err.rs1
-rw-r--r--tests/ui/result_large_err.stderr22
6 files changed, 267 insertions, 139 deletions
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index c58df126d62..eb13d0869c0 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -1,13 +1,12 @@
 //! lint when there is a large size difference between variants on an enum
 
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
+use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{Adt, Ty};
+use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
@@ -17,7 +16,7 @@ declare_clippy_lint! {
     /// `enum`s.
     ///
     /// ### Why is this bad?
-    /// Enum size is bounded by the largest variant. Having a
+    /// Enum size is bounded by the largest variant. Having one
     /// large variant can penalize the memory layout of that enum.
     ///
     /// ### Known problems
@@ -33,8 +32,9 @@ declare_clippy_lint! {
     /// use case it may be possible to store the large data in an auxiliary
     /// structure (e.g. Arena or ECS).
     ///
-    /// The lint will ignore generic types if the layout depends on the
-    /// generics, even if the size difference will be large anyway.
+    /// The lint will ignore the impact of generic types to the type layout by
+    /// assuming every type parameter is zero-sized. Depending on your use case,
+    /// this may lead to a false positive.
     ///
     /// ### Example
     /// ```rust
@@ -83,6 +83,38 @@ struct VariantInfo {
     fields_size: Vec<FieldInfo>,
 }
 
+fn variants_size<'tcx>(
+    cx: &LateContext<'tcx>,
+    adt: AdtDef<'tcx>,
+    subst: &'tcx List<GenericArg<'tcx>>,
+) -> Vec<VariantInfo> {
+    let mut variants_size = adt
+        .variants()
+        .iter()
+        .enumerate()
+        .map(|(i, variant)| {
+            let mut fields_size = variant
+                .fields
+                .iter()
+                .enumerate()
+                .map(|(i, f)| FieldInfo {
+                    ind: i,
+                    size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
+                })
+                .collect::<Vec<_>>();
+            fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
+
+            VariantInfo {
+                ind: i,
+                size: fields_size.iter().map(|info| info.size).sum(),
+                fields_size,
+            }
+        })
+        .collect::<Vec<_>>();
+    variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+    variants_size
+}
+
 impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -92,36 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
-            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+            let (adt, subst) = match ty.kind() {
+                Adt(adt, subst) => (adt, subst),
+                _ => panic!("already checked whether this is an enum"),
+            };
             if adt.variants().len() <= 1 {
                 return;
             }
-            let mut variants_size: Vec<VariantInfo> = Vec::new();
-            for (i, variant) in adt.variants().iter().enumerate() {
-                let mut fields_size = Vec::new();
-                for (i, f) in variant.fields.iter().enumerate() {
-                    let ty = cx.tcx.type_of(f.did);
-                    // don't lint variants which have a field of generic type.
-                    match cx.layout_of(ty) {
-                        Ok(l) => {
-                            let fsize = l.size.bytes();
-                            fields_size.push(FieldInfo { ind: i, size: fsize });
-                        },
-                        Err(_) => {
-                            return;
-                        },
-                    }
-                }
-                let size: u64 = fields_size.iter().map(|info| info.size).sum();
-
-                variants_size.push(VariantInfo {
-                    ind: i,
-                    size,
-                    fields_size,
-                });
-            }
-
-            variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+            let variants_size = variants_size(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
             if difference > self.maximum_size_difference_allowed {
@@ -129,20 +139,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                 span_lint_and_then(
                     cx,
                     LARGE_ENUM_VARIANT,
-                    def.variants[variants_size[0].ind].span,
+                    item.span,
                     "large size difference between variants",
                     |diag| {
                         diag.span_label(
+                            item.span,
+                            format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)),
+                        );
+                        diag.span_label(
                             def.variants[variants_size[0].ind].span,
-                            &format!("this variant is {} bytes", variants_size[0].size),
+                            format!("the largest variant contains at least {} bytes", variants_size[0].size),
                         );
-                        diag.span_note(
+                        diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
+                            &if variants_size[1].fields_size.is_empty() {
+                                "the second-largest variant carries no data at all".to_owned()
+                            } else {
+                                format!(
+                                    "the second-largest variant contains at least {} bytes",
+                                    variants_size[1].size
+                                )
+                            },
                         );
 
                         let fields = def.variants[variants_size[0].ind].data.fields();
-                        variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
                         let mut applicability = Applicability::MaybeIncorrect;
                         if is_copy(cx, ty) || maybe_copy(cx, ty) {
                             diag.span_note(
diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt
index 787e8e027e1..1f95430790d 100644
--- a/src/docs/large_enum_variant.txt
+++ b/src/docs/large_enum_variant.txt
@@ -3,7 +3,7 @@ Checks for large size differences between variants on
 `enum`s.
 
 ### Why is this bad?
-Enum size is bounded by the largest variant. Having a
+Enum size is bounded by the largest variant. Having one
 large variant can penalize the memory layout of that enum.
 
 ### Known problems
@@ -19,8 +19,9 @@ still be `Clone`, but that is worse ergonomically. Depending on the
 use case it may be possible to store the large data in an auxiliary
 structure (e.g. Arena or ECS).
 
-The lint will ignore generic types if the layout depends on the
-generics, even if the size difference will be large anyway.
+The lint will ignore the impact of generic types to the type layout by
+assuming every type parameter is zero-sized. Depending on your use case,
+this may lead to a false positive.
 
 ### Example
 ```
diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs
index 23152a13322..717009e4c4c 100644
--- a/tests/ui/large_enum_variant.rs
+++ b/tests/ui/large_enum_variant.rs
@@ -130,6 +130,30 @@ impl<T: Copy> Clone for SomeGenericPossiblyCopyEnum<T> {
 
 impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
 
+enum LargeEnumWithGenerics<T> {
+    Small,
+    Large((T, [u8; 512])),
+}
+
+struct Foo<T> {
+    foo: T,
+}
+
+enum WithGenerics {
+    Large([Foo<u64>; 64]),
+    Small(u8),
+}
+
+enum PossiblyLargeEnumWithConst<const U: usize> {
+    SmallBuffer([u8; 4]),
+    MightyBuffer([u16; U]),
+}
+
+enum LargeEnumOfConst {
+    Ok,
+    Error(PossiblyLargeEnumWithConst<256>),
+}
+
 fn main() {
     large_enum_variant!();
 }
diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr
index 0248327262d..e1ed2460e08 100644
--- a/tests/ui/large_enum_variant.stderr
+++ b/tests/ui/large_enum_variant.stderr
@@ -1,143 +1,177 @@
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:12:5
+  --> $DIR/large_enum_variant.rs:10:1
    |
-LL |     B([i32; 8000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum {
+LL | |     A(i32),
+   | |     ------ the second-largest variant contains at least 4 bytes
+LL | |     B([i32; 8000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
    = note: `-D clippy::large-enum-variant` implied by `-D warnings`
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:11:5
-   |
-LL |     A(i32),
-   |     ^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[i32; 8000]>),
    |       ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:36:5
-   |
-LL |     ContainingLargeEnum(LargeEnum),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+  --> $DIR/large_enum_variant.rs:34:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:35:5
+LL | / enum LargeEnum2 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingLargeEnum(LargeEnum),
+   | |     ------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingLargeEnum(Box<LargeEnum>),
    |                         ~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:40:5
-   |
-LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
+  --> $DIR/large_enum_variant.rs:39:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:42:5
+LL | / enum LargeEnum3 {
+LL | |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+   | |     --------------------------------------------------------- the largest variant contains at least 70004 bytes
+LL | |     VoidVariant,
+LL | |     StructLikeLittle { x: i32, y: i32 },
+   | |     ----------------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+   | |_^ the entire enum is at least 70008 bytes
    |
-LL |     StructLikeLittle { x: i32, y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
    |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:47:5
+  --> $DIR/large_enum_variant.rs:45:1
    |
-LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+LL | / enum LargeEnum4 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   | |     ------------------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:46:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
    |                          ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:52:5
-   |
-LL |     StructLikeLarge2 { x: [i32; 8000] },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
+  --> $DIR/large_enum_variant.rs:50:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:51:5
+LL | / enum LargeEnum5 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge2 { x: [i32; 8000] },
+   | |     ----------------------------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
    |                           ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:68:5
-   |
-LL |     B([u8; 1255]),
-   |     ^^^^^^^^^^^^^ this variant is 1255 bytes
+  --> $DIR/large_enum_variant.rs:66:1
    |
-note: and the second-largest variant is 200 bytes:
-  --> $DIR/large_enum_variant.rs:69:5
+LL | / enum LargeEnum7 {
+LL | |     A,
+LL | |     B([u8; 1255]),
+   | |     ------------- the largest variant contains at least 1255 bytes
+LL | |     C([u8; 200]),
+   | |     ------------ the second-largest variant contains at least 200 bytes
+LL | | }
+   | |_^ the entire enum is at least 1256 bytes
    |
-LL |     C([u8; 200]),
-   |     ^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[u8; 1255]>),
    |       ~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:74:5
+  --> $DIR/large_enum_variant.rs:72:1
    |
-LL |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
+LL | / enum LargeEnum8 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
+   | |     ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes
+LL | | }
+   | |_^ the entire enum is at least 70132 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:73:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
    |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:79:5
+  --> $DIR/large_enum_variant.rs:77:1
+   |
+LL | / enum LargeEnum9 {
+LL | |     A(Struct<()>),
+   | |     ------------- the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
    |
-LL |     B(Struct2),
-   |     ^^^^^^^^^^ this variant is 32000 bytes
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:82:1
    |
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:78:5
+LL | / enum LargeEnumOk2<T> {
+LL | |     A(T),
+   | |     ---- the second-largest variant contains at least 0 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
    |
-LL |     A(Struct<()>),
-   |     ^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:104:5
+  --> $DIR/large_enum_variant.rs:87:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | / enum LargeEnumOk3<T> {
+LL | |     A(Struct<T>),
+   | |     ------------ the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
    |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:103:5
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:102:1
+   |
+LL | / enum CopyableLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:102:6
    |
@@ -150,16 +184,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:109:5
+  --> $DIR/large_enum_variant.rs:107:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
-   |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:108:5
+LL | / enum ManuallyCopyLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:107:6
    |
@@ -172,16 +206,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:122:5
+  --> $DIR/large_enum_variant.rs:120:1
    |
-LL |     B([u64; 4000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
-   |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:121:5
+LL | / enum SomeGenericPossiblyCopyEnum<T> {
+LL | |     A(bool, std::marker::PhantomData<T>),
+   | |     ------------------------------------ the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 4000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-LL |     A(bool, std::marker::PhantomData<T>),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:120:6
    |
@@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     B([u64; 4000]),
    |     ^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:133:1
+   |
+LL | / enum LargeEnumWithGenerics<T> {
+LL | |     Small,
+   | |     ----- the second-largest variant carries no data at all
+LL | |     Large((T, [u8; 512])),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | | }
+   | |_^ the entire enum is at least 512 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<(T, [u8; 512])>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:142:1
+   |
+LL | / enum WithGenerics {
+LL | |     Large([Foo<u64>; 64]),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | |     Small(u8),
+   | |     --------- the second-largest variant contains at least 1 bytes
+LL | | }
+   | |_^ the entire enum is at least 520 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[Foo<u64>; 64]>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:152:1
+   |
+LL | / enum LargeEnumOfConst {
+LL | |     Ok,
+   | |     -- the second-largest variant carries no data at all
+LL | |     Error(PossiblyLargeEnumWithConst<256>),
+   | |     -------------------------------------- the largest variant contains at least 514 bytes
+LL | | }
+   | |_^ the entire enum is at least 514 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs
index 78d8f76fe66..f7df3b85655 100644
--- a/tests/ui/result_large_err.rs
+++ b/tests/ui/result_large_err.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::result_large_err)]
+#![allow(clippy::large_enum_variant)]
 
 pub fn small_err() -> Result<(), u128> {
     Ok(())
diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr
index 0f1f39d72cb..ef19f2854ab 100644
--- a/tests/ui/result_large_err.stderr
+++ b/tests/ui/result_large_err.stderr
@@ -1,5 +1,5 @@
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:7:23
+  --> $DIR/result_large_err.rs:8:23
    |
 LL | pub fn large_err() -> Result<(), [u8; 512]> {
    |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -8,7 +8,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:18:21
+  --> $DIR/result_large_err.rs:19:21
    |
 LL |     pub fn ret() -> Result<(), Self> {
    |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -16,7 +16,7 @@ LL |     pub fn ret() -> Result<(), Self> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:23:26
+  --> $DIR/result_large_err.rs:24:26
    |
 LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -24,7 +24,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:28:45
+  --> $DIR/result_large_err.rs:29:45
    |
 LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -32,7 +32,7 @@ LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:36:34
+  --> $DIR/result_large_err.rs:37:34
    |
 LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
@@ -40,7 +40,7 @@ LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeErro
    = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:47:34
+  --> $DIR/result_large_err.rs:48:34
    |
 LL |     pub fn large_enum_error() -> Result<(), Self> {
    |                                  ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
@@ -48,7 +48,7 @@ LL |     pub fn large_enum_error() -> Result<(), Self> {
    = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:53:25
+  --> $DIR/result_large_err.rs:54:25
    |
 LL |     fn large_error() -> Result<(), [u8; 512]> {
    |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -56,7 +56,7 @@ LL |     fn large_error() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:72:29
+  --> $DIR/result_large_err.rs:73:29
    |
 LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -64,7 +64,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:81:40
+  --> $DIR/result_large_err.rs:82:40
    |
 LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -72,7 +72,7 @@ LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:90:34
+  --> $DIR/result_large_err.rs:91:34
    |
 LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
@@ -80,7 +80,7 @@ LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:94:31
+  --> $DIR/result_large_err.rs:95:31
    |
 LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes