Update tooling
This commit is contained in:
parent
a17ccfa621
commit
dc53c8f25f
15 changed files with 137 additions and 99 deletions
|
@ -770,11 +770,7 @@ fn codegen_stmt<'tcx>(
|
||||||
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
|
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
|
||||||
}
|
}
|
||||||
Rvalue::NullaryOp(null_op, ty) => {
|
Rvalue::NullaryOp(null_op, ty) => {
|
||||||
assert!(
|
assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
|
||||||
lval.layout()
|
|
||||||
.ty
|
|
||||||
.is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
|
|
||||||
);
|
|
||||||
let layout = fx.layout_of(fx.monomorphize(ty));
|
let layout = fx.layout_of(fx.monomorphize(ty));
|
||||||
let val = match null_op {
|
let val = match null_op {
|
||||||
NullOp::SizeOf => layout.size.bytes(),
|
NullOp::SizeOf => layout.size.bytes(),
|
||||||
|
|
|
@ -5,7 +5,6 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{
|
||||||
read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
|
read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
|
||||||
};
|
};
|
||||||
use rustc_span::DUMMY_SP;
|
|
||||||
|
|
||||||
use cranelift_module::*;
|
use cranelift_module::*;
|
||||||
|
|
||||||
|
@ -291,7 +290,7 @@ fn data_id_for_static(
|
||||||
let is_mutable = if tcx.is_mutable_static(def_id) {
|
let is_mutable = if tcx.is_mutable_static(def_id) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
!ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all())
|
!ty.is_freeze(tcx, ParamEnv::reveal_all())
|
||||||
};
|
};
|
||||||
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ where
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
// We are only interested in case the type *doesn't* implement the Sized trait.
|
// We are only interested in case the type *doesn't* implement the Sized trait.
|
||||||
if !ty.is_sized(tcx.at(rustc_span::DUMMY_SP), param_env) {
|
if !ty.is_sized(tcx, param_env) {
|
||||||
// In case `#![no_core]` is used, `sized_trait` returns nothing.
|
// In case `#![no_core]` is used, `sized_trait` returns nothing.
|
||||||
if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
|
if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
|
||||||
self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
|
self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
|
||||||
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
|
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
|
||||||
// The `U` in `pointer::cast` have to be `Sized`
|
// The `U` in `pointer::cast` have to be `Sized`
|
||||||
// as explained here: https://github.com/rust-lang/rust/issues/60602.
|
// as explained here: https://github.com/rust-lang/rust/issues/60602.
|
||||||
if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
|
if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
|
||||||
then {
|
then {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
|
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
|
||||||
|
|
|
@ -29,7 +29,7 @@ use rustc_middle::ty::{
|
||||||
};
|
};
|
||||||
use rustc_semver::RustcVersion;
|
use rustc_semver::RustcVersion;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
|
use rustc_span::{symbol::sym, Span, Symbol};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
|
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -990,7 +990,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
|
||||||
cx.typeck_results().node_type(ty.ty.hir_id),
|
cx.typeck_results().node_type(ty.ty.hir_id),
|
||||||
binder_args,
|
binder_args,
|
||||||
))
|
))
|
||||||
.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1005,7 +1005,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
|
||||||
cx.typeck_results().node_type(ty.ty.hir_id),
|
cx.typeck_results().node_type(ty.ty.hir_id),
|
||||||
binder_args,
|
binder_args,
|
||||||
))
|
))
|
||||||
.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
|
||||||
),
|
),
|
||||||
TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
|
TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
|
||||||
Position::ReborrowStable(precedence)
|
Position::ReborrowStable(precedence)
|
||||||
|
@ -1297,7 +1297,7 @@ impl<'tcx> TyPosition<'tcx> {
|
||||||
fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
|
fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
|
||||||
match (self.position, self.ty) {
|
match (self.position, self.ty) {
|
||||||
(Position::ReborrowStable(precedence), Some(ty)) => {
|
(Position::ReborrowStable(precedence), Some(ty)) => {
|
||||||
Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
|
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
|
||||||
},
|
},
|
||||||
(position, _) => position,
|
(position, _) => position,
|
||||||
}
|
}
|
||||||
|
@ -1348,7 +1348,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
||||||
| ty::Tuple(_)
|
| ty::Tuple(_)
|
||||||
| ty::Projection(_) => Position::DerefStable(
|
| ty::Projection(_) => Position::DerefStable(
|
||||||
precedence,
|
precedence,
|
||||||
ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -188,7 +188,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
|
||||||
// primitive types are never mutable
|
// primitive types are never mutable
|
||||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
|
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
|
||||||
ty::Adt(adt, substs) => {
|
ty::Adt(adt, substs) => {
|
||||||
tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
|
tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
|
||||||
|| KNOWN_WRAPPER_TYS
|
|| KNOWN_WRAPPER_TYS
|
||||||
.iter()
|
.iter()
|
||||||
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
|
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
|
||||||
let span = stmt.span.to(if_.span);
|
let span = stmt.span.to(if_.span);
|
||||||
|
|
||||||
let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
|
let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
|
||||||
cx.tcx.at(span),
|
cx.tcx,
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
);
|
);
|
||||||
if has_interior_mutability { return; }
|
if has_interior_mutability { return; }
|
||||||
|
|
|
@ -136,12 +136,14 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
|
||||||
/// [`Hash`] or [`Ord`].
|
/// [`Hash`] or [`Ord`].
|
||||||
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span),
|
Ref(_, inner_ty, mutbl) => {
|
||||||
|
mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
|
||||||
|
}
|
||||||
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
|
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
|
||||||
Array(inner_ty, size) => {
|
Array(inner_ty, size) => {
|
||||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||||
&& is_interior_mutable_type(cx, inner_ty, span)
|
&& is_interior_mutable_type(cx, inner_ty, span)
|
||||||
},
|
}
|
||||||
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
|
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
|
||||||
Adt(def, substs) => {
|
Adt(def, substs) => {
|
||||||
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
|
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
|
||||||
|
@ -167,9 +169,9 @@ fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Sp
|
||||||
} else {
|
} else {
|
||||||
!ty.has_escaping_bound_vars()
|
!ty.has_escaping_bound_vars()
|
||||||
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
||||||
&& !ty.is_freeze(cx.tcx.at(span), cx.param_env)
|
&& !ty.is_freeze(cx.tcx, cx.param_env)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::{self, TypeVisitable};
|
use rustc_middle::ty::{self, TypeVisitable};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::{sym, Span, DUMMY_SP};
|
use rustc_span::{sym, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::misc::can_type_implement_copy;
|
use rustc_trait_selection::traits::misc::can_type_implement_copy;
|
||||||
|
@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
||||||
if !is_self(arg);
|
if !is_self(arg);
|
||||||
if !ty.is_mutable_ptr();
|
if !ty.is_mutable_ptr();
|
||||||
if !is_copy(cx, ty);
|
if !is_copy(cx, ty);
|
||||||
if ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env);
|
if ty.is_sized(cx.tcx, cx.param_env);
|
||||||
if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
|
if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
|
||||||
if !implements_borrow_trait;
|
if !implements_borrow_trait;
|
||||||
if !all_borrowable_trait;
|
if !all_borrowable_trait;
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
|
||||||
use rustc_middle::ty::adjustment::Adjust;
|
use rustc_middle::ty::adjustment::Adjust;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
|
use rustc_span::{sym, InnerSpan, Span};
|
||||||
|
|
||||||
// FIXME: this is a correctness problem but there's no suitable
|
// FIXME: this is a correctness problem but there's no suitable
|
||||||
// warn-by-default category.
|
// warn-by-default category.
|
||||||
|
@ -136,7 +136,7 @@ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
// since it works when a pointer indirection involves (`Cell<*const T>`).
|
// since it works when a pointer indirection involves (`Cell<*const T>`).
|
||||||
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
|
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
|
||||||
// but I'm not sure whether it's a decent way, if possible.
|
// but I'm not sure whether it's a decent way, if possible.
|
||||||
cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
|
cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_value_unfrozen_raw<'tcx>(
|
fn is_value_unfrozen_raw<'tcx>(
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
|
||||||
then {
|
then {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
|
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
|
||||||
let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx.at(caller.span), cx.param_env) &&
|
let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
|
||||||
!matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
|
!matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
|
||||||
let sugg = if let Some(else_inner) = r#else {
|
let sugg = if let Some(else_inner) = r#else {
|
||||||
if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
|
if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
|
||||||
|
|
|
@ -5,7 +5,6 @@ use rustc_hir::Expr;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::SubstsRef;
|
use rustc_middle::ty::SubstsRef;
|
||||||
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
|
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
|
||||||
use rustc_span::DUMMY_SP;
|
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
pub(super) fn check<'tcx>(
|
pub(super) fn check<'tcx>(
|
||||||
|
@ -28,24 +27,32 @@ pub(super) fn check<'tcx>(
|
||||||
|
|
||||||
// `Repr(C)` <-> unordered type.
|
// `Repr(C)` <-> unordered type.
|
||||||
// If the first field of the `Repr(C)` type matches then the transmute is ok
|
// 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::OrderedFields(_, Some(from_sub_ty)),
|
||||||
|
ReducedTy::UnorderedFields(to_sub_ty),
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
ReducedTy::UnorderedFields(from_sub_ty),
|
||||||
|
ReducedTy::OrderedFields(_, Some(to_sub_ty)),
|
||||||
|
) => {
|
||||||
from_ty = from_sub_ty;
|
from_ty = from_sub_ty;
|
||||||
to_ty = to_sub_ty;
|
to_ty = to_sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
|
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty))
|
||||||
|
if reduced_tys.to_fat_ptr =>
|
||||||
|
{
|
||||||
from_ty = from_sub_ty;
|
from_ty = from_sub_ty;
|
||||||
to_ty = to_sub_ty;
|
to_ty = to_sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
|
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
|
||||||
if reduced_tys.from_fat_ptr =>
|
if reduced_tys.from_fat_ptr =>
|
||||||
{
|
{
|
||||||
from_ty = from_sub_ty;
|
from_ty = from_sub_ty;
|
||||||
to_ty = to_sub_ty;
|
to_ty = to_sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
|
|
||||||
// ptr <-> ptr
|
// ptr <-> ptr
|
||||||
(ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
|
(ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
|
||||||
|
@ -55,19 +62,19 @@ pub(super) fn check<'tcx>(
|
||||||
from_ty = from_sub_ty;
|
from_ty = from_sub_ty;
|
||||||
to_ty = to_sub_ty;
|
to_ty = to_sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
|
|
||||||
// fat ptr <-> (*size, *size)
|
// fat ptr <-> (*size, *size)
|
||||||
(ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
|
(ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
|
||||||
if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
|
if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
(ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
|
(ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
|
||||||
if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
|
if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
// fat ptr -> some struct | some struct -> fat ptr
|
// fat ptr -> some struct | some struct -> fat ptr
|
||||||
(ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
|
(ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
|
||||||
|
@ -78,12 +85,14 @@ pub(super) fn check<'tcx>(
|
||||||
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|
||||||
|diag| {
|
|diag| {
|
||||||
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
|
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
|
||||||
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{from_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
(_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
|
(_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
|
@ -92,14 +101,18 @@ pub(super) fn check<'tcx>(
|
||||||
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|
||||||
|diag| {
|
|diag| {
|
||||||
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
|
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
|
||||||
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{to_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
|
|
||||||
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
|
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty))
|
||||||
|
if from_ty != to_ty =>
|
||||||
|
{
|
||||||
let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
|
let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
|
||||||
= (from_ty.kind(), to_ty.kind())
|
= (from_ty.kind(), to_ty.kind())
|
||||||
&& from_def == to_def
|
&& from_def == to_def
|
||||||
|
@ -126,19 +139,25 @@ pub(super) fn check<'tcx>(
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
if from_ty_orig.peel_refs() != from_ty {
|
if from_ty_orig.peel_refs() != from_ty {
|
||||||
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{from_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if to_ty_orig.peel_refs() != to_ty {
|
if to_ty_orig.peel_refs() != to_ty {
|
||||||
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{to_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
(
|
(
|
||||||
ReducedTy::UnorderedFields(from_ty),
|
ReducedTy::UnorderedFields(from_ty),
|
||||||
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
|
ReducedTy::Other(_)
|
||||||
|
| ReducedTy::OrderedFields(..)
|
||||||
|
| ReducedTy::TypeErasure { raw_ptr_only: true },
|
||||||
) => {
|
) => {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
|
@ -147,14 +166,18 @@ pub(super) fn check<'tcx>(
|
||||||
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|
||||||
|diag| {
|
|diag| {
|
||||||
if from_ty_orig.peel_refs() != from_ty {
|
if from_ty_orig.peel_refs() != from_ty {
|
||||||
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{from_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
(
|
(
|
||||||
ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
|
ReducedTy::Other(_)
|
||||||
|
| ReducedTy::OrderedFields(..)
|
||||||
|
| ReducedTy::TypeErasure { raw_ptr_only: true },
|
||||||
ReducedTy::UnorderedFields(to_ty),
|
ReducedTy::UnorderedFields(to_ty),
|
||||||
) => {
|
) => {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
|
@ -164,19 +187,25 @@ pub(super) fn check<'tcx>(
|
||||||
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|
||||||
|diag| {
|
|diag| {
|
||||||
if to_ty_orig.peel_refs() != to_ty {
|
if to_ty_orig.peel_refs() != to_ty {
|
||||||
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
|
diag.note(&format!(
|
||||||
|
"the contained type `{to_ty}` has an undefined layout"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
(
|
(
|
||||||
ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
|
ReducedTy::OrderedFields(..)
|
||||||
ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
|
| ReducedTy::Other(_)
|
||||||
|
| ReducedTy::TypeErasure { raw_ptr_only: true },
|
||||||
|
ReducedTy::OrderedFields(..)
|
||||||
|
| ReducedTy::Other(_)
|
||||||
|
| ReducedTy::TypeErasure { raw_ptr_only: true },
|
||||||
)
|
)
|
||||||
| (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
|
| (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,10 +223,15 @@ struct ReducedTys<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove references so long as both types are references.
|
/// Remove references so long as both types are references.
|
||||||
fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
|
fn reduce_refs<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
mut from_ty: Ty<'tcx>,
|
||||||
|
mut to_ty: Ty<'tcx>,
|
||||||
|
) -> ReducedTys<'tcx> {
|
||||||
let mut from_raw_ptr = false;
|
let mut from_raw_ptr = false;
|
||||||
let mut to_raw_ptr = false;
|
let mut to_raw_ptr = false;
|
||||||
let (from_fat_ptr, to_fat_ptr) = loop {
|
let (from_fat_ptr, to_fat_ptr) =
|
||||||
|
loop {
|
||||||
break match (from_ty.kind(), to_ty.kind()) {
|
break match (from_ty.kind(), to_ty.kind()) {
|
||||||
(
|
(
|
||||||
&(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
|
&(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
|
||||||
|
@ -208,28 +242,19 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T
|
||||||
to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
|
to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
|
||||||
to_ty = to_sub_ty;
|
to_ty = to_sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
(&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
|
(
|
||||||
if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
|
&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
|
||||||
{
|
_,
|
||||||
(true, false)
|
) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (true, false),
|
||||||
},
|
(
|
||||||
(_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
|
_,
|
||||||
if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
|
&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
|
||||||
{
|
) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (false, true),
|
||||||
(false, true)
|
|
||||||
},
|
|
||||||
_ => (false, false),
|
_ => (false, false),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ReducedTys {
|
ReducedTys { from_ty, to_ty, from_raw_ptr, to_raw_ptr, from_fat_ptr, to_fat_ptr }
|
||||||
from_ty,
|
|
||||||
to_ty,
|
|
||||||
from_raw_ptr,
|
|
||||||
to_raw_ptr,
|
|
||||||
from_fat_ptr,
|
|
||||||
to_fat_ptr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ReducedTy<'tcx> {
|
enum ReducedTy<'tcx> {
|
||||||
|
@ -252,11 +277,11 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
|
||||||
return match *ty.kind() {
|
return match *ty.kind() {
|
||||||
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
|
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
|
||||||
ReducedTy::TypeErasure { raw_ptr_only: false }
|
ReducedTy::TypeErasure { raw_ptr_only: false }
|
||||||
},
|
}
|
||||||
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
|
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
|
||||||
ty = sub_ty;
|
ty = sub_ty;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
|
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
|
||||||
ty::Tuple(args) => {
|
ty::Tuple(args) => {
|
||||||
let mut iter = args.iter();
|
let mut iter = args.iter();
|
||||||
|
@ -268,7 +293,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ReducedTy::UnorderedFields(ty)
|
ReducedTy::UnorderedFields(ty)
|
||||||
},
|
}
|
||||||
ty::Adt(def, substs) if def.is_struct() => {
|
ty::Adt(def, substs) if def.is_struct() => {
|
||||||
let mut iter = def
|
let mut iter = def
|
||||||
.non_enum_variant()
|
.non_enum_variant()
|
||||||
|
@ -287,10 +312,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
|
||||||
} else {
|
} else {
|
||||||
ReducedTy::UnorderedFields(ty)
|
ReducedTy::UnorderedFields(ty)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
|
ty::Adt(def, _)
|
||||||
|
if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) =>
|
||||||
|
{
|
||||||
ReducedTy::TypeErasure { raw_ptr_only: false }
|
ReducedTy::TypeErasure { raw_ptr_only: false }
|
||||||
},
|
}
|
||||||
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
|
// 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 { raw_ptr_only: false },
|
ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
|
||||||
ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
|
ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
|
||||||
|
@ -329,7 +356,11 @@ fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> b
|
||||||
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
|
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
|
||||||
match (ty1.kind(), ty2.kind()) {
|
match (ty1.kind(), ty2.kind()) {
|
||||||
(ty::Param(_), _) | (_, ty::Param(_)) => (),
|
(ty::Param(_), _) | (_, ty::Param(_)) => (),
|
||||||
(ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
|
(ty::Adt(adt1, subs1), ty::Adt(adt2, subs2))
|
||||||
|
if adt1 == adt2 && same_except_params(subs1, subs2) =>
|
||||||
|
{
|
||||||
|
()
|
||||||
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,12 @@ use rustc_span::symbol::sym;
|
||||||
|
|
||||||
use super::{utils, REDUNDANT_ALLOCATION};
|
use super::{utils, REDUNDANT_ALLOCATION};
|
||||||
|
|
||||||
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
|
pub(super) fn check(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
hir_ty: &hir::Ty<'_>,
|
||||||
|
qpath: &QPath<'_>,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> bool {
|
||||||
let mut applicability = Applicability::MaybeIncorrect;
|
let mut applicability = Applicability::MaybeIncorrect;
|
||||||
let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
|
let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
|
||||||
"Box"
|
"Box"
|
||||||
|
@ -29,7 +34,12 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||||
hir_ty.span,
|
hir_ty.span,
|
||||||
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|
||||||
|diag| {
|
|diag| {
|
||||||
diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
|
diag.span_suggestion(
|
||||||
|
hir_ty.span,
|
||||||
|
"try",
|
||||||
|
format!("{generic_snippet}"),
|
||||||
|
applicability,
|
||||||
|
);
|
||||||
diag.note(&format!(
|
diag.note(&format!(
|
||||||
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
|
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
|
||||||
));
|
));
|
||||||
|
@ -55,11 +65,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||||
// Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
|
// Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
|
||||||
// here because `mod.rs` guarantees this lint is only run on types outside of bodies and
|
// here because `mod.rs` guarantees this lint is only run on types outside of bodies and
|
||||||
// is not run on locals.
|
// is not run on locals.
|
||||||
if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx.at(ty.span), cx.param_env) {
|
if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ty.span
|
ty.span
|
||||||
},
|
}
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
if inner_sym == outer_sym {
|
if inner_sym == outer_sym {
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub(super) fn check(
|
||||||
});
|
});
|
||||||
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
|
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
|
||||||
if !ty_ty.has_escaping_bound_vars();
|
if !ty_ty.has_escaping_bound_vars();
|
||||||
if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
|
if ty_ty.is_sized(cx.tcx, cx.param_env);
|
||||||
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
|
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
|
||||||
if ty_ty_size <= box_size_threshold;
|
if ty_ty_size <= box_size_threshold;
|
||||||
then {
|
then {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use rustc_middle::ty::{
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
use rustc_span::{sym, Span, Symbol};
|
||||||
use rustc_target::abi::{Size, VariantIdx};
|
use rustc_target::abi::{Size, VariantIdx};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||||
|
@ -28,7 +28,7 @@ use crate::{match_def_path, path_res, paths};
|
||||||
|
|
||||||
// Checks if the given type implements copy.
|
// Checks if the given type implements copy.
|
||||||
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
|
ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This checks whether a given type is known to implement Debug.
|
/// This checks whether a given type is known to implement Debug.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue