@@ -1922,6 +1922,14 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
19221922 None
19231923 }
19241924
1925+ /// Test if this enum has several actually "existing" variants.
1926+ /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
1927+ fn is_multi_variant ( adt : & ty:: AdtDef ) -> bool {
1928+ // As an approximation, we only count dataless variants. Those are definitely inhabited.
1929+ let existing_variants = adt. variants . iter ( ) . filter ( |v| v. fields . is_empty ( ) ) . count ( ) ;
1930+ existing_variants > 1
1931+ }
1932+
19251933 /// Return `Some` only if we are sure this type does *not*
19261934 /// allow zero initialization.
19271935 fn ty_find_init_error < ' tcx > (
@@ -1950,7 +1958,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
19501958 }
19511959 // Recurse and checks for some compound types.
19521960 Adt ( adt_def, substs) if !adt_def. is_union ( ) => {
1953- // First check f this ADT has a layout attribute (like `NonNull` and friends).
1961+ // First check if this ADT has a layout attribute (like `NonNull` and friends).
19541962 use std:: ops:: Bound ;
19551963 match tcx. layout_scalar_valid_range ( adt_def. did ) {
19561964 // We exploit here that `layout_scalar_valid_range` will never
@@ -2001,10 +2009,20 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
20012009 )
20022010 } )
20032011 }
2004- // Multi-variant enums are tricky: if all but one variant are
2005- // uninhabited, we might actually do layout like for a single-variant
2006- // enum, and then even leaving them uninitialized could be okay.
2007- _ => None , // Conservative fallback for multi-variant enum.
2012+ // Multi-variant enum.
2013+ _ => {
2014+ if init == InitKind :: Uninit && is_multi_variant ( adt_def) {
2015+ let span = tcx. def_span ( adt_def. did ) ;
2016+ Some ( (
2017+ "enums have to be initialized to a variant" . to_string ( ) ,
2018+ Some ( span) ,
2019+ ) )
2020+ } else {
2021+ // In principle, for zero-initialization we could figure out which variant corresponds
2022+ // to tag 0, and check that... but for now we just accept all zero-initializations.
2023+ None
2024+ }
2025+ }
20082026 }
20092027 }
20102028 Tuple ( ..) => {
0 commit comments