Skip to content

Commit 9d574b2

Browse files
committed
In uninit checking, add fallback for polymorphic types
1 parent 5ed64d4 commit 9d574b2

File tree

3 files changed

+39
-11
lines changed

3 files changed

+39
-11
lines changed

clippy_utils/src/ty.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,25 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
541541
pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
542542
cx.tcx
543543
.check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty)))
544-
// For types containing generic parameters we cannot get a layout to check.
545-
// Therefore, we are conservative and assume that they don't allow uninit.
546-
.unwrap_or(false)
544+
.unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty))
545+
}
546+
547+
/// A fallback for polymorphic types, which are not supported by `check_validity_requirement`.
548+
fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
549+
match *ty.kind() {
550+
// The array length may be polymorphic, let's try the inner type.
551+
ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
552+
// Peek through tuples and try their fallbacks.
553+
ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
554+
// Unions are always fine right now.
555+
// This includes MaybeUninit, the main way people use uninitialized memory.
556+
ty::Adt(adt, _) if adt.is_union() => true,
557+
// For ADTs, we could look at all fields just like for tuples, but that's potentially
558+
// exponential, so let's avoid doing that for now. Code doing that is sketchy enough to
559+
// just use an `#[allow()]`.
560+
// For the rest, conservatively assume that they cannot be uninit.
561+
_ => false,
562+
}
547563
}
548564

549565
/// Gets an iterator over all predicates which apply to the given item.

tests/ui/uninit.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(stmt_expr_attributes)]
22
#![allow(clippy::let_unit_value, invalid_value)]
33

4-
use std::mem::{self, MaybeUninit};
4+
use std::mem::MaybeUninit;
55

66
union MyOwnMaybeUninit {
77
value: u8,
@@ -30,12 +30,24 @@ fn main() {
3030
let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
3131

3232
// Was a false negative.
33-
let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
33+
let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
3434

3535
polymorphic::<()>();
36+
polymorphic_maybe_uninit_array::<10>();
37+
polymorphic_maybe_uninit::<u8>();
3638

3739
fn polymorphic<T>() {
3840
// We are conservative around polymorphic types.
39-
let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
41+
let _: T = unsafe { MaybeUninit::uninit().assume_init() };
42+
}
43+
44+
fn polymorphic_maybe_uninit_array<const N: usize>() {
45+
// While the type is polymorphic, MaybeUninit<u8> is not.
46+
let _: [MaybeUninit<u8>; N] = unsafe { MaybeUninit::uninit().assume_init() };
47+
}
48+
49+
fn polymorphic_maybe_uninit<T>() {
50+
// The entire type is polymorphic, but it's wrapped in a MaybeUninit.
51+
let _: MaybeUninit<T> = unsafe { MaybeUninit::uninit().assume_init() };
4052
}
4153
}

tests/ui/uninit.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
99
error: this call for this type may be undefined behavior
1010
--> $DIR/uninit.rs:33:29
1111
|
12-
LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: this call for this type may be undefined behavior
16-
--> $DIR/uninit.rs:39:29
16+
--> $DIR/uninit.rs:41:29
1717
|
18-
LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
19-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
LL | let _: T = unsafe { MaybeUninit::uninit().assume_init() };
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error: aborting due to 3 previous errors
2222

0 commit comments

Comments
 (0)