1 use super::TRANSMUTE_UNDEFINED_REPR
;
2 use clippy_utils
::diagnostics
::span_lint_and_then
;
4 use rustc_lint
::LateContext
;
5 use rustc_middle
::ty
::subst
::{GenericArg, Subst}
;
6 use rustc_middle
::ty
::{self, Ty, TypeAndMut}
;
9 #[allow(clippy::too_many_lines)]
10 pub(super) fn check
<'tcx
>(
11 cx
: &LateContext
<'tcx
>,
13 from_ty_orig
: Ty
<'tcx
>,
16 let mut from_ty
= cx
.tcx
.erase_regions(from_ty_orig
);
17 let mut to_ty
= cx
.tcx
.erase_regions(to_ty_orig
);
19 while from_ty
!= to_ty
{
20 match reduce_refs(cx
, e
.span
, from_ty
, to_ty
) {
21 ReducedTys
::FromFatPtr { unsized_ty, .. }
=> {
24 TRANSMUTE_UNDEFINED_REPR
,
26 &format
!("transmute from `{}` which has an undefined layout", from_ty_orig
),
28 if from_ty_orig
.peel_refs() != unsized_ty
{
29 diag
.note(&format
!("the contained type `&{}` has an undefined layout", unsized_ty
));
35 ReducedTys
::ToFatPtr { unsized_ty, .. }
=> {
38 TRANSMUTE_UNDEFINED_REPR
,
40 &format
!("transmute to `{}` which has an undefined layout", to_ty_orig
),
42 if to_ty_orig
.peel_refs() != unsized_ty
{
43 diag
.note(&format
!("the contained type `&{}` has an undefined layout", unsized_ty
));
52 } => match reduce_ty(cx
, from_sub_ty
) {
53 ReducedTy
::UnorderedFields(from_ty
) => {
56 TRANSMUTE_UNDEFINED_REPR
,
58 &format
!("transmute from `{}` which has an undefined layout", from_ty_orig
),
60 if from_ty_orig
.peel_refs() != from_ty
{
61 diag
.note(&format
!("the contained type `{}` has an undefined layout", from_ty
));
67 ReducedTy
::Ref(from_sub_ty
) => {
68 from_ty
= from_sub_ty
;
77 } => match reduce_ty(cx
, to_sub_ty
) {
78 ReducedTy
::UnorderedFields(to_ty
) => {
81 TRANSMUTE_UNDEFINED_REPR
,
83 &format
!("transmute to `{}` which has an undefined layout", to_ty_orig
),
85 if to_ty_orig
.peel_refs() != to_ty
{
86 diag
.note(&format
!("the contained type `{}` has an undefined layout", to_ty
));
92 ReducedTy
::Ref(to_sub_ty
) => {
93 from_ty
= from_sub_ty
;
100 from_ty
: from_sub_ty
,
102 } => match (reduce_ty(cx
, from_sub_ty
), reduce_ty(cx
, to_sub_ty
)) {
103 (ReducedTy
::IntArray
, _
) | (_
, ReducedTy
::IntArray
) => return false,
104 (ReducedTy
::UnorderedFields(from_ty
), ReducedTy
::UnorderedFields(to_ty
)) if from_ty
!= to_ty
=> {
107 TRANSMUTE_UNDEFINED_REPR
,
110 "transmute from `{}` to `{}`, both of which have an undefined layout",
111 from_ty_orig
, to_ty_orig
115 if let (Some(from_def
), Some(to_def
)) = (from_ty
.ty_adt_def(), to_ty
.ty_adt_def());
116 if from_def
== to_def
;
119 "two instances of the same generic type (`{}`) may have different layouts",
120 cx
.tcx
.item_name(from_def
.did
)
123 if from_ty_orig
.peel_refs() != from_ty
{
124 diag
.note(&format
!("the contained type `{}` has an undefined layout", from_ty
));
126 if to_ty_orig
.peel_refs() != to_ty
{
127 diag
.note(&format
!("the contained type `{}` has an undefined layout", to_ty
));
136 ReducedTy
::UnorderedFields(from_ty
),
137 ReducedTy
::Other(_
) | ReducedTy
::OrderedFields(_
) | ReducedTy
::Ref(_
),
141 TRANSMUTE_UNDEFINED_REPR
,
143 &format
!("transmute from `{}` which has an undefined layout", from_ty_orig
),
145 if from_ty_orig
.peel_refs() != from_ty
{
146 diag
.note(&format
!("the contained type `{}` has an undefined layout", from_ty
));
153 ReducedTy
::Other(_
) | ReducedTy
::OrderedFields(_
) | ReducedTy
::Ref(_
),
154 ReducedTy
::UnorderedFields(to_ty
),
158 TRANSMUTE_UNDEFINED_REPR
,
160 &format
!("transmute into `{}` which has an undefined layout", to_ty_orig
),
162 if to_ty_orig
.peel_refs() != to_ty
{
163 diag
.note(&format
!("the contained type `{}` has an undefined layout", to_ty
));
169 (ReducedTy
::Ref(from_sub_ty
), ReducedTy
::Ref(to_sub_ty
)) => {
170 from_ty
= from_sub_ty
;
175 ReducedTy
::OrderedFields(_
) | ReducedTy
::Ref(_
) | ReducedTy
::Other(_
),
176 ReducedTy
::OrderedFields(_
) | ReducedTy
::Ref(_
) | ReducedTy
::Other(_
),
178 | (ReducedTy
::UnorderedFields(_
), ReducedTy
::UnorderedFields(_
)) => break,
186 enum ReducedTys
<'tcx
> {
187 FromFatPtr { unsized_ty: Ty<'tcx> }
,
188 ToFatPtr { unsized_ty: Ty<'tcx> }
,
189 ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }
,
190 FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }
,
191 Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }
,
194 fn reduce_refs
<'tcx
>(
195 cx
: &LateContext
<'tcx
>,
197 mut from_ty
: Ty
<'tcx
>,
199 ) -> ReducedTys
<'tcx
> {
201 return match (from_ty
.kind(), to_ty
.kind()) {
203 &ty
::Ref(_
, from_sub_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: from_sub_ty, .. }
),
204 &ty
::Ref(_
, to_sub_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: to_sub_ty, .. }
),
206 from_ty
= from_sub_ty
;
210 (&ty
::Ref(_
, unsized_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: unsized_ty, .. }
), _
)
211 if !unsized_ty
.is_sized(cx
.tcx
.at(span
), cx
.param_env
) =>
213 ReducedTys
::FromFatPtr { unsized_ty }
215 (_
, &ty
::Ref(_
, unsized_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: unsized_ty, .. }
))
216 if !unsized_ty
.is_sized(cx
.tcx
.at(span
), cx
.param_env
) =>
218 ReducedTys
::ToFatPtr { unsized_ty }
220 (&ty
::Ref(_
, from_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: from_ty, .. }
), _
) => {
221 ReducedTys
::FromPtr { from_ty, to_ty }
223 (_
, &ty
::Ref(_
, to_ty
, _
) | &ty
::RawPtr(TypeAndMut { ty: to_ty, .. }
)) => {
224 ReducedTys
::ToPtr { from_ty, to_ty }
226 _
=> ReducedTys
::Other { from_ty, to_ty }
,
231 enum ReducedTy
<'tcx
> {
232 OrderedFields(Ty
<'tcx
>),
233 UnorderedFields(Ty
<'tcx
>),
239 fn reduce_ty
<'tcx
>(cx
: &LateContext
<'tcx
>, mut ty
: Ty
<'tcx
>) -> ReducedTy
<'tcx
> {
241 ty
= cx
.tcx
.try_normalize_erasing_regions(cx
.param_env
, ty
).unwrap_or(ty
);
242 return match *ty
.kind() {
243 ty
::Array(sub_ty
, _
) if matches
!(sub_ty
.kind(), ty
::Int(_
) | ty
::Uint(_
)) => ReducedTy
::IntArray
,
244 ty
::Array(sub_ty
, _
) | ty
::Slice(sub_ty
) => {
249 let mut iter
= args
.iter().map(GenericArg
::expect_ty
);
250 let Some(sized_ty
) = iter
.find(|ty
| !is_zero_sized_ty(cx
, *ty
)) else {
251 return ReducedTy
::OrderedFields(ty
);
253 if iter
.all(|ty
| is_zero_sized_ty(cx
, ty
)) {
257 ReducedTy
::UnorderedFields(ty
)
259 ty
::Adt(def
, substs
) if def
.is_struct() => {
260 if def
.repr
.inhibit_struct_field_reordering_opt() {
261 return ReducedTy
::OrderedFields(ty
);
267 .map(|f
| cx
.tcx
.type_of(f
.did
).subst(cx
.tcx
, substs
));
268 let Some(sized_ty
) = iter
.find(|ty
| !is_zero_sized_ty(cx
, *ty
)) else {
269 return ReducedTy
::OrderedFields(ty
);
271 if iter
.all(|ty
| is_zero_sized_ty(cx
, ty
)) {
275 ReducedTy
::UnorderedFields(ty
)
277 ty
::Ref(..) | ty
::RawPtr(_
) => ReducedTy
::Ref(ty
),
278 _
=> ReducedTy
::Other(ty
),
283 fn is_zero_sized_ty
<'tcx
>(cx
: &LateContext
<'tcx
>, ty
: Ty
<'tcx
>) -> bool
{
285 if let Ok(ty
) = cx
.tcx
.try_normalize_erasing_regions(cx
.param_env
, ty
);
286 if let Ok(layout
) = cx
.tcx
.layout_of(cx
.param_env
.and(ty
));
288 layout
.layout
.size
.bytes() == 0