Don't lint transmute_undefined_repr when the the first field of a repr(C) type is compatible with the other type

This commit is contained in:
Jason Newcomb 2022-08-03 13:16:04 -04:00
parent 71777465cc
commit b426bd52a1
3 changed files with 44 additions and 15 deletions

View File

@ -164,9 +164,18 @@ pub(super) fn check<'tcx>(
);
return true;
},
// `Repr(C)` <-> unordered type.
// If the first field of the `Repr(C)` type matches then the transmute is ok
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
| (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
| (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(
ReducedTy::UnorderedFields(from_ty),
ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
) => {
span_lint_and_then(
cx,
@ -182,7 +191,7 @@ pub(super) fn check<'tcx>(
return true;
},
(
ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
ReducedTy::UnorderedFields(to_ty),
) => {
span_lint_and_then(
@ -198,14 +207,9 @@ pub(super) fn check<'tcx>(
);
return true;
},
(ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
)
| (
ReducedTy::UnorderedFields(_) | ReducedTy::Param,
@ -269,7 +273,8 @@ enum ReducedTy<'tcx> {
TypeErasure,
/// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
/// sized fields with a defined order.
OrderedFields(Ty<'tcx>),
/// The second value is the first non-zero sized type.
OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
/// The type is a struct containing multiple non-zero sized fields with no defined order.
UnorderedFields(Ty<'tcx>),
/// The type is a reference to the contained type.
@ -294,7 +299,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
ty::Tuple(args) => {
let mut iter = args.iter();
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
return ReducedTy::OrderedFields(ty);
return ReducedTy::OrderedFields(ty, None);
};
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
ty = sized_ty;
@ -316,7 +321,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
continue;
}
if def.repr().inhibit_struct_field_reordering_opt() {
ReducedTy::OrderedFields(ty)
ReducedTy::OrderedFields(ty, Some(sized_ty))
} else {
ReducedTy::UnorderedFields(ty)
}

View File

@ -109,6 +109,14 @@ fn main() {
let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
}
}

View File

@ -60,8 +60,24 @@ LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32,
|
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
--> $DIR/transmute_undefined_repr.rs:118:39
|
LL | let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the contained type `Ty2<u32, u32>` has an undefined layout
error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
--> $DIR/transmute_undefined_repr.rs:119:50
|
LL | let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the contained type `Ty2<u32, u32>` has an undefined layout
error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
--> $DIR/transmute_undefined_repr.rs:138:35
--> $DIR/transmute_undefined_repr.rs:146:35
|
LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -69,12 +85,12 @@ LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); /
= note: two instances of the same generic type (`Vec`) may have different layouts
error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
--> $DIR/transmute_undefined_repr.rs:139:35
--> $DIR/transmute_undefined_repr.rs:147:35
|
LL | let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: two instances of the same generic type (`Vec`) may have different layouts
error: aborting due to 10 previous errors
error: aborting due to 12 previous errors