Skip to content

Commit b426bd5

Browse files
committed
Don't lint transmute_undefined_repr when the the first field of a repr(C) type is compatible with the other type
1 parent 7177746 commit b426bd5

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

clippy_lints/src/transmute/transmute_undefined_repr.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,18 @@ pub(super) fn check<'tcx>(
164164
);
165165
return true;
166166
},
167+
// `Repr(C)` <-> unordered type.
168+
// If the first field of the `Repr(C)` type matches then the transmute is ok
169+
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
170+
| (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
171+
| (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
172+
from_ty = from_sub_ty;
173+
to_ty = to_sub_ty;
174+
continue;
175+
},
167176
(
168177
ReducedTy::UnorderedFields(from_ty),
169-
ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
178+
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
170179
) => {
171180
span_lint_and_then(
172181
cx,
@@ -182,7 +191,7 @@ pub(super) fn check<'tcx>(
182191
return true;
183192
},
184193
(
185-
ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
194+
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_),
186195
ReducedTy::UnorderedFields(to_ty),
187196
) => {
188197
span_lint_and_then(
@@ -198,14 +207,9 @@ pub(super) fn check<'tcx>(
198207
);
199208
return true;
200209
},
201-
(ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
202-
from_ty = from_sub_ty;
203-
to_ty = to_sub_ty;
204-
continue;
205-
},
206210
(
207-
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
208-
ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
211+
ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
212+
ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
209213
)
210214
| (
211215
ReducedTy::UnorderedFields(_) | ReducedTy::Param,
@@ -269,7 +273,8 @@ enum ReducedTy<'tcx> {
269273
TypeErasure,
270274
/// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
271275
/// sized fields with a defined order.
272-
OrderedFields(Ty<'tcx>),
276+
/// The second value is the first non-zero sized type.
277+
OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
273278
/// The type is a struct containing multiple non-zero sized fields with no defined order.
274279
UnorderedFields(Ty<'tcx>),
275280
/// 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>
294299
ty::Tuple(args) => {
295300
let mut iter = args.iter();
296301
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
297-
return ReducedTy::OrderedFields(ty);
302+
return ReducedTy::OrderedFields(ty, None);
298303
};
299304
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
300305
ty = sized_ty;
@@ -316,7 +321,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
316321
continue;
317322
}
318323
if def.repr().inhibit_struct_field_reordering_opt() {
319-
ReducedTy::OrderedFields(ty)
324+
ReducedTy::OrderedFields(ty, Some(sized_ty))
320325
} else {
321326
ReducedTy::UnorderedFields(ty)
322327
}

tests/ui/transmute_undefined_repr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ fn main() {
109109
let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
110110

111111
let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
112+
113+
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
114+
let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
115+
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
116+
let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
117+
118+
let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
119+
let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
112120
}
113121
}
114122

tests/ui/transmute_undefined_repr.stderr

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,37 @@ LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32,
6060
|
6161
= note: two instances of the same generic type (`Ty2`) may have different layouts
6262

63+
error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
64+
--> $DIR/transmute_undefined_repr.rs:118:39
65+
|
66+
LL | let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
|
69+
= note: the contained type `Ty2<u32, u32>` has an undefined layout
70+
71+
error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
72+
--> $DIR/transmute_undefined_repr.rs:119:50
73+
|
74+
LL | let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76+
|
77+
= note: the contained type `Ty2<u32, u32>` has an undefined layout
78+
6379
error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
64-
--> $DIR/transmute_undefined_repr.rs:138:35
80+
--> $DIR/transmute_undefined_repr.rs:146:35
6581
|
6682
LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
6783
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6884
|
6985
= note: two instances of the same generic type (`Vec`) may have different layouts
7086

7187
error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
72-
--> $DIR/transmute_undefined_repr.rs:139:35
88+
--> $DIR/transmute_undefined_repr.rs:147:35
7389
|
7490
LL | let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
7591
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7692
|
7793
= note: two instances of the same generic type (`Vec`) may have different layouts
7894

79-
error: aborting due to 10 previous errors
95+
error: aborting due to 12 previous errors
8096

0 commit comments

Comments
 (0)