From c19daa472b69fdcbbb15402e8d1e8e05bae39f38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Sep 2022 22:56:01 +0200 Subject: make invalid_value lint a bit smarter around enums --- compiler/rustc_lint/src/builtin.rs | 160 ++++-- .../validate_uninhabited_zsts.32bit.stderr | 8 +- .../validate_uninhabited_zsts.64bit.stderr | 8 +- src/test/ui/lint/invalid_value.rs | 159 ++++++ src/test/ui/lint/invalid_value.stderr | 611 +++++++++++++++++++++ src/test/ui/lint/uninitialized-zeroed.rs | 137 ----- src/test/ui/lint/uninitialized-zeroed.stderr | 528 ------------------ src/test/ui/statics/uninhabited-static.stderr | 12 +- 8 files changed, 897 insertions(+), 726 deletions(-) create mode 100644 src/test/ui/lint/invalid_value.rs create mode 100644 src/test/ui/lint/invalid_value.stderr delete mode 100644 src/test/ui/lint/uninitialized-zeroed.rs delete mode 100644 src/test/ui/lint/uninitialized-zeroed.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5fba1d3d3c7..529e709c5db 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,56 @@ 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(ty: Ty<'_>) -> Option { + use rustc_type_ir::sty::TyKind::*; + 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>(tys: impl Iterator>) -> Option { + let mut definitely_inhabited = true; // with no fields, we are definitely inhabited. + for ty in tys { + match ty_inhabited(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 +2511,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 +2519,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 +2536,64 @@ 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( + 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/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index bdaeb4a0fbe..b568518b449 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 bdaeb4a0fbe..b568518b449 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/invalid_value.rs b/src/test/ui/lint/invalid_value.rs new file mode 100644 index 00000000000..c37a472ffe1 --- /dev/null +++ b/src/test/ui/lint/invalid_value.rs @@ -0,0 +1,159 @@ +// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results +// in a lint. + +#![feature(never_type, rustc_attrs)] +#![allow(deprecated)] +#![deny(invalid_value)] + +use std::mem::{self, MaybeUninit}; +use std::ptr::NonNull; +use std::num::NonZeroU32; + +enum Void {} + +struct Ref(&'static i32); +struct RefPair((&'static i32, i32)); + +struct Wrap { wrapped: T } +enum WrapEnum { Wrapped(T) } + +#[rustc_layout_scalar_valid_range_start(0)] +#[rustc_layout_scalar_valid_range_end(128)] +#[repr(transparent)] +pub(crate) struct NonBig(u64); + +/// A two-variant enum, thus needs a tag and may not remain uninitialized. +enum Fruit { + Apple, + Banana, +} + +/// Looks like two variants but really only has one. +enum OneFruit { + Apple(!), + Banana, +} + +enum OneFruitNonZero { + Apple(!), + Banana(NonZeroU32), +} + +enum TwoUninhabited { + A(!), + B(!), +} + +#[allow(unused)] +fn generic() { + unsafe { + let _val: &'static T = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: &'static T = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Wrap<&'static T> = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: Wrap<&'static T> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + } +} + +fn main() { + unsafe { + // Things that cannot even be zero. + let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: (i32, !) = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: (i32, !) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Void = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: Void = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Ref = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: Ref = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Wrap = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: Wrap = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: WrapEnum = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: WrapEnum = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Wrap<(RefPair, i32)> = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: NonNull = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: NonNull = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization + let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + 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 + + let _val: Wrap = mem::zeroed(); + let _val: Wrap = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: NonBig = mem::zeroed(); + let _val: NonBig = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: Fruit = mem::zeroed(); + let _val: Fruit = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: [bool; 2] = mem::zeroed(); + let _val: [bool; 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: i32 = mem::zeroed(); + let _val: i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: f32 = mem::zeroed(); + let _val: f32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + let _val: *const () = mem::zeroed(); + let _val: *const () = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized + + 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 + let _val: NonZeroU32 = mem::transmute(0); //~ ERROR: does not permit zero-initialization + + // `MaybeUninit` cases + let _val: NonNull = MaybeUninit::zeroed().assume_init(); //~ ERROR: does not permit zero-initialization + let _val: NonNull = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized + let _val: bool = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized + + // Some more types that should work just fine. + let _val: Option<&'static i32> = mem::zeroed(); + let _val: Option = mem::zeroed(); + let _val: MaybeUninit<&'static i32> = mem::zeroed(); + let _val: bool = MaybeUninit::zeroed().assume_init(); + let _val: [bool; 0] = MaybeUninit::uninit().assume_init(); + let _val: [!; 0] = MaybeUninit::zeroed().assume_init(); + } +} diff --git a/src/test/ui/lint/invalid_value.stderr b/src/test/ui/lint/invalid_value.stderr new file mode 100644 index 00000000000..750b3c76c44 --- /dev/null +++ b/src/test/ui/lint/invalid_value.stderr @@ -0,0 +1,611 @@ +error: the type `&T` does not permit zero-initialization + --> $DIR/invalid_value.rs:50:32 + | +LL | let _val: &'static T = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: the lint level is defined here + --> $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/invalid_value.rs:51:32 + | +LL | let _val: &'static T = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: references must be non-null + +error: the type `Wrap<&T>` does not permit zero-initialization + --> $DIR/invalid_value.rs:53:38 + | +LL | let _val: Wrap<&'static T> = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $DIR/invalid_value.rs:17:18 + | +LL | struct Wrap { wrapped: T } + | ^^^^^^^^^^ + +error: the type `Wrap<&T>` does not permit being left uninitialized + --> $DIR/invalid_value.rs:54:38 + | +LL | let _val: Wrap<&'static T> = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $DIR/invalid_value.rs:17:18 + | +LL | struct Wrap { wrapped: T } + | ^^^^^^^^^^ + +error: the type `!` does not permit zero-initialization + --> $DIR/invalid_value.rs:61:23 + | +LL | let _val: ! = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: the `!` type has no valid value + +error: the type `!` does not permit being left uninitialized + --> $DIR/invalid_value.rs:62:23 + | +LL | let _val: ! = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: the `!` type has no valid value + +error: the type `(i32, !)` does not permit zero-initialization + --> $DIR/invalid_value.rs:64:30 + | +LL | let _val: (i32, !) = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: the `!` type has no valid value + +error: the type `(i32, !)` does not permit being left uninitialized + --> $DIR/invalid_value.rs:65:30 + | +LL | let _val: (i32, !) = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: integers must not be uninitialized + +error: the type `Void` does not permit zero-initialization + --> $DIR/invalid_value.rs:67:26 + | +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 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/invalid_value.rs:68:26 + | +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 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/invalid_value.rs:70:34 + | +LL | let _val: &'static i32 = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: references must be non-null + +error: the type `&i32` does not permit being left uninitialized + --> $DIR/invalid_value.rs:71:34 + | +LL | let _val: &'static i32 = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: references must be non-null + +error: the type `Ref` does not permit zero-initialization + --> $DIR/invalid_value.rs:73:25 + | +LL | let _val: Ref = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $DIR/invalid_value.rs:14:12 + | +LL | struct Ref(&'static i32); + | ^^^^^^^^^^^^ + +error: the type `Ref` does not permit being left uninitialized + --> $DIR/invalid_value.rs:74:25 + | +LL | let _val: Ref = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $DIR/invalid_value.rs:14:12 + | +LL | struct Ref(&'static i32); + | ^^^^^^^^^^^^ + +error: the type `fn()` does not permit zero-initialization + --> $DIR/invalid_value.rs:76:26 + | +LL | let _val: fn() = 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 + +error: the type `fn()` does not permit being left uninitialized + --> $DIR/invalid_value.rs:77:26 + | +LL | let _val: fn() = 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 + +error: the type `Wrap` does not permit zero-initialization + --> $DIR/invalid_value.rs:79:32 + | +LL | let _val: Wrap = 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 struct field) + --> $DIR/invalid_value.rs:17:18 + | +LL | struct Wrap { wrapped: T } + | ^^^^^^^^^^ + +error: the type `Wrap` does not permit being left uninitialized + --> $DIR/invalid_value.rs:80:32 + | +LL | let _val: Wrap = 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 struct field) + --> $DIR/invalid_value.rs:17:18 + | +LL | struct Wrap { wrapped: T } + | ^^^^^^^^^^ + +error: the type `WrapEnum` does not permit zero-initialization + --> $DIR/invalid_value.rs:82:36 + | +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 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/invalid_value.rs:83:36 + | +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 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/invalid_value.rs:85:42 + | +LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $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/invalid_value.rs:86:42 + | +LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | +note: references must be non-null (in this struct field) + --> $DIR/invalid_value.rs:15:16 + | +LL | struct RefPair((&'static i32, i32)); + | ^^^^^^^^^^^^^^^^^^^ + +error: the type `NonNull` does not permit zero-initialization + --> $DIR/invalid_value.rs:88:34 + | +LL | let _val: NonNull = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `std::ptr::NonNull` must be non-null + +error: the type `NonNull` does not permit being left uninitialized + --> $DIR/invalid_value.rs:89:34 + | +LL | let _val: NonNull = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `std::ptr::NonNull` must be non-null + +error: the type `*const dyn Send` does not permit zero-initialization + --> $DIR/invalid_value.rs:91:37 + | +LL | let _val: *const dyn Send = mem::zeroed(); + | ^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = 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/invalid_value.rs:92:37 + | +LL | let _val: *const dyn Send = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: the vtable of a wide raw pointer must be non-null + +error: the type `[fn(); 2]` does not permit zero-initialization + --> $DIR/invalid_value.rs:94:31 + | +LL | let _val: [fn(); 2] = 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 + +error: the type `[fn(); 2]` does not permit being left uninitialized + --> $DIR/invalid_value.rs:95:31 + | +LL | let _val: [fn(); 2] = 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 + +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/invalid_value.rs:105:26 + | +LL | let _val: bool = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: booleans must be either `true` or `false` + +error: the type `Wrap` does not permit being left uninitialized + --> $DIR/invalid_value.rs:108:32 + | +LL | let _val: Wrap = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | 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/invalid_value.rs:17:18 + | +LL | struct Wrap { wrapped: T } + | ^^^^^^^^^^ + +error: the type `NonBig` does not permit being left uninitialized + --> $DIR/invalid_value.rs:111:28 + | +LL | let _val: NonBig = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `NonBig` must be initialized inside its custom valid range + +error: the type `Fruit` does not permit being left uninitialized + --> $DIR/invalid_value.rs:114:27 + | +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 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/invalid_value.rs:117:31 + | +LL | let _val: [bool; 2] = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: booleans must be either `true` or `false` + +error: the type `i32` does not permit being left uninitialized + --> $DIR/invalid_value.rs:120:25 + | +LL | let _val: i32 = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: integers must not be uninitialized + +error: the type `f32` does not permit being left uninitialized + --> $DIR/invalid_value.rs:123:25 + | +LL | let _val: f32 = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: floats must not be uninitialized + +error: the type `*const ()` does not permit being left uninitialized + --> $DIR/invalid_value.rs:126:31 + | +LL | let _val: *const () = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: raw pointers must not be uninitialized + +error: the type `*const [()]` does not permit being left uninitialized + --> $DIR/invalid_value.rs:129:33 + | +LL | let _val: *const [()] = mem::uninitialized(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = 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/invalid_value.rs:142:34 + | +LL | let _val: &'static i32 = mem::transmute(0usize); + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: references must be non-null + +error: the type `&[i32]` does not permit zero-initialization + --> $DIR/invalid_value.rs:143:36 + | +LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: references must be non-null + +error: the type `NonZeroU32` does not permit zero-initialization + --> $DIR/invalid_value.rs:144:32 + | +LL | let _val: NonZeroU32 = mem::transmute(0); + | ^^^^^^^^^^^^^^^^^ + | | + | 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 + +error: the type `NonNull` does not permit zero-initialization + --> $DIR/invalid_value.rs:147:34 + | +LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `std::ptr::NonNull` must be non-null + +error: the type `NonNull` does not permit being left uninitialized + --> $DIR/invalid_value.rs:148:34 + | +LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `std::ptr::NonNull` must be non-null + +error: the type `bool` does not permit being left uninitialized + --> $DIR/invalid_value.rs:149:26 + | +LL | let _val: bool = MaybeUninit::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: booleans must be either `true` or `false` + +error: aborting due to 48 previous errors + diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/uninitialized-zeroed.rs deleted file mode 100644 index dae258407eb..00000000000 --- a/src/test/ui/lint/uninitialized-zeroed.rs +++ /dev/null @@ -1,137 +0,0 @@ -// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results -// in a lint. - -#![feature(never_type, rustc_attrs)] -#![allow(deprecated)] -#![deny(invalid_value)] - -use std::mem::{self, MaybeUninit}; -use std::ptr::NonNull; -use std::num::NonZeroU32; - -enum Void {} - -struct Ref(&'static i32); -struct RefPair((&'static i32, i32)); - -struct Wrap { wrapped: T } -enum WrapEnum { Wrapped(T) } - -#[rustc_layout_scalar_valid_range_start(0)] -#[rustc_layout_scalar_valid_range_end(128)] -#[repr(transparent)] -pub(crate) struct NonBig(u64); - -/// A two-variant enum, thus needs a tag and may not remain uninitialized. -enum Fruit { - Apple, - Banana, -} - -/// Looks like two variants but really only has one. -enum OneFruit { - Apple(!), - Banana, -} - -#[allow(unused)] -fn generic() { - unsafe { - let _val: &'static T = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: &'static T = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Wrap<&'static T> = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: Wrap<&'static T> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - } -} - -fn main() { - unsafe { - // Things that cannot even be zero. - let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: (i32, !) = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: (i32, !) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Void = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: Void = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Ref = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: Ref = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Wrap = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: Wrap = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: WrapEnum = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: WrapEnum = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Wrap<(RefPair, i32)> = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: NonNull = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: NonNull = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization - let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - 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 - - // 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 - - let _val: Wrap = mem::zeroed(); - let _val: Wrap = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: NonBig = mem::zeroed(); - let _val: NonBig = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: Fruit = mem::zeroed(); - let _val: Fruit = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: [bool; 2] = mem::zeroed(); - let _val: [bool; 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: i32 = mem::zeroed(); - let _val: i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: f32 = mem::zeroed(); - let _val: f32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: *const () = mem::zeroed(); - let _val: *const () = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized - - let _val: *const [()] = mem::zeroed(); - let _val: *const [()] = mem::uninitialized(); //~ ERROR: does not permit being left 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 - let _val: NonZeroU32 = mem::transmute(0); //~ ERROR: does not permit zero-initialization - - // `MaybeUninit` cases - let _val: NonNull = MaybeUninit::zeroed().assume_init(); //~ ERROR: does not permit zero-initialization - let _val: NonNull = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized - let _val: bool = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized - - // Some more types that should work just fine. - let _val: Option<&'static i32> = mem::zeroed(); - let _val: Option = mem::zeroed(); - let _val: MaybeUninit<&'static i32> = mem::zeroed(); - 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/uninitialized-zeroed.stderr deleted file mode 100644 index b46042e7be4..00000000000 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ /dev/null @@ -1,528 +0,0 @@ -error: the type `&T` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:40:32 - | -LL | let _val: &'static T = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -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 - | -LL | let _val: &'static T = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: references must be non-null - -error: the type `Wrap<&T>` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:43:38 - | -LL | let _val: Wrap<&'static T> = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct Wrap { wrapped: T } - | ^^^^^^^^^^ - -error: the type `Wrap<&T>` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:44:38 - | -LL | let _val: Wrap<&'static T> = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct Wrap { wrapped: T } - | ^^^^^^^^^^ - -error: the type `!` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:51:23 - | -LL | let _val: ! = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: the `!` type has no valid value - -error: the type `!` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:52:23 - | -LL | let _val: ! = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: the `!` type has no valid value - -error: the type `(i32, !)` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:54:30 - | -LL | let _val: (i32, !) = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: the `!` type has no valid value - -error: the type `(i32, !)` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:55:30 - | -LL | let _val: (i32, !) = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: integers must not be uninitialized - -error: the type `Void` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:57:26 - | -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 - -error: the type `Void` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:58:26 - | -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 - -error: the type `&i32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:60:34 - | -LL | let _val: &'static i32 = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: references must be non-null - -error: the type `&i32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:61:34 - | -LL | let _val: &'static i32 = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: references must be non-null - -error: the type `Ref` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:63:25 - | -LL | let _val: Ref = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct Ref(&'static i32); - | ^^^^^^^^^^^^ - -error: the type `Ref` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:64:25 - | -LL | let _val: Ref = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct Ref(&'static i32); - | ^^^^^^^^^^^^ - -error: the type `fn()` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:66:26 - | -LL | let _val: fn() = 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 - -error: the type `fn()` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:67:26 - | -LL | let _val: fn() = 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 - -error: the type `Wrap` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:69:32 - | -LL | let _val: Wrap = 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 struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 - | -LL | struct Wrap { wrapped: T } - | ^^^^^^^^^^ - -error: the type `Wrap` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:70:32 - | -LL | let _val: Wrap = 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 struct field) - --> $DIR/uninitialized-zeroed.rs:17:18 - | -LL | struct Wrap { wrapped: T } - | ^^^^^^^^^^ - -error: the type `WrapEnum` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:72:36 - | -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 - | -LL | enum WrapEnum { Wrapped(T) } - | ^ - -error: the type `WrapEnum` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:73:36 - | -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 - | -LL | enum WrapEnum { Wrapped(T) } - | ^ - -error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:75:42 - | -LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct RefPair((&'static i32, i32)); - | ^^^^^^^^^^^^^^^^^^^ - -error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:76:42 - | -LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct RefPair((&'static i32, i32)); - | ^^^^^^^^^^^^^^^^^^^ - -error: the type `NonNull` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:78:34 - | -LL | let _val: NonNull = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `std::ptr::NonNull` must be non-null - -error: the type `NonNull` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:79:34 - | -LL | let _val: NonNull = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = 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 - | -LL | let _val: *const dyn Send = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = 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 - | -LL | let _val: *const dyn Send = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = 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 - | -LL | let _val: [fn(); 2] = 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 - -error: the type `[fn(); 2]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:85:31 - | -LL | let _val: [fn(); 2] = 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 - -error: the type `bool` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:89:26 - | -LL | let _val: bool = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: booleans must be either `true` or `false` - -error: the type `Wrap` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:92:32 - | -LL | let _val: Wrap = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | 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 - | -LL | struct Wrap { wrapped: T } - | ^^^^^^^^^^ - -error: the type `NonBig` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:95:28 - | -LL | let _val: NonBig = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = 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 - | -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 - | -LL | enum Fruit { - | ^^^^^^^^^^ - -error: the type `[bool; 2]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:101:31 - | -LL | let _val: [bool; 2] = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: booleans must be either `true` or `false` - -error: the type `i32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:104:25 - | -LL | let _val: i32 = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: integers must not be uninitialized - -error: the type `f32` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:107:25 - | -LL | let _val: f32 = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: floats must not be uninitialized - -error: the type `*const ()` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:110:31 - | -LL | let _val: *const () = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: raw pointers must not be uninitialized - -error: the type `*const [()]` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:113:33 - | -LL | let _val: *const [()] = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: raw pointers must not be uninitialized - -error: the type `&i32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:116:34 - | -LL | let _val: &'static i32 = mem::transmute(0usize); - | ^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: references must be non-null - -error: the type `&[i32]` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:117:36 - | -LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: references must be non-null - -error: the type `NonZeroU32` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:118:32 - | -LL | let _val: NonZeroU32 = mem::transmute(0); - | ^^^^^^^^^^^^^^^^^ - | | - | 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 - -error: the type `NonNull` does not permit zero-initialization - --> $DIR/uninitialized-zeroed.rs:121:34 - | -LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `std::ptr::NonNull` must be non-null - -error: the type `NonNull` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:122:34 - | -LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `std::ptr::NonNull` must be non-null - -error: the type `bool` does not permit being left uninitialized - --> $DIR/uninitialized-zeroed.rs:123:26 - | -LL | let _val: bool = MaybeUninit::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: booleans must be either `true` or `false` - -error: aborting due to 43 previous errors - diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr index 88ee4cbdc2e..6d37de8ff3f 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 -- cgit 1.4.1-3-g733a5