visit struct fields in uninit fallback check
This commit is contained in:
parent
a95afe2d0a
commit
ae5326b967
@ -606,10 +606,13 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
|
|||||||
ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
|
ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
|
||||||
// Unions are always fine right now.
|
// Unions are always fine right now.
|
||||||
// This includes MaybeUninit, the main way people use uninitialized memory.
|
// This includes MaybeUninit, the main way people use uninitialized memory.
|
||||||
// For ADTs, we could look at all fields just like for tuples, but that's potentially
|
ty::Adt(adt, _) if adt.is_union() => true,
|
||||||
// exponential, so let's avoid doing that for now. Code doing that is sketchy enough to
|
// Types (e.g. `UnsafeCell<MaybeUninit<T>>`) that recursively contain only types that can be uninit
|
||||||
// just use an `#[allow()]`.
|
// can themselves be uninit too.
|
||||||
ty::Adt(adt, _) => adt.is_union(),
|
// This purposefully ignores enums as they may have a discriminant that can't be uninit.
|
||||||
|
ty::Adt(adt, args) if adt.is_struct() => adt
|
||||||
|
.all_fields()
|
||||||
|
.all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args))),
|
||||||
// For the rest, conservatively assume that they cannot be uninit.
|
// For the rest, conservatively assume that they cannot be uninit.
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -150,4 +150,36 @@ fn poly_maybe_uninit<T>() {
|
|||||||
vec.set_len(10);
|
vec.set_len(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nested_union<T>() {
|
||||||
|
let mut vec: Vec<UnsafeCell<MaybeUninit<T>>> = Vec::with_capacity(1);
|
||||||
|
unsafe {
|
||||||
|
vec.set_len(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Recursive<T>(*const Recursive<T>, MaybeUninit<T>);
|
||||||
|
fn recursive_union<T>() {
|
||||||
|
// Make sure we don't stack overflow on recursive types.
|
||||||
|
// The pointer acts as the base case because it can't be uninit regardless of its pointee.
|
||||||
|
|
||||||
|
let mut vec: Vec<Recursive<T>> = Vec::with_capacity(1);
|
||||||
|
//~^ uninit_vec
|
||||||
|
unsafe {
|
||||||
|
vec.set_len(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Enum<T> {
|
||||||
|
Variant(T),
|
||||||
|
}
|
||||||
|
fn union_in_enum<T>() {
|
||||||
|
// Enums can have a discriminant that can't be uninit, so this should still warn
|
||||||
|
let mut vec: Vec<Enum<T>> = Vec::with_capacity(1);
|
||||||
|
//~^ uninit_vec
|
||||||
|
unsafe {
|
||||||
|
vec.set_len(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,5 +125,27 @@ LL | vec.set_len(10);
|
|||||||
|
|
|
|
||||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||||
|
--> tests/ui/uninit_vec.rs:166:9
|
||||||
|
|
|
||||||
|
LL | let mut vec: Vec<Recursive<T>> = Vec::with_capacity(1);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | vec.set_len(1);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||||
|
|
||||||
|
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||||
|
--> tests/ui/uninit_vec.rs:179:9
|
||||||
|
|
|
||||||
|
LL | let mut vec: Vec<Enum<T>> = Vec::with_capacity(1);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | vec.set_len(1);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||||
|
|
||||||
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user