mirror of https://github.com/rust-lang/rust.git
warn for more cases
This commit is contained in:
parent
da6fbb1895
commit
ca1e94b131
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
use rustc::hir::def::{Res, DefKind};
|
use rustc::hir::def::{Res, DefKind};
|
||||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx};
|
||||||
use rustc::{lint, util};
|
use rustc::{lint, util};
|
||||||
use hir::Node;
|
use hir::Node;
|
||||||
use util::nodemap::HirIdSet;
|
use util::nodemap::HirIdSet;
|
||||||
|
@ -1879,11 +1879,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||||
|
|
||||||
/// Return `false` only if we are sure this type does *not*
|
/// Return `false` only if we are sure this type does *not*
|
||||||
/// allow zero initialization.
|
/// allow zero initialization.
|
||||||
fn ty_maybe_allows_zero_init(ty: Ty<'_>) -> bool {
|
fn ty_maybe_allows_zero_init<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
use rustc::ty::TyKind::*;
|
use rustc::ty::TyKind::*;
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
// Primitive types that don't like 0 as a value.
|
// Primitive types that don't like 0 as a value.
|
||||||
Ref(..) | FnPtr(..) | Never => false,
|
Ref(..) | FnPtr(..) | Never => false,
|
||||||
|
Adt(..) if ty.is_box() => false,
|
||||||
|
// Recurse for some compound types.
|
||||||
|
Adt(adt_def, substs) if !adt_def.is_union() => {
|
||||||
|
match adt_def.variants.len() {
|
||||||
|
0 => false, // Uninhabited enum!
|
||||||
|
1 => {
|
||||||
|
// Struct, or enum with exactly one variant.
|
||||||
|
// Proceed recursively, check all fields.
|
||||||
|
let variant = &adt_def.variants[VariantIdx::from_u32(0)];
|
||||||
|
variant.fields.iter().all(|field| {
|
||||||
|
ty_maybe_allows_zero_init(
|
||||||
|
tcx,
|
||||||
|
field.ty(tcx, substs),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => true, // Conservative fallback for multi-variant enum.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tuple(substs) => {
|
||||||
|
// Proceed recursively, check all fields.
|
||||||
|
substs.iter().all(|field| {
|
||||||
|
ty_maybe_allows_zero_init(
|
||||||
|
tcx,
|
||||||
|
field.expect_ty(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
|
||||||
// Conservative fallback.
|
// Conservative fallback.
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
|
@ -1900,8 +1929,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||||
// We are extremely conservative with what we warn about.
|
// We are extremely conservative with what we warn about.
|
||||||
let conjured_ty = cx.tables.expr_ty(expr);
|
let conjured_ty = cx.tables.expr_ty(expr);
|
||||||
|
|
||||||
if !ty_maybe_allows_zero_init(conjured_ty) {
|
if !ty_maybe_allows_zero_init(cx.tcx, conjured_ty) {
|
||||||
cx.span_lint(
|
cx.struct_span_lint(
|
||||||
INVALID_VALUE,
|
INVALID_VALUE,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -1913,7 +1942,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||||
"being left uninitialized"
|
"being left uninitialized"
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
);
|
)
|
||||||
|
.note("this means that this code causes undefined behavior \
|
||||||
|
when executed")
|
||||||
|
.help("use `MaybeUninit` instead")
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,52 @@
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
#![deny(invalid_value)]
|
#![deny(invalid_value)]
|
||||||
|
|
||||||
use std::mem;
|
use std::mem::{self, MaybeUninit};
|
||||||
|
|
||||||
|
enum Void {}
|
||||||
|
|
||||||
|
struct Ref(&'static i32);
|
||||||
|
|
||||||
|
struct Wrap<T> { wrapped: T }
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn generic<T: 'static>() {
|
||||||
|
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() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||||
let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
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::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||||
let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
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::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||||
let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||||
|
|
||||||
|
let _val: Wrap<fn()> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||||
|
let _val: Wrap<fn()> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||||
|
|
||||||
// Some types that should work just fine.
|
// Some types that should work just fine.
|
||||||
let _val: Option<&'static i32> = mem::zeroed();
|
let _val: Option<&'static i32> = mem::zeroed();
|
||||||
let _val: Option<fn()> = mem::zeroed();
|
let _val: Option<fn()> = mem::zeroed();
|
||||||
|
let _val: MaybeUninit<&'static i32> = mem::zeroed();
|
||||||
let _val: bool = mem::zeroed();
|
let _val: bool = mem::zeroed();
|
||||||
let _val: i32 = mem::zeroed();
|
let _val: i32 = mem::zeroed();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,169 @@
|
||||||
error: the type `!` does not permit zero-initialization
|
error: the type `&'static T` does not permit zero-initialization
|
||||||
--> $DIR/uninitialized-zeroed.rs:15:23
|
--> $DIR/uninitialized-zeroed.rs:20:32
|
||||||
|
|
|
|
||||||
LL | let _val: ! = mem::zeroed();
|
LL | let _val: &'static T = mem::zeroed();
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: lint level defined here
|
note: lint level defined here
|
||||||
--> $DIR/uninitialized-zeroed.rs:7:9
|
--> $DIR/uninitialized-zeroed.rs:7:9
|
||||||
|
|
|
|
||||||
LL | #![deny(invalid_value)]
|
LL | #![deny(invalid_value)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `&'static T` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:21:32
|
||||||
|
|
|
||||||
|
LL | let _val: &'static T = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Wrap<&'static T>` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:23:38
|
||||||
|
|
|
||||||
|
LL | let _val: Wrap<&'static T> = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Wrap<&'static T>` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:24:38
|
||||||
|
|
|
||||||
|
LL | let _val: Wrap<&'static T> = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `!` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:30:23
|
||||||
|
|
|
||||||
|
LL | let _val: ! = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: the type `!` does not permit being left uninitialized
|
error: the type `!` does not permit being left uninitialized
|
||||||
--> $DIR/uninitialized-zeroed.rs:16:23
|
--> $DIR/uninitialized-zeroed.rs:31:23
|
||||||
|
|
|
|
||||||
LL | let _val: ! = mem::uninitialized();
|
LL | let _val: ! = mem::uninitialized();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `(i32, !)` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:33:30
|
||||||
|
|
|
||||||
|
LL | let _val: (i32, !) = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `(i32, !)` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:34:30
|
||||||
|
|
|
||||||
|
LL | let _val: (i32, !) = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Void` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:36:26
|
||||||
|
|
|
||||||
|
LL | let _val: Void = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Void` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:37:26
|
||||||
|
|
|
||||||
|
LL | let _val: Void = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: the type `&'static i32` does not permit zero-initialization
|
error: the type `&'static i32` does not permit zero-initialization
|
||||||
--> $DIR/uninitialized-zeroed.rs:21:34
|
--> $DIR/uninitialized-zeroed.rs:39:34
|
||||||
|
|
|
|
||||||
LL | let _val: &'static i32 = mem::zeroed();
|
LL | let _val: &'static i32 = mem::zeroed();
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: the type `&'static i32` does not permit being left uninitialized
|
error: the type `&'static i32` does not permit being left uninitialized
|
||||||
--> $DIR/uninitialized-zeroed.rs:22:34
|
--> $DIR/uninitialized-zeroed.rs:40:34
|
||||||
|
|
|
|
||||||
LL | let _val: &'static i32 = mem::uninitialized();
|
LL | let _val: &'static i32 = mem::uninitialized();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Ref` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:42:25
|
||||||
|
|
|
||||||
|
LL | let _val: Ref = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Ref` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:43:25
|
||||||
|
|
|
||||||
|
LL | let _val: Ref = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: the type `fn()` does not permit zero-initialization
|
error: the type `fn()` does not permit zero-initialization
|
||||||
--> $DIR/uninitialized-zeroed.rs:24:26
|
--> $DIR/uninitialized-zeroed.rs:45:26
|
||||||
|
|
|
|
||||||
LL | let _val: fn() = mem::zeroed();
|
LL | let _val: fn() = mem::zeroed();
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: the type `fn()` does not permit being left uninitialized
|
error: the type `fn()` does not permit being left uninitialized
|
||||||
--> $DIR/uninitialized-zeroed.rs:25:26
|
--> $DIR/uninitialized-zeroed.rs:46:26
|
||||||
|
|
|
|
||||||
LL | let _val: fn() = mem::uninitialized();
|
LL | let _val: fn() = mem::uninitialized();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: the type `Wrap<fn()>` does not permit zero-initialization
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:48:32
|
||||||
|
|
|
||||||
|
LL | let _val: Wrap<fn()> = mem::zeroed();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: the type `Wrap<fn()>` does not permit being left uninitialized
|
||||||
|
--> $DIR/uninitialized-zeroed.rs:49:32
|
||||||
|
|
|
||||||
|
LL | let _val: Wrap<fn()> = mem::uninitialized();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this means that this code causes undefined behavior when executed
|
||||||
|
= help: use `MaybeUninit` instead
|
||||||
|
|
||||||
|
error: aborting due to 18 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue