Skip to content

Commit 0d242b3

Browse files
committed
invalid_value: warn for types with custom valid range
1 parent 25d8a0a commit 0d242b3

File tree

3 files changed

+102
-30
lines changed

3 files changed

+102
-30
lines changed

src/librustc_lint/builtin.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,8 +1928,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19281928
Some((format!("Booleans must be `true` or `false`"), None)),
19291929
Char if init == InitKind::Uninit =>
19301930
Some((format!("Characters must be a valid unicode codepoint"), None)),
1931-
// Recurse for some compound types.
1931+
// Recurse and checks for some compound types.
19321932
Adt(adt_def, substs) if !adt_def.is_union() => {
1933+
// First check f this ADT has a layout attribute (like `NonNull` and friends).
1934+
use std::ops::Bound;
1935+
match tcx.layout_scalar_valid_range(adt_def.did) {
1936+
// We exploit here that `layout_scalar_valid_range` will never
1937+
// return `Bound::Excluded`. (And we have tests checking that we
1938+
// handle the attribute correctly.)
1939+
(Bound::Included(lo), _) if lo > 0 =>
1940+
return Some((format!("{} must be non-null", ty), None)),
1941+
(Bound::Included(_), _) | (_, Bound::Included(_))
1942+
if init == InitKind::Uninit =>
1943+
return Some((
1944+
format!("{} must be initialized inside its custom valid range", ty),
1945+
None,
1946+
)),
1947+
_ => {}
1948+
}
1949+
// Now, recurse.
19331950
match adt_def.variants.len() {
19341951
0 => Some((format!("0-variant enums have no valid value"), None)),
19351952
1 => {
@@ -1961,7 +1978,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19611978
// Proceed recursively, check all fields.
19621979
ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field, init))
19631980
}
1964-
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
19651981
// FIXME: *Only for `mem::uninitialized`*, we could also warn for multivariant enum.
19661982
// Conservative fallback.
19671983
_ => None,

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results
33
// in a lint.
44

5-
#![feature(never_type)]
5+
#![feature(never_type, rustc_attrs)]
66
#![allow(deprecated)]
77
#![deny(invalid_value)]
88

@@ -16,6 +16,11 @@ struct RefPair((&'static i32, i32));
1616
struct Wrap<T> { wrapped: T }
1717
enum WrapEnum<T> { Wrapped(T) }
1818

19+
#[rustc_layout_scalar_valid_range_start(0)]
20+
#[rustc_layout_scalar_valid_range_end(128)]
21+
#[repr(transparent)]
22+
pub(crate) struct NonBig(u64);
23+
1924
#[allow(unused)]
2025
fn generic<T: 'static>() {
2126
unsafe {
@@ -29,6 +34,7 @@ fn generic<T: 'static>() {
2934

3035
fn main() {
3136
unsafe {
37+
// Things that cannot even be zero.
3238
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
3339
let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
3440

@@ -56,14 +62,23 @@ fn main() {
5662
let _val: Wrap<(RefPair, i32)> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
5763
let _val: Wrap<(RefPair, i32)> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
5864

65+
let _val: Vec<i32> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
66+
let _val: Vec<i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
67+
68+
// Things that can be zero, but not uninit.
69+
let _val: bool = mem::zeroed();
5970
let _val: bool = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
71+
72+
let _val: Wrap<char> = mem::zeroed();
6073
let _val: Wrap<char> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
6174

62-
// Some types that should work just fine.
75+
let _val: NonBig = mem::zeroed();
76+
let _val: NonBig = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
77+
78+
// Some more types that should work just fine.
6379
let _val: Option<&'static i32> = mem::zeroed();
6480
let _val: Option<fn()> = mem::zeroed();
6581
let _val: MaybeUninit<&'static i32> = mem::zeroed();
66-
let _val: bool = mem::zeroed();
6782
let _val: i32 = mem::zeroed();
6883
}
6984
}

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

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: the type `&'static T` does not permit zero-initialization
2-
--> $DIR/uninitialized-zeroed.rs:22:32
2+
--> $DIR/uninitialized-zeroed.rs:27:32
33
|
44
LL | let _val: &'static T = mem::zeroed();
55
| ^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #![deny(invalid_value)]
1515
= note: References must be non-null
1616

1717
error: the type `&'static T` does not permit being left uninitialized
18-
--> $DIR/uninitialized-zeroed.rs:23:32
18+
--> $DIR/uninitialized-zeroed.rs:28:32
1919
|
2020
LL | let _val: &'static T = mem::uninitialized();
2121
| ^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | let _val: &'static T = mem::uninitialized();
2626
= note: References must be non-null
2727

2828
error: the type `Wrap<&'static T>` does not permit zero-initialization
29-
--> $DIR/uninitialized-zeroed.rs:25:38
29+
--> $DIR/uninitialized-zeroed.rs:30:38
3030
|
3131
LL | let _val: Wrap<&'static T> = mem::zeroed();
3232
| ^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | struct Wrap<T> { wrapped: T }
4141
| ^^^^^^^^^^
4242

4343
error: the type `Wrap<&'static T>` does not permit being left uninitialized
44-
--> $DIR/uninitialized-zeroed.rs:26:38
44+
--> $DIR/uninitialized-zeroed.rs:31:38
4545
|
4646
LL | let _val: Wrap<&'static T> = mem::uninitialized();
4747
| ^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL | struct Wrap<T> { wrapped: T }
5656
| ^^^^^^^^^^
5757

5858
error: the type `!` does not permit zero-initialization
59-
--> $DIR/uninitialized-zeroed.rs:32:23
59+
--> $DIR/uninitialized-zeroed.rs:38:23
6060
|
6161
LL | let _val: ! = mem::zeroed();
6262
| ^^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL | let _val: ! = mem::zeroed();
6767
= note: The never type (`!`) has no valid value
6868

6969
error: the type `!` does not permit being left uninitialized
70-
--> $DIR/uninitialized-zeroed.rs:33:23
70+
--> $DIR/uninitialized-zeroed.rs:39:23
7171
|
7272
LL | let _val: ! = mem::uninitialized();
7373
| ^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL | let _val: ! = mem::uninitialized();
7878
= note: The never type (`!`) has no valid value
7979

8080
error: the type `(i32, !)` does not permit zero-initialization
81-
--> $DIR/uninitialized-zeroed.rs:35:30
81+
--> $DIR/uninitialized-zeroed.rs:41:30
8282
|
8383
LL | let _val: (i32, !) = mem::zeroed();
8484
| ^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ LL | let _val: (i32, !) = mem::zeroed();
8989
= note: The never type (`!`) has no valid value
9090

9191
error: the type `(i32, !)` does not permit being left uninitialized
92-
--> $DIR/uninitialized-zeroed.rs:36:30
92+
--> $DIR/uninitialized-zeroed.rs:42:30
9393
|
9494
LL | let _val: (i32, !) = mem::uninitialized();
9595
| ^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL | let _val: (i32, !) = mem::uninitialized();
100100
= note: The never type (`!`) has no valid value
101101

102102
error: the type `Void` does not permit zero-initialization
103-
--> $DIR/uninitialized-zeroed.rs:38:26
103+
--> $DIR/uninitialized-zeroed.rs:44:26
104104
|
105105
LL | let _val: Void = mem::zeroed();
106106
| ^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL | let _val: Void = mem::zeroed();
111111
= note: 0-variant enums have no valid value
112112

113113
error: the type `Void` does not permit being left uninitialized
114-
--> $DIR/uninitialized-zeroed.rs:39:26
114+
--> $DIR/uninitialized-zeroed.rs:45:26
115115
|
116116
LL | let _val: Void = mem::uninitialized();
117117
| ^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL | let _val: Void = mem::uninitialized();
122122
= note: 0-variant enums have no valid value
123123

124124
error: the type `&'static i32` does not permit zero-initialization
125-
--> $DIR/uninitialized-zeroed.rs:41:34
125+
--> $DIR/uninitialized-zeroed.rs:47:34
126126
|
127127
LL | let _val: &'static i32 = mem::zeroed();
128128
| ^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL | let _val: &'static i32 = mem::zeroed();
133133
= note: References must be non-null
134134

135135
error: the type `&'static i32` does not permit being left uninitialized
136-
--> $DIR/uninitialized-zeroed.rs:42:34
136+
--> $DIR/uninitialized-zeroed.rs:48:34
137137
|
138138
LL | let _val: &'static i32 = mem::uninitialized();
139139
| ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL | let _val: &'static i32 = mem::uninitialized();
144144
= note: References must be non-null
145145

146146
error: the type `Ref` does not permit zero-initialization
147-
--> $DIR/uninitialized-zeroed.rs:44:25
147+
--> $DIR/uninitialized-zeroed.rs:50:25
148148
|
149149
LL | let _val: Ref = mem::zeroed();
150150
| ^^^^^^^^^^^^^
@@ -159,7 +159,7 @@ LL | struct Ref(&'static i32);
159159
| ^^^^^^^^^^^^
160160

161161
error: the type `Ref` does not permit being left uninitialized
162-
--> $DIR/uninitialized-zeroed.rs:45:25
162+
--> $DIR/uninitialized-zeroed.rs:51:25
163163
|
164164
LL | let _val: Ref = mem::uninitialized();
165165
| ^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +174,7 @@ LL | struct Ref(&'static i32);
174174
| ^^^^^^^^^^^^
175175

176176
error: the type `fn()` does not permit zero-initialization
177-
--> $DIR/uninitialized-zeroed.rs:47:26
177+
--> $DIR/uninitialized-zeroed.rs:53:26
178178
|
179179
LL | let _val: fn() = mem::zeroed();
180180
| ^^^^^^^^^^^^^
@@ -185,7 +185,7 @@ LL | let _val: fn() = mem::zeroed();
185185
= note: Function pointers must be non-null
186186

187187
error: the type `fn()` does not permit being left uninitialized
188-
--> $DIR/uninitialized-zeroed.rs:48:26
188+
--> $DIR/uninitialized-zeroed.rs:54:26
189189
|
190190
LL | let _val: fn() = mem::uninitialized();
191191
| ^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +196,7 @@ LL | let _val: fn() = mem::uninitialized();
196196
= note: Function pointers must be non-null
197197

198198
error: the type `Wrap<fn()>` does not permit zero-initialization
199-
--> $DIR/uninitialized-zeroed.rs:50:32
199+
--> $DIR/uninitialized-zeroed.rs:56:32
200200
|
201201
LL | let _val: Wrap<fn()> = mem::zeroed();
202202
| ^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL | struct Wrap<T> { wrapped: T }
211211
| ^^^^^^^^^^
212212

213213
error: the type `Wrap<fn()>` does not permit being left uninitialized
214-
--> $DIR/uninitialized-zeroed.rs:51:32
214+
--> $DIR/uninitialized-zeroed.rs:57:32
215215
|
216216
LL | let _val: Wrap<fn()> = mem::uninitialized();
217217
| ^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +226,7 @@ LL | struct Wrap<T> { wrapped: T }
226226
| ^^^^^^^^^^
227227

228228
error: the type `WrapEnum<fn()>` does not permit zero-initialization
229-
--> $DIR/uninitialized-zeroed.rs:53:36
229+
--> $DIR/uninitialized-zeroed.rs:59:36
230230
|
231231
LL | let _val: WrapEnum<fn()> = mem::zeroed();
232232
| ^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
241241
| ^
242242

243243
error: the type `WrapEnum<fn()>` does not permit being left uninitialized
244-
--> $DIR/uninitialized-zeroed.rs:54:36
244+
--> $DIR/uninitialized-zeroed.rs:60:36
245245
|
246246
LL | let _val: WrapEnum<fn()> = mem::uninitialized();
247247
| ^^^^^^^^^^^^^^^^^^^^
@@ -256,7 +256,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
256256
| ^
257257

258258
error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization
259-
--> $DIR/uninitialized-zeroed.rs:56:42
259+
--> $DIR/uninitialized-zeroed.rs:62:42
260260
|
261261
LL | let _val: Wrap<(RefPair, i32)> = mem::zeroed();
262262
| ^^^^^^^^^^^^^
@@ -271,7 +271,7 @@ LL | struct RefPair((&'static i32, i32));
271271
| ^^^^^^^^^^^^^^^^^^^
272272

273273
error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized
274-
--> $DIR/uninitialized-zeroed.rs:57:42
274+
--> $DIR/uninitialized-zeroed.rs:63:42
275275
|
276276
LL | let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
277277
| ^^^^^^^^^^^^^^^^^^^^
@@ -285,8 +285,38 @@ note: References must be non-null (in this struct field)
285285
LL | struct RefPair((&'static i32, i32));
286286
| ^^^^^^^^^^^^^^^^^^^
287287

288+
error: the type `std::vec::Vec<i32>` does not permit zero-initialization
289+
--> $DIR/uninitialized-zeroed.rs:65:30
290+
|
291+
LL | let _val: Vec<i32> = mem::zeroed();
292+
| ^^^^^^^^^^^^^
293+
| |
294+
| this code causes undefined behavior when executed
295+
| help: use `MaybeUninit<T>` instead
296+
|
297+
note: std::ptr::Unique<i32> must be non-null (in this struct field)
298+
--> $SRC_DIR/liballoc/raw_vec.rs:LL:COL
299+
|
300+
LL | ptr: Unique<T>,
301+
| ^^^^^^^^^^^^^^
302+
303+
error: the type `std::vec::Vec<i32>` does not permit being left uninitialized
304+
--> $DIR/uninitialized-zeroed.rs:66:30
305+
|
306+
LL | let _val: Vec<i32> = mem::uninitialized();
307+
| ^^^^^^^^^^^^^^^^^^^^
308+
| |
309+
| this code causes undefined behavior when executed
310+
| help: use `MaybeUninit<T>` instead
311+
|
312+
note: std::ptr::Unique<i32> must be non-null (in this struct field)
313+
--> $SRC_DIR/liballoc/raw_vec.rs:LL:COL
314+
|
315+
LL | ptr: Unique<T>,
316+
| ^^^^^^^^^^^^^^
317+
288318
error: the type `bool` does not permit being left uninitialized
289-
--> $DIR/uninitialized-zeroed.rs:59:26
319+
--> $DIR/uninitialized-zeroed.rs:70:26
290320
|
291321
LL | let _val: bool = mem::uninitialized();
292322
| ^^^^^^^^^^^^^^^^^^^^
@@ -297,7 +327,7 @@ LL | let _val: bool = mem::uninitialized();
297327
= note: Booleans must be `true` or `false`
298328

299329
error: the type `Wrap<char>` does not permit being left uninitialized
300-
--> $DIR/uninitialized-zeroed.rs:60:32
330+
--> $DIR/uninitialized-zeroed.rs:73:32
301331
|
302332
LL | let _val: Wrap<char> = mem::uninitialized();
303333
| ^^^^^^^^^^^^^^^^^^^^
@@ -311,5 +341,16 @@ note: Characters must be a valid unicode codepoint (in this struct field)
311341
LL | struct Wrap<T> { wrapped: T }
312342
| ^^^^^^^^^^
313343

314-
error: aborting due to 24 previous errors
344+
error: the type `NonBig` does not permit being left uninitialized
345+
--> $DIR/uninitialized-zeroed.rs:76:28
346+
|
347+
LL | let _val: NonBig = mem::uninitialized();
348+
| ^^^^^^^^^^^^^^^^^^^^
349+
| |
350+
| this code causes undefined behavior when executed
351+
| help: use `MaybeUninit<T>` instead
352+
|
353+
= note: NonBig must be initialized inside its custom valid range
354+
355+
error: aborting due to 27 previous errors
315356

0 commit comments

Comments
 (0)