Auto merge of #8547 - Jarcho:transmute_8501, r=flip1995
More `transmute_undefined_repr` fixes fixes: #8498 fixes: #8501 fixes: #8503 changelog: Allow `transumte_undefined_repr` between fat pointers and `(usize, usize)` changelog: Allow `transumte_undefined_repr` when one side is a union changelog: Fix `transumte_undefined_repr` on tuples with one non-zero-sized type.
This commit is contained in:
commit
2b0e730bf3
4 changed files with 49 additions and 15 deletions
|
|
@ -415,7 +415,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
|||
// And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
|
||||
let const_context = in_constant(cx, e.hir_id);
|
||||
|
||||
let from_ty = cx.typeck_results().expr_ty(arg);
|
||||
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
|
||||
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
|
||||
let to_ty = cx.typeck_results().expr_ty(e);
|
||||
|
||||
// If useless_transmute is triggered, the other lints can be skipped.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void;
|
|||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
|
|
@ -23,7 +23,8 @@ pub(super) fn check<'tcx>(
|
|||
unsized_ty,
|
||||
to_ty: to_sub_ty,
|
||||
} => match reduce_ty(cx, to_sub_ty) {
|
||||
ReducedTy::IntArray | ReducedTy::TypeErasure => break,
|
||||
ReducedTy::TypeErasure => break,
|
||||
ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
|
||||
ReducedTy::Ref(to_sub_ty) => {
|
||||
from_ty = unsized_ty;
|
||||
to_ty = to_sub_ty;
|
||||
|
|
@ -48,7 +49,8 @@ pub(super) fn check<'tcx>(
|
|||
unsized_ty,
|
||||
from_ty: from_sub_ty,
|
||||
} => match reduce_ty(cx, from_sub_ty) {
|
||||
ReducedTy::IntArray | ReducedTy::TypeErasure => break,
|
||||
ReducedTy::TypeErasure => break,
|
||||
ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
|
||||
ReducedTy::Ref(from_sub_ty) => {
|
||||
from_ty = from_sub_ty;
|
||||
to_ty = unsized_ty;
|
||||
|
|
@ -123,8 +125,7 @@ pub(super) fn check<'tcx>(
|
|||
from_ty: from_sub_ty,
|
||||
to_ty: to_sub_ty,
|
||||
} => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
|
||||
(ReducedTy::IntArray | ReducedTy::TypeErasure, _)
|
||||
| (_, ReducedTy::IntArray | ReducedTy::TypeErasure) => return false,
|
||||
(ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
|
||||
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
@ -263,9 +264,6 @@ enum ReducedTy<'tcx> {
|
|||
UnorderedFields(Ty<'tcx>),
|
||||
/// The type is a reference to the contained type.
|
||||
Ref(Ty<'tcx>),
|
||||
/// The type is an array of a primitive integer type. These can be used as storage for a value
|
||||
/// of another type.
|
||||
IntArray,
|
||||
/// Any other type.
|
||||
Other(Ty<'tcx>),
|
||||
}
|
||||
|
|
@ -275,17 +273,18 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
|
|||
loop {
|
||||
ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
|
||||
return match *ty.kind() {
|
||||
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::IntArray,
|
||||
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure,
|
||||
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
|
||||
ty = sub_ty;
|
||||
continue;
|
||||
},
|
||||
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
|
||||
ty::Tuple(args) => {
|
||||
let Some(sized_ty) = args.iter().find(|&ty| !is_zero_sized_ty(cx, ty)) else {
|
||||
let mut iter = args.iter();
|
||||
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
|
||||
return ReducedTy::OrderedFields(ty);
|
||||
};
|
||||
if args.iter().all(|ty| is_zero_sized_ty(cx, ty)) {
|
||||
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
|
||||
ty = sized_ty;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -313,6 +312,8 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
|
|||
ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
|
||||
ReducedTy::TypeErasure
|
||||
},
|
||||
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
|
||||
ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure,
|
||||
ty::Foreign(_) => ReducedTy::TypeErasure,
|
||||
ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
|
||||
ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
|
||||
|
|
@ -332,3 +333,14 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_size_pair(ty: Ty<'_>) -> bool {
|
||||
if let ty::Tuple(tys) = *ty.kind()
|
||||
&& let [ty1, ty2] = &**tys
|
||||
{
|
||||
matches!(ty1.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
|
||||
&& matches!(ty2.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue