@@ -1922,6 +1922,14 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
1922
1922
None
1923
1923
}
1924
1924
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
+
1925
1933
/// Return `Some` only if we are sure this type does *not*
1926
1934
/// allow zero initialization.
1927
1935
fn ty_find_init_error < ' tcx > (
@@ -1950,7 +1958,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
1950
1958
}
1951
1959
// Recurse and checks for some compound types.
1952
1960
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).
1954
1962
use std:: ops:: Bound ;
1955
1963
match tcx. layout_scalar_valid_range ( adt_def. did ) {
1956
1964
// We exploit here that `layout_scalar_valid_range` will never
@@ -2001,10 +2009,20 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2001
2009
)
2002
2010
} )
2003
2011
}
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
+ }
2008
2026
}
2009
2027
}
2010
2028
Tuple ( ..) => {
0 commit comments