Skip to content

Commit 16c0902

Browse files
committed
warn for more cases
1 parent ad832a1 commit 16c0902

File tree

3 files changed

+204
-16
lines changed

3 files changed

+204
-16
lines changed

src/librustc_lint/builtin.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
use rustc::hir::def::{Res, DefKind};
2525
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
26-
use rustc::ty::{self, Ty, TyCtxt};
26+
use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx};
2727
use rustc::{lint, util};
2828
use hir::Node;
2929
use util::nodemap::HirIdSet;
@@ -1879,11 +1879,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
18791879

18801880
/// Return `false` only if we are sure this type does *not*
18811881
/// allow zero initialization.
1882-
fn ty_maybe_allows_zero_init(ty: Ty<'_>) -> bool {
1882+
fn ty_maybe_allows_zero_init<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
18831883
use rustc::ty::TyKind::*;
18841884
match ty.sty {
18851885
// Primitive types that don't like 0 as a value.
18861886
Ref(..) | FnPtr(..) | Never => false,
1887+
Adt(..) if ty.is_box() => false,
1888+
// Recurse for some compound types.
1889+
Adt(adt_def, substs) if !adt_def.is_union() => {
1890+
match adt_def.variants.len() {
1891+
0 => false, // Uninhabited enum!
1892+
1 => {
1893+
// Struct, or enum with exactly one variant.
1894+
// Proceed recursively, check all fields.
1895+
let variant = &adt_def.variants[VariantIdx::from_u32(0)];
1896+
variant.fields.iter().all(|field| {
1897+
ty_maybe_allows_zero_init(
1898+
tcx,
1899+
field.ty(tcx, substs),
1900+
)
1901+
})
1902+
}
1903+
_ => true, // Conservative fallback for multi-variant enum.
1904+
}
1905+
}
1906+
Tuple(substs) => {
1907+
// Proceed recursively, check all fields.
1908+
substs.iter().all(|field| {
1909+
ty_maybe_allows_zero_init(
1910+
tcx,
1911+
field.expect_ty(),
1912+
)
1913+
})
1914+
}
1915+
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
18871916
// Conservative fallback.
18881917
_ => true,
18891918
}
@@ -1900,8 +1929,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19001929
// We are extremely conservative with what we warn about.
19011930
let conjured_ty = cx.tables.expr_ty(expr);
19021931

1903-
if !ty_maybe_allows_zero_init(conjured_ty) {
1904-
cx.span_lint(
1932+
if !ty_maybe_allows_zero_init(cx.tcx, conjured_ty) {
1933+
cx.struct_span_lint(
19051934
INVALID_VALUE,
19061935
expr.span,
19071936
&format!(
@@ -1913,7 +1942,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19131942
"being left uninitialized"
19141943
}
19151944
),
1916-
);
1945+
)
1946+
.note("this means that this code causes undefined behavior \
1947+
when executed")
1948+
.help("use `MaybeUninit` instead")
1949+
.emit();
19171950
}
19181951
}
19191952
}

src/test/ui/lint/uninitialized-zeroed.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,52 @@
66
#![allow(deprecated)]
77
#![deny(invalid_value)]
88

9-
use std::mem;
9+
use std::mem::{self, MaybeUninit};
10+
11+
enum Void {}
12+
13+
struct Ref(&'static i32);
14+
15+
struct Wrap<T> { wrapped: T }
16+
17+
#[allow(unused)]
18+
fn generic<T: 'static>() {
19+
unsafe {
20+
let _val: &'static T = mem::zeroed(); //~ ERROR: does not permit zero-initialization
21+
let _val: &'static T = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
22+
23+
let _val: Wrap<&'static T> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
24+
let _val: Wrap<&'static T> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
25+
}
26+
}
1027

1128
fn main() {
1229
unsafe {
1330
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
1431
let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
1532

33+
let _val: (i32, !) = mem::zeroed(); //~ ERROR: does not permit zero-initialization
34+
let _val: (i32, !) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
35+
36+
let _val: Void = mem::zeroed(); //~ ERROR: does not permit zero-initialization
37+
let _val: Void = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
38+
1639
let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization
1740
let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
1841

42+
let _val: Ref = mem::zeroed(); //~ ERROR: does not permit zero-initialization
43+
let _val: Ref = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
44+
1945
let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization
2046
let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
2147

48+
let _val: Wrap<fn()> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
49+
let _val: Wrap<fn()> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
50+
2251
// Some types that should work just fine.
2352
let _val: Option<&'static i32> = mem::zeroed();
2453
let _val: Option<fn()> = mem::zeroed();
54+
let _val: MaybeUninit<&'static i32> = mem::zeroed();
2555
let _val: bool = mem::zeroed();
2656
let _val: i32 = mem::zeroed();
2757
}
Lines changed: 135 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,169 @@
1-
error: the type `!` does not permit zero-initialization
2-
--> $DIR/uninitialized-zeroed.rs:15:23
1+
error: the type `&'static T` does not permit zero-initialization
2+
--> $DIR/uninitialized-zeroed.rs:20:32
33
|
4-
LL | let _val: ! = mem::zeroed();
5-
| ^^^^^^^^^^^^^
4+
LL | let _val: &'static T = mem::zeroed();
5+
| ^^^^^^^^^^^^^
66
|
77
note: lint level defined here
88
--> $DIR/uninitialized-zeroed.rs:7:9
99
|
1010
LL | #![deny(invalid_value)]
1111
| ^^^^^^^^^^^^^
12+
= note: this means that this code causes undefined behavior when executed
13+
= help: use `MaybeUninit` instead
14+
15+
error: the type `&'static T` does not permit being left uninitialized
16+
--> $DIR/uninitialized-zeroed.rs:21:32
17+
|
18+
LL | let _val: &'static T = mem::uninitialized();
19+
| ^^^^^^^^^^^^^^^^^^^^
20+
|
21+
= note: this means that this code causes undefined behavior when executed
22+
= help: use `MaybeUninit` instead
23+
24+
error: the type `Wrap<&'static T>` does not permit zero-initialization
25+
--> $DIR/uninitialized-zeroed.rs:23:38
26+
|
27+
LL | let _val: Wrap<&'static T> = mem::zeroed();
28+
| ^^^^^^^^^^^^^
29+
|
30+
= note: this means that this code causes undefined behavior when executed
31+
= help: use `MaybeUninit` instead
32+
33+
error: the type `Wrap<&'static T>` does not permit being left uninitialized
34+
--> $DIR/uninitialized-zeroed.rs:24:38
35+
|
36+
LL | let _val: Wrap<&'static T> = mem::uninitialized();
37+
| ^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= note: this means that this code causes undefined behavior when executed
40+
= help: use `MaybeUninit` instead
41+
42+
error: the type `!` does not permit zero-initialization
43+
--> $DIR/uninitialized-zeroed.rs:30:23
44+
|
45+
LL | let _val: ! = mem::zeroed();
46+
| ^^^^^^^^^^^^^
47+
|
48+
= note: this means that this code causes undefined behavior when executed
49+
= help: use `MaybeUninit` instead
1250

1351
error: the type `!` does not permit being left uninitialized
14-
--> $DIR/uninitialized-zeroed.rs:16:23
52+
--> $DIR/uninitialized-zeroed.rs:31:23
1553
|
1654
LL | let _val: ! = mem::uninitialized();
1755
| ^^^^^^^^^^^^^^^^^^^^
56+
|
57+
= note: this means that this code causes undefined behavior when executed
58+
= help: use `MaybeUninit` instead
59+
60+
error: the type `(i32, !)` does not permit zero-initialization
61+
--> $DIR/uninitialized-zeroed.rs:33:30
62+
|
63+
LL | let _val: (i32, !) = mem::zeroed();
64+
| ^^^^^^^^^^^^^
65+
|
66+
= note: this means that this code causes undefined behavior when executed
67+
= help: use `MaybeUninit` instead
68+
69+
error: the type `(i32, !)` does not permit being left uninitialized
70+
--> $DIR/uninitialized-zeroed.rs:34:30
71+
|
72+
LL | let _val: (i32, !) = mem::uninitialized();
73+
| ^^^^^^^^^^^^^^^^^^^^
74+
|
75+
= note: this means that this code causes undefined behavior when executed
76+
= help: use `MaybeUninit` instead
77+
78+
error: the type `Void` does not permit zero-initialization
79+
--> $DIR/uninitialized-zeroed.rs:36:26
80+
|
81+
LL | let _val: Void = mem::zeroed();
82+
| ^^^^^^^^^^^^^
83+
|
84+
= note: this means that this code causes undefined behavior when executed
85+
= help: use `MaybeUninit` instead
86+
87+
error: the type `Void` does not permit being left uninitialized
88+
--> $DIR/uninitialized-zeroed.rs:37:26
89+
|
90+
LL | let _val: Void = mem::uninitialized();
91+
| ^^^^^^^^^^^^^^^^^^^^
92+
|
93+
= note: this means that this code causes undefined behavior when executed
94+
= help: use `MaybeUninit` instead
1895

1996
error: the type `&'static i32` does not permit zero-initialization
20-
--> $DIR/uninitialized-zeroed.rs:21:34
97+
--> $DIR/uninitialized-zeroed.rs:39:34
2198
|
2299
LL | let _val: &'static i32 = mem::zeroed();
23100
| ^^^^^^^^^^^^^
101+
|
102+
= note: this means that this code causes undefined behavior when executed
103+
= help: use `MaybeUninit` instead
24104

25105
error: the type `&'static i32` does not permit being left uninitialized
26-
--> $DIR/uninitialized-zeroed.rs:22:34
106+
--> $DIR/uninitialized-zeroed.rs:40:34
27107
|
28108
LL | let _val: &'static i32 = mem::uninitialized();
29109
| ^^^^^^^^^^^^^^^^^^^^
110+
|
111+
= note: this means that this code causes undefined behavior when executed
112+
= help: use `MaybeUninit` instead
113+
114+
error: the type `Ref` does not permit zero-initialization
115+
--> $DIR/uninitialized-zeroed.rs:42:25
116+
|
117+
LL | let _val: Ref = mem::zeroed();
118+
| ^^^^^^^^^^^^^
119+
|
120+
= note: this means that this code causes undefined behavior when executed
121+
= help: use `MaybeUninit` instead
122+
123+
error: the type `Ref` does not permit being left uninitialized
124+
--> $DIR/uninitialized-zeroed.rs:43:25
125+
|
126+
LL | let _val: Ref = mem::uninitialized();
127+
| ^^^^^^^^^^^^^^^^^^^^
128+
|
129+
= note: this means that this code causes undefined behavior when executed
130+
= help: use `MaybeUninit` instead
30131

31132
error: the type `fn()` does not permit zero-initialization
32-
--> $DIR/uninitialized-zeroed.rs:24:26
133+
--> $DIR/uninitialized-zeroed.rs:45:26
33134
|
34135
LL | let _val: fn() = mem::zeroed();
35136
| ^^^^^^^^^^^^^
137+
|
138+
= note: this means that this code causes undefined behavior when executed
139+
= help: use `MaybeUninit` instead
36140

37141
error: the type `fn()` does not permit being left uninitialized
38-
--> $DIR/uninitialized-zeroed.rs:25:26
142+
--> $DIR/uninitialized-zeroed.rs:46:26
39143
|
40144
LL | let _val: fn() = mem::uninitialized();
41145
| ^^^^^^^^^^^^^^^^^^^^
146+
|
147+
= note: this means that this code causes undefined behavior when executed
148+
= help: use `MaybeUninit` instead
149+
150+
error: the type `Wrap<fn()>` does not permit zero-initialization
151+
--> $DIR/uninitialized-zeroed.rs:48:32
152+
|
153+
LL | let _val: Wrap<fn()> = mem::zeroed();
154+
| ^^^^^^^^^^^^^
155+
|
156+
= note: this means that this code causes undefined behavior when executed
157+
= help: use `MaybeUninit` instead
158+
159+
error: the type `Wrap<fn()>` does not permit being left uninitialized
160+
--> $DIR/uninitialized-zeroed.rs:49:32
161+
|
162+
LL | let _val: Wrap<fn()> = mem::uninitialized();
163+
| ^^^^^^^^^^^^^^^^^^^^
164+
|
165+
= note: this means that this code causes undefined behavior when executed
166+
= help: use `MaybeUninit` instead
42167

43-
error: aborting due to 6 previous errors
168+
error: aborting due to 18 previous errors
44169

0 commit comments

Comments
 (0)