diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5fba1d3d3c7ac..146c4971348ea 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -46,8 +46,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef}; use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; @@ -2425,12 +2424,63 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { None } - /// Test if this enum has several actually "existing" variants. - /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist". - fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool { - // As an approximation, we only count dataless variants. Those are definitely inhabited. - let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count(); - existing_variants > 1 + /// Determines whether the given type is inhabited. `None` means that we don't know. + fn ty_inhabited<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { + use rustc_type_ir::sty::TyKind::*; + if !cx.tcx.type_uninhabited_from(cx.param_env.and(ty)).is_empty() { + // This is definitely uninhabited from some module. + return Some(false); + } + match ty.kind() { + Never => Some(false), + Int(_) | Uint(_) | Float(_) | Bool | Char | RawPtr(_) => Some(true), + // Fallback for more complicated types. (Note that `&!` might be considered + // uninhabited so references are "complicated", too.) + _ => None, + } + } + /// Determines whether a product type formed from a list of types is inhabited. + fn tys_inhabited<'tcx>( + cx: &LateContext<'tcx>, + tys: impl Iterator>, + ) -> Option { + let mut definitely_inhabited = true; // with no fields, we are definitely inhabited. + for ty in tys { + match ty_inhabited(cx, ty) { + // If any type is uninhabited, the product is uninhabited. + Some(false) => return Some(false), + // Otherwise go searching for a `None`. + None => { + // We don't know. + definitely_inhabited = false; + } + Some(true) => {} + } + } + if definitely_inhabited { Some(true) } else { None } + } + + fn variant_find_init_error<'tcx>( + cx: &LateContext<'tcx>, + variant: &VariantDef, + substs: ty::SubstsRef<'tcx>, + descr: &str, + init: InitKind, + ) -> Option { + variant.fields.iter().find_map(|field| { + ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|(mut msg, span)| { + if span.is_none() { + // Point to this field, should be helpful for figuring + // out where the source of the error is. + let span = cx.tcx.def_span(field.did); + write!(&mut msg, " (in this {descr})").unwrap(); + (msg, Some(span)) + } else { + // Just forward. + (msg, span) + } + }) + }) } /// Return `Some` only if we are sure this type does *not* @@ -2468,7 +2518,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { RawPtr(_) if init == InitKind::Uninit => { Some(("raw pointers must not be uninitialized".to_string(), None)) } - // Recurse and checks for some compound types. + // Recurse and checks for some compound types. (but not unions) Adt(adt_def, substs) if !adt_def.is_union() => { // First check if this ADT has a layout attribute (like `NonNull` and friends). use std::ops::Bound; @@ -2476,6 +2526,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // We exploit here that `layout_scalar_valid_range` will never // return `Bound::Excluded`. (And we have tests checking that we // handle the attribute correctly.) + // We don't add a span since users cannot declare such types anyway. (Bound::Included(lo), _) if lo > 0 => { return Some((format!("`{}` must be non-null", ty), None)); } @@ -2492,50 +2543,65 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { } _ => {} } - // Now, recurse. - match adt_def.variants().len() { - 0 => Some(("enums with no variants have no valid value".to_string(), None)), - 1 => { - // Struct, or enum with exactly one variant. - // Proceed recursively, check all fields. - let variant = &adt_def.variant(VariantIdx::from_u32(0)); - variant.fields.iter().find_map(|field| { - ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map( - |(mut msg, span)| { - if span.is_none() { - // Point to this field, should be helpful for figuring - // out where the source of the error is. - let span = cx.tcx.def_span(field.did); - write!( - &mut msg, - " (in this {} field)", - adt_def.descr() - ) - .unwrap(); - (msg, Some(span)) - } else { - // Just forward. - (msg, span) - } - }, - ) - }) - } - // Multi-variant enum. - _ => { - if init == InitKind::Uninit && is_multi_variant(*adt_def) { - let span = cx.tcx.def_span(adt_def.did()); - Some(( - "enums have to be initialized to a variant".to_string(), - Some(span), - )) - } else { - // In principle, for zero-initialization we could figure out which variant corresponds - // to tag 0, and check that... but for now we just accept all zero-initializations. - None - } + // Handle structs. + if adt_def.is_struct() { + return variant_find_init_error( + cx, + adt_def.non_enum_variant(), + substs, + "struct field", + init, + ); + } + // And now, enums. + let span = cx.tcx.def_span(adt_def.did()); + let mut potential_variants = adt_def.variants().iter().filter_map(|variant| { + let inhabited = tys_inhabited( + cx, + variant.fields.iter().map(|field| field.ty(cx.tcx, substs)), + ); + let definitely_inhabited = match inhabited { + // Entirely skip uninhbaited variants. + Some(false) => return None, + // Forward the others, but remember which ones are definitely inhabited. + Some(true) => true, + None => false, + }; + Some((variant, definitely_inhabited)) + }); + let Some(first_variant) = potential_variants.next() else { + return Some(("enums with no inhabited variants have no valid value".to_string(), Some(span))); + }; + // So we have at least one potentially inhabited variant. Might we have two? + let Some(second_variant) = potential_variants.next() else { + // There is only one potentially inhabited variant. So we can recursively check that variant! + return variant_find_init_error( + cx, + &first_variant.0, + substs, + "field of the only potentially inhabited enum variant", + init, + ); + }; + // So we have at least two potentially inhabited variants. + // If we can prove that we have at least two *definitely* inhabited variants, + // then we have a tag and hence leaving this uninit is definitely disallowed. + // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.) + if init == InitKind::Uninit { + let definitely_inhabited = (first_variant.1 as usize) + + (second_variant.1 as usize) + + potential_variants + .filter(|(_variant, definitely_inhabited)| *definitely_inhabited) + .count(); + if definitely_inhabited > 1 { + return Some(( + "enums with multiple inhabited variants have to be initialized to a variant".to_string(), + Some(span), + )); } } + // We couldn't find anything wrong here. + None } Tuple(..) => { // Proceed recursively, check all fields. diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr index 752fd01f33805..80395e32db0ca 100644 --- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:23:1 + --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error: any use of this value will cause an error - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -22,7 +22,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error: any use of this value will cause an error - --> $DIR/ub-enum.rs:30:1 + --> $DIR/ub-enum.rs:31:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -33,7 +33,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag @@ -44,7 +44,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error: any use of this value will cause an error - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -55,7 +55,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error: any use of this value will cause an error - --> $DIR/ub-enum.rs:49:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -66,13 +66,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:59:42 + --> $DIR/ub-enum.rs:60:42 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error: any use of this value will cause an error - --> $DIR/ub-enum.rs:64:1 + --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -83,7 +83,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:82:1 + --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a value of the never type `!` @@ -94,7 +94,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:84:1 + --> $DIR/ub-enum.rs:85:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a value of uninhabited type Never @@ -105,7 +105,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:92:1 + --> $DIR/ub-enum.rs:93:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -116,13 +116,13 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:97:77 + --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:99:77 + --> $DIR/ub-enum.rs:100:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type @@ -132,7 +132,7 @@ error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -145,7 +145,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:30:1 + --> $DIR/ub-enum.rs:31:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -158,7 +158,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -171,7 +171,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:49:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -184,7 +184,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:64:1 + --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr index 3f1546a2786ca..d20f63a728994 100644 --- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:23:1 + --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error: any use of this value will cause an error - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -22,7 +22,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error: any use of this value will cause an error - --> $DIR/ub-enum.rs:30:1 + --> $DIR/ub-enum.rs:31:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -33,7 +33,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag @@ -44,7 +44,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error: any use of this value will cause an error - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -55,7 +55,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error: any use of this value will cause an error - --> $DIR/ub-enum.rs:49:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -66,13 +66,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:59:42 + --> $DIR/ub-enum.rs:60:42 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error: any use of this value will cause an error - --> $DIR/ub-enum.rs:64:1 + --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -83,7 +83,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:82:1 + --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a value of the never type `!` @@ -94,7 +94,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:84:1 + --> $DIR/ub-enum.rs:85:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a value of uninhabited type Never @@ -105,7 +105,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:92:1 + --> $DIR/ub-enum.rs:93:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -116,13 +116,13 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:97:77 + --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type error[E0080]: evaluation of constant value failed - --> $DIR/ub-enum.rs:99:77 + --> $DIR/ub-enum.rs:100:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type @@ -132,7 +132,7 @@ error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:26:1 + --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -145,7 +145,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:30:1 + --> $DIR/ub-enum.rs:31:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -158,7 +158,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -171,7 +171,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:49:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -184,7 +184,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; Future breakage diagnostic: error: any use of this value will cause an error - --> $DIR/ub-enum.rs:64:1 + --> $DIR/ub-enum.rs:65:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index d8dc6d057a73d..9e1c28e2351a8 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,5 +1,6 @@ // stderr-per-bitwidth #![feature(never_type)] +#![allow(invalid_value)] use std::mem; diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index bdaeb4a0fbee0..b568518b4499d 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -40,11 +40,11 @@ LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | -note: enums with no variants have no valid value (in this struct field) - --> $DIR/validate_uninhabited_zsts.rs:16:22 +note: enums with no inhabited variants have no valid value + --> $DIR/validate_uninhabited_zsts.rs:13:5 | -LL | pub struct Empty(Void); - | ^^^^ +LL | enum Void {} + | ^^^^^^^^^ error: aborting due to 2 previous errors; 2 warnings emitted diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index bdaeb4a0fbee0..b568518b4499d 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -40,11 +40,11 @@ LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | -note: enums with no variants have no valid value (in this struct field) - --> $DIR/validate_uninhabited_zsts.rs:16:22 +note: enums with no inhabited variants have no valid value + --> $DIR/validate_uninhabited_zsts.rs:13:5 | -LL | pub struct Empty(Void); - | ^^^^ +LL | enum Void {} + | ^^^^^^^^^ error: aborting due to 2 previous errors; 2 warnings emitted diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/invalid_value.rs similarity index 88% rename from src/test/ui/lint/uninitialized-zeroed.rs rename to src/test/ui/lint/invalid_value.rs index dae258407ebb0..51edb2b7baf59 100644 --- a/src/test/ui/lint/uninitialized-zeroed.rs +++ b/src/test/ui/lint/invalid_value.rs @@ -34,6 +34,16 @@ enum OneFruit { Banana, } +enum OneFruitNonZero { + Apple(!), + Banana(NonZeroU32), +} + +enum TwoUninhabited { + A(!), + B(Void), +} + #[allow(unused)] fn generic() { unsafe { @@ -84,6 +94,12 @@ fn main() { let _val: [fn(); 2] = mem::zeroed(); //~ ERROR: does not permit zero-initialization let _val: [fn(); 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + let _val: TwoUninhabited = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: TwoUninhabited = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: OneFruitNonZero = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: OneFruitNonZero = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + // Things that can be zero, but not uninit. let _val: bool = mem::zeroed(); let _val: bool = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized @@ -112,6 +128,16 @@ fn main() { let _val: *const [()] = mem::zeroed(); let _val: *const [()] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + // Things where 0 is okay due to rustc implementation details, + // but that are not guaranteed to keep working. + let _val: Result = mem::zeroed(); + let _val: Result = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + // Some things that happen to work due to rustc implementation details, + // but are not guaranteed to keep working. + let _val: OneFruit = mem::zeroed(); + let _val: OneFruit = mem::uninitialized(); + // Transmute-from-0 let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization @@ -129,9 +155,5 @@ fn main() { let _val: bool = MaybeUninit::zeroed().assume_init(); let _val: [bool; 0] = MaybeUninit::uninit().assume_init(); let _val: [!; 0] = MaybeUninit::zeroed().assume_init(); - - // Some things that happen to work due to rustc implementation details, - // but are not guaranteed to keep working. - let _val: OneFruit = mem::uninitialized(); } } diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/invalid_value.stderr similarity index 78% rename from src/test/ui/lint/uninitialized-zeroed.stderr rename to src/test/ui/lint/invalid_value.stderr index b46042e7be43f..750b3c76c44c2 100644 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ b/src/test/ui/lint/invalid_value.stderr @@ -1,5 +1,5 @@ error: the type `&T` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:40:32 + --> $DIR/invalid_value.rs:50:32 | LL | let _val: &'static T = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -8,14 +8,14 @@ LL | let _val: &'static T = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: the lint level is defined here - --> $DIR/uninitialized-zeroed.rs:6:9 + --> $DIR/invalid_value.rs:6:9 | LL | #![deny(invalid_value)] | ^^^^^^^^^^^^^ = note: references must be non-null error: the type `&T` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:41:32 + --> $DIR/invalid_value.rs:51:32 | LL | let _val: &'static T = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let _val: &'static T = mem::uninitialized(); = note: references must be non-null error: the type `Wrap<&T>` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:43:38 + --> $DIR/invalid_value.rs:53:38 | LL | let _val: Wrap<&'static T> = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -35,13 +35,13 @@ LL | let _val: Wrap<&'static T> = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 + --> $DIR/invalid_value.rs:17:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `Wrap<&T>` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:44:38 + --> $DIR/invalid_value.rs:54:38 | LL | let _val: Wrap<&'static T> = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -50,13 +50,13 @@ LL | let _val: Wrap<&'static T> = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 + --> $DIR/invalid_value.rs:17:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `!` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:51:23 + --> $DIR/invalid_value.rs:61:23 | LL | let _val: ! = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | let _val: ! = mem::zeroed(); = note: the `!` type has no valid value error: the type `!` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:52:23 + --> $DIR/invalid_value.rs:62:23 | LL | let _val: ! = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -78,7 +78,7 @@ LL | let _val: ! = mem::uninitialized(); = note: the `!` type has no valid value error: the type `(i32, !)` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:54:30 + --> $DIR/invalid_value.rs:64:30 | LL | let _val: (i32, !) = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _val: (i32, !) = mem::zeroed(); = note: the `!` type has no valid value error: the type `(i32, !)` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:55:30 + --> $DIR/invalid_value.rs:65:30 | LL | let _val: (i32, !) = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | let _val: (i32, !) = mem::uninitialized(); = note: integers must not be uninitialized error: the type `Void` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:57:26 + --> $DIR/invalid_value.rs:67:26 | LL | let _val: Void = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -108,10 +108,14 @@ LL | let _val: Void = mem::zeroed(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: enums with no variants have no valid value +note: enums with no inhabited variants have no valid value + --> $DIR/invalid_value.rs:12:1 + | +LL | enum Void {} + | ^^^^^^^^^ error: the type `Void` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:58:26 + --> $DIR/invalid_value.rs:68:26 | LL | let _val: Void = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -119,10 +123,14 @@ LL | let _val: Void = mem::uninitialized(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: enums with no variants have no valid value +note: enums with no inhabited variants have no valid value + --> $DIR/invalid_value.rs:12:1 + | +LL | enum Void {} + | ^^^^^^^^^ error: the type `&i32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:60:34 + --> $DIR/invalid_value.rs:70:34 | LL | let _val: &'static i32 = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -133,7 +141,7 @@ LL | let _val: &'static i32 = mem::zeroed(); = note: references must be non-null error: the type `&i32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:61:34 + --> $DIR/invalid_value.rs:71:34 | LL | let _val: &'static i32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +152,7 @@ LL | let _val: &'static i32 = mem::uninitialized(); = note: references must be non-null error: the type `Ref` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:63:25 + --> $DIR/invalid_value.rs:73:25 | LL | let _val: Ref = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -153,13 +161,13 @@ LL | let _val: Ref = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:14:12 + --> $DIR/invalid_value.rs:14:12 | LL | struct Ref(&'static i32); | ^^^^^^^^^^^^ error: the type `Ref` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:64:25 + --> $DIR/invalid_value.rs:74:25 | LL | let _val: Ref = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -168,13 +176,13 @@ LL | let _val: Ref = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:14:12 + --> $DIR/invalid_value.rs:14:12 | LL | struct Ref(&'static i32); | ^^^^^^^^^^^^ error: the type `fn()` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:66:26 + --> $DIR/invalid_value.rs:76:26 | LL | let _val: fn() = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -185,7 +193,7 @@ LL | let _val: fn() = mem::zeroed(); = note: function pointers must be non-null error: the type `fn()` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:67:26 + --> $DIR/invalid_value.rs:77:26 | LL | let _val: fn() = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +204,7 @@ LL | let _val: fn() = mem::uninitialized(); = note: function pointers must be non-null error: the type `Wrap` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:69:32 + --> $DIR/invalid_value.rs:79:32 | LL | let _val: Wrap = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -205,13 +213,13 @@ LL | let _val: Wrap = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: function pointers must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 + --> $DIR/invalid_value.rs:17:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `Wrap` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:70:32 + --> $DIR/invalid_value.rs:80:32 | LL | let _val: Wrap = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -220,13 +228,13 @@ LL | let _val: Wrap = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: function pointers must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 + --> $DIR/invalid_value.rs:17:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `WrapEnum` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:72:36 + --> $DIR/invalid_value.rs:82:36 | LL | let _val: WrapEnum = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -234,14 +242,14 @@ LL | let _val: WrapEnum = mem::zeroed(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | -note: function pointers must be non-null (in this enum field) - --> $DIR/uninitialized-zeroed.rs:18:28 +note: function pointers must be non-null (in this field of the only potentially inhabited enum variant) + --> $DIR/invalid_value.rs:18:28 | LL | enum WrapEnum { Wrapped(T) } | ^ error: the type `WrapEnum` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:73:36 + --> $DIR/invalid_value.rs:83:36 | LL | let _val: WrapEnum = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -249,14 +257,14 @@ LL | let _val: WrapEnum = mem::uninitialized(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | -note: function pointers must be non-null (in this enum field) - --> $DIR/uninitialized-zeroed.rs:18:28 +note: function pointers must be non-null (in this field of the only potentially inhabited enum variant) + --> $DIR/invalid_value.rs:18:28 | LL | enum WrapEnum { Wrapped(T) } | ^ error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:75:42 + --> $DIR/invalid_value.rs:85:42 | LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -265,13 +273,13 @@ LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:15:16 + --> $DIR/invalid_value.rs:15:16 | LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:76:42 + --> $DIR/invalid_value.rs:86:42 | LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -280,13 +288,13 @@ LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: references must be non-null (in this struct field) - --> $DIR/uninitialized-zeroed.rs:15:16 + --> $DIR/invalid_value.rs:15:16 | LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ error: the type `NonNull` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:78:34 + --> $DIR/invalid_value.rs:88:34 | LL | let _val: NonNull = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -297,7 +305,7 @@ LL | let _val: NonNull = mem::zeroed(); = note: `std::ptr::NonNull` must be non-null error: the type `NonNull` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:79:34 + --> $DIR/invalid_value.rs:89:34 | LL | let _val: NonNull = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -308,7 +316,7 @@ LL | let _val: NonNull = mem::uninitialized(); = note: `std::ptr::NonNull` must be non-null error: the type `*const dyn Send` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:81:37 + --> $DIR/invalid_value.rs:91:37 | LL | let _val: *const dyn Send = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -319,7 +327,7 @@ LL | let _val: *const dyn Send = mem::zeroed(); = note: the vtable of a wide raw pointer must be non-null error: the type `*const dyn Send` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:82:37 + --> $DIR/invalid_value.rs:92:37 | LL | let _val: *const dyn Send = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -330,7 +338,7 @@ LL | let _val: *const dyn Send = mem::uninitialized(); = note: the vtable of a wide raw pointer must be non-null error: the type `[fn(); 2]` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:84:31 + --> $DIR/invalid_value.rs:94:31 | LL | let _val: [fn(); 2] = mem::zeroed(); | ^^^^^^^^^^^^^ @@ -341,7 +349,7 @@ LL | let _val: [fn(); 2] = mem::zeroed(); = note: function pointers must be non-null error: the type `[fn(); 2]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:85:31 + --> $DIR/invalid_value.rs:95:31 | LL | let _val: [fn(); 2] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -351,8 +359,68 @@ LL | let _val: [fn(); 2] = mem::uninitialized(); | = note: function pointers must be non-null +error: the type `TwoUninhabited` does not permit zero-initialization + --> $DIR/invalid_value.rs:97:36 + | +LL | let _val: TwoUninhabited = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: enums with no inhabited variants have no valid value + --> $DIR/invalid_value.rs:42:1 + | +LL | enum TwoUninhabited { + | ^^^^^^^^^^^^^^^^^^^ + +error: the type `TwoUninhabited` does not permit being left uninitialized + --> $DIR/invalid_value.rs:98:36 + | +LL | let _val: TwoUninhabited = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: enums with no inhabited variants have no valid value + --> $DIR/invalid_value.rs:42:1 + | +LL | enum TwoUninhabited { + | ^^^^^^^^^^^^^^^^^^^ + +error: the type `OneFruitNonZero` does not permit zero-initialization + --> $DIR/invalid_value.rs:100:37 + | +LL | let _val: OneFruitNonZero = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) + --> $DIR/invalid_value.rs:39:12 + | +LL | Banana(NonZeroU32), + | ^^^^^^^^^^ + +error: the type `OneFruitNonZero` does not permit being left uninitialized + --> $DIR/invalid_value.rs:101:37 + | +LL | let _val: OneFruitNonZero = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant) + --> $DIR/invalid_value.rs:39:12 + | +LL | Banana(NonZeroU32), + | ^^^^^^^^^^ + error: the type `bool` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:89:26 + --> $DIR/invalid_value.rs:105:26 | LL | let _val: bool = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -363,7 +431,7 @@ LL | let _val: bool = mem::uninitialized(); = note: booleans must be either `true` or `false` error: the type `Wrap` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:92:32 + --> $DIR/invalid_value.rs:108:32 | LL | let _val: Wrap = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -372,13 +440,13 @@ LL | let _val: Wrap = mem::uninitialized(); | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | note: characters must be a valid Unicode codepoint (in this struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 + --> $DIR/invalid_value.rs:17:18 | LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ error: the type `NonBig` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:95:28 + --> $DIR/invalid_value.rs:111:28 | LL | let _val: NonBig = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -389,7 +457,7 @@ LL | let _val: NonBig = mem::uninitialized(); = note: `NonBig` must be initialized inside its custom valid range error: the type `Fruit` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:98:27 + --> $DIR/invalid_value.rs:114:27 | LL | let _val: Fruit = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -397,14 +465,14 @@ LL | let _val: Fruit = mem::uninitialized(); | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | -note: enums have to be initialized to a variant - --> $DIR/uninitialized-zeroed.rs:26:1 +note: enums with multiple inhabited variants have to be initialized to a variant + --> $DIR/invalid_value.rs:26:1 | LL | enum Fruit { | ^^^^^^^^^^ error: the type `[bool; 2]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:101:31 + --> $DIR/invalid_value.rs:117:31 | LL | let _val: [bool; 2] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -415,7 +483,7 @@ LL | let _val: [bool; 2] = mem::uninitialized(); = note: booleans must be either `true` or `false` error: the type `i32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:104:25 + --> $DIR/invalid_value.rs:120:25 | LL | let _val: i32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -426,7 +494,7 @@ LL | let _val: i32 = mem::uninitialized(); = note: integers must not be uninitialized error: the type `f32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:107:25 + --> $DIR/invalid_value.rs:123:25 | LL | let _val: f32 = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -437,7 +505,7 @@ LL | let _val: f32 = mem::uninitialized(); = note: floats must not be uninitialized error: the type `*const ()` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:110:31 + --> $DIR/invalid_value.rs:126:31 | LL | let _val: *const () = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -448,7 +516,7 @@ LL | let _val: *const () = mem::uninitialized(); = note: raw pointers must not be uninitialized error: the type `*const [()]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:113:33 + --> $DIR/invalid_value.rs:129:33 | LL | let _val: *const [()] = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ @@ -458,8 +526,23 @@ LL | let _val: *const [()] = mem::uninitialized(); | = note: raw pointers must not be uninitialized +error: the type `Result` does not permit being left uninitialized + --> $DIR/invalid_value.rs:134:38 + | +LL | let _val: Result = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: enums with multiple inhabited variants have to be initialized to a variant + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | pub enum Result { + | ^^^^^^^^^^^^^^^^^^^^^ + error: the type `&i32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:116:34 + --> $DIR/invalid_value.rs:142:34 | LL | let _val: &'static i32 = mem::transmute(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -470,7 +553,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize); = note: references must be non-null error: the type `&[i32]` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:117:36 + --> $DIR/invalid_value.rs:143:36 | LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +564,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); = note: references must be non-null error: the type `NonZeroU32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:118:32 + --> $DIR/invalid_value.rs:144:32 | LL | let _val: NonZeroU32 = mem::transmute(0); | ^^^^^^^^^^^^^^^^^ @@ -492,7 +575,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0); = note: `std::num::NonZeroU32` must be non-null error: the type `NonNull` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:121:34 + --> $DIR/invalid_value.rs:147:34 | LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -503,7 +586,7 @@ LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); = note: `std::ptr::NonNull` must be non-null error: the type `NonNull` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:122:34 + --> $DIR/invalid_value.rs:148:34 | LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,7 +597,7 @@ LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); = note: `std::ptr::NonNull` must be non-null error: the type `bool` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:123:26 + --> $DIR/invalid_value.rs:149:26 | LL | let _val: bool = MaybeUninit::uninit().assume_init(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -524,5 +607,5 @@ LL | let _val: bool = MaybeUninit::uninit().assume_init(); | = note: booleans must be either `true` or `false` -error: aborting due to 43 previous errors +error: aborting due to 48 previous errors diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr index 88ee4cbdc2efc..6d37de8ff3f68 100644 --- a/src/test/ui/statics/uninhabited-static.stderr +++ b/src/test/ui/statics/uninhabited-static.stderr @@ -59,7 +59,11 @@ LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | = note: `#[warn(invalid_value)]` on by default - = note: enums with no variants have no valid value +note: enums with no inhabited variants have no valid value + --> $DIR/uninhabited-static.rs:4:1 + | +LL | enum Void {} + | ^^^^^^^^^ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:16:32 @@ -76,7 +80,11 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | this code causes undefined behavior when executed | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done | - = note: enums with no variants have no valid value +note: enums with no inhabited variants have no valid value + --> $DIR/uninhabited-static.rs:4:1 + | +LL | enum Void {} + | ^^^^^^^^^ error: aborting due to 6 previous errors; 2 warnings emitted