Rollup merge of #141551 - compiler-errors:hir-lints, r=BoxyUwU
Make two transmute-related MIR lints into HIR lint Make `PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS` (rust-lang/rust#130540) and `UNNECESSARY_TRANSMUTES` (rust-lang/rust#136083) into "normal" HIR-based lints. Funny enough this came up in the review of the latter (https://github.com/rust-lang/rust/pull/136083#issuecomment-2614301413), but I guess it just was overlooked. But anywyas, there's no reason for these to be MIR lints; in fact, it makes the suggestions for them a bit more complicated than necessary. Note that there's probably a few more simplifications and improvements to be done here. Follow-ups can be done in a separate PR, especially if they're about the messaging and suggestions themselves, which I didn't write.
This commit is contained in:
@@ -807,6 +807,11 @@ lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're
|
|||||||
lint_type_ir_trait_usage = do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver
|
lint_type_ir_trait_usage = do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver
|
||||||
.note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler
|
.note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler
|
||||||
|
|
||||||
|
lint_undefined_transmute = pointers cannot be transmuted to integers during const eval
|
||||||
|
.note = at compile-time, pointers do not have an integer value
|
||||||
|
.note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
||||||
|
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
|
|
||||||
lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing
|
lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing
|
||||||
.label = argument has type `{$arg_ty}`
|
.label = argument has type `{$arg_ty}`
|
||||||
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ mod reference_casting;
|
|||||||
mod shadowed_into_iter;
|
mod shadowed_into_iter;
|
||||||
mod static_mut_refs;
|
mod static_mut_refs;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
mod transmute;
|
||||||
mod types;
|
mod types;
|
||||||
mod unit_bindings;
|
mod unit_bindings;
|
||||||
mod unqualified_local_imports;
|
mod unqualified_local_imports;
|
||||||
@@ -118,6 +119,7 @@ use shadowed_into_iter::ShadowedIntoIter;
|
|||||||
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
|
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
|
||||||
use static_mut_refs::*;
|
use static_mut_refs::*;
|
||||||
use traits::*;
|
use traits::*;
|
||||||
|
use transmute::CheckTransmutes;
|
||||||
use types::*;
|
use types::*;
|
||||||
use unit_bindings::*;
|
use unit_bindings::*;
|
||||||
use unqualified_local_imports::*;
|
use unqualified_local_imports::*;
|
||||||
@@ -246,6 +248,7 @@ late_lint_methods!(
|
|||||||
IfLetRescope: IfLetRescope::default(),
|
IfLetRescope: IfLetRescope::default(),
|
||||||
StaticMutRefs: StaticMutRefs,
|
StaticMutRefs: StaticMutRefs,
|
||||||
UnqualifiedLocalImports: UnqualifiedLocalImports,
|
UnqualifiedLocalImports: UnqualifiedLocalImports,
|
||||||
|
CheckTransmutes: CheckTransmutes,
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
278
compiler/rustc_lint/src/transmute.rs
Normal file
278
compiler/rustc_lint/src/transmute.rs
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
use rustc_hir::{self as hir};
|
||||||
|
use rustc_macros::LintDiagnostic;
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_session::{declare_lint, impl_lint_pass};
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
use crate::{LateContext, LateLintPass};
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
|
||||||
|
/// transmute in const functions and associated constants.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// const fn foo(ptr: *const u8) -> usize {
|
||||||
|
/// unsafe {
|
||||||
|
/// std::mem::transmute::<*const u8, usize>(ptr)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Transmuting pointers to integers in a `const` context is undefined behavior.
|
||||||
|
/// Any attempt to use the resulting integer will abort const-evaluation.
|
||||||
|
///
|
||||||
|
/// But sometimes the compiler might not emit an error for pointer to integer transmutes
|
||||||
|
/// inside const functions and associated consts because they are evaluated only when referenced.
|
||||||
|
/// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior
|
||||||
|
/// from compiling without any warnings or errors.
|
||||||
|
///
|
||||||
|
/// See [std::mem::transmute] in the reference for more details.
|
||||||
|
///
|
||||||
|
/// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
|
pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
||||||
|
Warn,
|
||||||
|
"detects pointer to integer transmutes in const functions and associated constants",
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn bytes_at_home(x: [u8; 4]) -> u32 {
|
||||||
|
/// unsafe { std::mem::transmute(x) }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Using an explicit method is preferable over calls to
|
||||||
|
/// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as
|
||||||
|
/// they more clearly communicate the intent, are easier to review, and
|
||||||
|
/// are less likely to accidentally result in unsoundness.
|
||||||
|
pub UNNECESSARY_TRANSMUTES,
|
||||||
|
Warn,
|
||||||
|
"detects transmutes that can also be achieved by other operations"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CheckTransmutes;
|
||||||
|
|
||||||
|
impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for CheckTransmutes {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
|
let hir::ExprKind::Call(callee, [arg]) = expr.kind else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let hir::ExprKind::Path(qpath) = callee.kind else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Res::Def(DefKind::Fn, def_id) = cx.qpath_res(&qpath, callee.hir_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if !cx.tcx.is_intrinsic(def_id, sym::transmute) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let body_owner_def_id = cx.tcx.hir_enclosing_body_owner(expr.hir_id);
|
||||||
|
let const_context = cx.tcx.hir_body_const_context(body_owner_def_id);
|
||||||
|
let args = cx.typeck_results().node_args(callee.hir_id);
|
||||||
|
|
||||||
|
let src = args.type_at(0);
|
||||||
|
let dst = args.type_at(1);
|
||||||
|
|
||||||
|
check_ptr_transmute_in_const(cx, expr, body_owner_def_id, const_context, src, dst);
|
||||||
|
check_unnecessary_transmute(cx, expr, callee, arg, const_context, src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check for transmutes that exhibit undefined behavior.
|
||||||
|
/// For example, transmuting pointers to integers in a const context.
|
||||||
|
///
|
||||||
|
/// Why do we consider const functions and associated constants only?
|
||||||
|
///
|
||||||
|
/// Generally, undefined behavior in const items are handled by the evaluator.
|
||||||
|
/// But, const functions and associated constants are evaluated only when referenced.
|
||||||
|
/// This can result in undefined behavior in a library going unnoticed until
|
||||||
|
/// the function or constant is actually used.
|
||||||
|
///
|
||||||
|
/// Therefore, we only consider const functions and associated constants here and leave
|
||||||
|
/// other const items to be handled by the evaluator.
|
||||||
|
fn check_ptr_transmute_in_const<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
body_owner_def_id: LocalDefId,
|
||||||
|
const_context: Option<hir::ConstContext>,
|
||||||
|
src: Ty<'tcx>,
|
||||||
|
dst: Ty<'tcx>,
|
||||||
|
) {
|
||||||
|
if matches!(const_context, Some(hir::ConstContext::ConstFn))
|
||||||
|
|| matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst)
|
||||||
|
{
|
||||||
|
if src.is_raw_ptr() && dst.is_integral() {
|
||||||
|
cx.tcx.emit_node_span_lint(
|
||||||
|
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
||||||
|
expr.hir_id,
|
||||||
|
expr.span,
|
||||||
|
UndefinedTransmuteLint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check for transmutes that overlap with stdlib methods.
|
||||||
|
/// For example, transmuting `[u8; 4]` to `u32`.
|
||||||
|
///
|
||||||
|
/// We chose not to lint u8 -> bool transmutes, see #140431.
|
||||||
|
fn check_unnecessary_transmute<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
callee: &'tcx hir::Expr<'tcx>,
|
||||||
|
arg: &'tcx hir::Expr<'tcx>,
|
||||||
|
const_context: Option<hir::ConstContext>,
|
||||||
|
src: Ty<'tcx>,
|
||||||
|
dst: Ty<'tcx>,
|
||||||
|
) {
|
||||||
|
let callee_span = callee.span.find_ancestor_inside(expr.span).unwrap_or(callee.span);
|
||||||
|
let (sugg, help) = match (src.kind(), dst.kind()) {
|
||||||
|
// dont check the length; transmute does that for us.
|
||||||
|
// [u8; _] => primitive
|
||||||
|
(ty::Array(t, _), ty::Uint(_) | ty::Float(_) | ty::Int(_))
|
||||||
|
if *t.kind() == ty::Uint(ty::UintTy::U8) =>
|
||||||
|
{
|
||||||
|
(
|
||||||
|
Some(vec![(callee_span, format!("{dst}::from_ne_bytes"))]),
|
||||||
|
Some(
|
||||||
|
"there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// primitive => [u8; _]
|
||||||
|
(ty::Uint(_) | ty::Float(_) | ty::Int(_), ty::Array(t, _))
|
||||||
|
if *t.kind() == ty::Uint(ty::UintTy::U8) =>
|
||||||
|
{
|
||||||
|
(
|
||||||
|
Some(vec![(callee_span, format!("{src}::to_ne_bytes"))]),
|
||||||
|
Some(
|
||||||
|
"there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// char → u32
|
||||||
|
(ty::Char, ty::Uint(ty::UintTy::U32)) => {
|
||||||
|
(Some(vec![(callee_span, "u32::from".to_string())]), None)
|
||||||
|
}
|
||||||
|
// char (→ u32) → i32
|
||||||
|
(ty::Char, ty::Int(ty::IntTy::I32)) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, "u32::from".to_string()),
|
||||||
|
(expr.span.shrink_to_hi(), ".cast_signed()".to_string()),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// u32 → char
|
||||||
|
(ty::Uint(ty::UintTy::U32), ty::Char) => (
|
||||||
|
Some(vec![(callee_span, "char::from_u32_unchecked".to_string())]),
|
||||||
|
Some("consider using `char::from_u32(…).unwrap()`"),
|
||||||
|
),
|
||||||
|
// i32 → char
|
||||||
|
(ty::Int(ty::IntTy::I32), ty::Char) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, "char::from_u32_unchecked(i32::cast_unsigned".to_string()),
|
||||||
|
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||||
|
]),
|
||||||
|
Some("consider using `char::from_u32(i32::cast_unsigned(…)).unwrap()`"),
|
||||||
|
),
|
||||||
|
// uNN → iNN
|
||||||
|
(ty::Uint(_), ty::Int(_)) => {
|
||||||
|
(Some(vec![(callee_span, format!("{src}::cast_signed"))]), None)
|
||||||
|
}
|
||||||
|
// iNN → uNN
|
||||||
|
(ty::Int(_), ty::Uint(_)) => {
|
||||||
|
(Some(vec![(callee_span, format!("{src}::cast_unsigned"))]), None)
|
||||||
|
}
|
||||||
|
// fNN → usize, isize
|
||||||
|
(ty::Float(_), ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize)) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, format!("{src}::to_bits")),
|
||||||
|
(expr.span.shrink_to_hi(), format!(" as {dst}")),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// fNN (→ uNN) → iNN
|
||||||
|
(ty::Float(_), ty::Int(..)) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, format!("{src}::to_bits")),
|
||||||
|
(expr.span.shrink_to_hi(), ".cast_signed()".to_string()),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// fNN → uNN
|
||||||
|
(ty::Float(_), ty::Uint(..)) => {
|
||||||
|
(Some(vec![(callee_span, format!("{src}::to_bits"))]), None)
|
||||||
|
}
|
||||||
|
// xsize → fNN
|
||||||
|
(ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize), ty::Float(_)) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, format!("{dst}::from_bits")),
|
||||||
|
(arg.span.shrink_to_hi(), " as _".to_string()),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// iNN (→ uNN) → fNN
|
||||||
|
(ty::Int(_), ty::Float(_)) => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, format!("{dst}::from_bits({src}::cast_unsigned")),
|
||||||
|
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// uNN → fNN
|
||||||
|
(ty::Uint(_), ty::Float(_)) => {
|
||||||
|
(Some(vec![(callee_span, format!("{dst}::from_bits"))]), None)
|
||||||
|
}
|
||||||
|
// bool → x8 in const context since `From::from` is not const yet
|
||||||
|
// FIXME: Consider arg expr's precedence to avoid parentheses.
|
||||||
|
// FIXME(const_traits): Remove this when `From::from` is constified.
|
||||||
|
(ty::Bool, ty::Int(..) | ty::Uint(..)) if const_context.is_some() => (
|
||||||
|
Some(vec![
|
||||||
|
(callee_span, "".to_string()),
|
||||||
|
(expr.span.shrink_to_hi(), format!(" as {dst}")),
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// bool → x8 using `x8::from`
|
||||||
|
(ty::Bool, ty::Int(..) | ty::Uint(..)) => {
|
||||||
|
(Some(vec![(callee_span, format!("{dst}::from"))]), None)
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.tcx.node_span_lint(UNNECESSARY_TRANSMUTES, expr.hir_id, expr.span, |diag| {
|
||||||
|
diag.primary_message("unnecessary transmute");
|
||||||
|
if let Some(sugg) = sugg {
|
||||||
|
diag.multipart_suggestion("replace this with", sugg, Applicability::MachineApplicable);
|
||||||
|
}
|
||||||
|
if let Some(help) = help {
|
||||||
|
diag.help(help);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_undefined_transmute)]
|
||||||
|
#[note]
|
||||||
|
#[note(lint_note2)]
|
||||||
|
#[help]
|
||||||
|
pub(crate) struct UndefinedTransmuteLint;
|
||||||
@@ -79,7 +79,6 @@ declare_lint_pass! {
|
|||||||
PRIVATE_BOUNDS,
|
PRIVATE_BOUNDS,
|
||||||
PRIVATE_INTERFACES,
|
PRIVATE_INTERFACES,
|
||||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||||
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
|
||||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||||
REDUNDANT_IMPORTS,
|
REDUNDANT_IMPORTS,
|
||||||
REDUNDANT_LIFETIMES,
|
REDUNDANT_LIFETIMES,
|
||||||
@@ -118,7 +117,6 @@ declare_lint_pass! {
|
|||||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
UNNAMEABLE_TEST_ITEMS,
|
UNNAMEABLE_TEST_ITEMS,
|
||||||
UNNAMEABLE_TYPES,
|
UNNAMEABLE_TYPES,
|
||||||
UNNECESSARY_TRANSMUTES,
|
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
UNREACHABLE_PATTERNS,
|
UNREACHABLE_PATTERNS,
|
||||||
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||||
@@ -4851,64 +4849,6 @@ declare_lint! {
|
|||||||
@feature_gate = supertrait_item_shadowing;
|
@feature_gate = supertrait_item_shadowing;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
|
|
||||||
/// transmute in const functions and associated constants.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// const fn foo(ptr: *const u8) -> usize {
|
|
||||||
/// unsafe {
|
|
||||||
/// std::mem::transmute::<*const u8, usize>(ptr)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// Transmuting pointers to integers in a `const` context is undefined behavior.
|
|
||||||
/// Any attempt to use the resulting integer will abort const-evaluation.
|
|
||||||
///
|
|
||||||
/// But sometimes the compiler might not emit an error for pointer to integer transmutes
|
|
||||||
/// inside const functions and associated consts because they are evaluated only when referenced.
|
|
||||||
/// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior
|
|
||||||
/// from compiling without any warnings or errors.
|
|
||||||
///
|
|
||||||
/// See [std::mem::transmute] in the reference for more details.
|
|
||||||
///
|
|
||||||
/// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html
|
|
||||||
pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
|
||||||
Warn,
|
|
||||||
"detects pointer to integer transmutes in const functions and associated constants",
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// fn bytes_at_home(x: [u8; 4]) -> u32 {
|
|
||||||
/// unsafe { std::mem::transmute(x) }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// Using an explicit method is preferable over calls to
|
|
||||||
/// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as
|
|
||||||
/// they more clearly communicate the intent, are easier to review, and
|
|
||||||
/// are less likely to accidentally result in unsoundness.
|
|
||||||
pub UNNECESSARY_TRANSMUTES,
|
|
||||||
Warn,
|
|
||||||
"detects transmutes that are shadowed by std methods"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
|
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
|
||||||
/// that runs a custom `Drop` destructor.
|
/// that runs a custom `Drop` destructor.
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
/// This should only be used for determining the context of a body, a return
|
/// This should only be used for determining the context of a body, a return
|
||||||
/// value of `Some` does not always suggest that the owner of the body is `const`,
|
/// value of `Some` does not always suggest that the owner of the body is `const`,
|
||||||
/// just that it has to be checked as if it were.
|
/// just that it has to be checked as if it were.
|
||||||
pub fn hir_body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstContext> {
|
pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
|
||||||
let def_id = def_id.into();
|
let def_id = def_id.into();
|
||||||
let ccx = match self.hir_body_owner_kind(def_id) {
|
let ccx = match self.hir_body_owner_kind(def_id) {
|
||||||
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
|
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
|
||||||
|
|||||||
@@ -1624,7 +1624,11 @@ pub fn write_allocations<'tcx>(
|
|||||||
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
||||||
write!(w, " (static: {}", tcx.def_path_str(did))?;
|
write!(w, " (static: {}", tcx.def_path_str(did))?;
|
||||||
if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)
|
if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)
|
||||||
&& tcx.hir_body_const_context(body.source.def_id()).is_some()
|
&& body
|
||||||
|
.source
|
||||||
|
.def_id()
|
||||||
|
.as_local()
|
||||||
|
.is_some_and(|def_id| tcx.hir_body_const_context(def_id).is_some())
|
||||||
{
|
{
|
||||||
// Statics may be cyclic and evaluating them too early
|
// Statics may be cyclic and evaluating them too early
|
||||||
// in the MIR pipeline may cause cycle errors even though
|
// in the MIR pipeline may cause cycle errors even though
|
||||||
|
|||||||
@@ -78,10 +78,4 @@ mir_transform_unconditional_recursion = function cannot return without recursing
|
|||||||
|
|
||||||
mir_transform_unconditional_recursion_call_site_label = recursive call site
|
mir_transform_unconditional_recursion_call_site_label = recursive call site
|
||||||
|
|
||||||
mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval
|
|
||||||
.note = at compile-time, pointers do not have an integer value
|
|
||||||
.note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
|
||||||
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
|
||||||
|
|
||||||
mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
|
mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
|
||||||
mir_transform_unnecessary_transmute = unnecessary transmute
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
use rustc_middle::mir::visit::Visitor;
|
|
||||||
use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind};
|
|
||||||
use rustc_middle::ty::{AssocItem, AssocKind, TyCtxt};
|
|
||||||
use rustc_session::lint::builtin::PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS;
|
|
||||||
use rustc_span::sym;
|
|
||||||
|
|
||||||
use crate::errors;
|
|
||||||
|
|
||||||
/// Check for transmutes that exhibit undefined behavior.
|
|
||||||
/// For example, transmuting pointers to integers in a const context.
|
|
||||||
pub(super) struct CheckUndefinedTransmutes;
|
|
||||||
|
|
||||||
impl<'tcx> crate::MirLint<'tcx> for CheckUndefinedTransmutes {
|
|
||||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
|
||||||
let mut checker = UndefinedTransmutesChecker { body, tcx };
|
|
||||||
checker.visit_body(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UndefinedTransmutesChecker<'a, 'tcx> {
|
|
||||||
body: &'a Body<'tcx>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> {
|
|
||||||
// This functions checks two things:
|
|
||||||
// 1. `function` takes a raw pointer as input and returns an integer as output.
|
|
||||||
// 2. `function` is called from a const function or an associated constant.
|
|
||||||
//
|
|
||||||
// Why do we consider const functions and associated constants only?
|
|
||||||
//
|
|
||||||
// Generally, undefined behavior in const items are handled by the evaluator.
|
|
||||||
// But, const functions and associated constants are evaluated only when referenced.
|
|
||||||
// This can result in undefined behavior in a library going unnoticed until
|
|
||||||
// the function or constant is actually used.
|
|
||||||
//
|
|
||||||
// Therefore, we only consider const functions and associated constants here and leave
|
|
||||||
// other const items to be handled by the evaluator.
|
|
||||||
fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool {
|
|
||||||
let def_id = self.body.source.def_id();
|
|
||||||
|
|
||||||
if self.tcx.is_const_fn(def_id)
|
|
||||||
|| matches!(
|
|
||||||
self.tcx.opt_associated_item(def_id),
|
|
||||||
Some(AssocItem { kind: AssocKind::Const { .. }, .. })
|
|
||||||
)
|
|
||||||
{
|
|
||||||
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
|
||||||
if let [input] = fn_sig.inputs() {
|
|
||||||
return input.is_raw_ptr() && fn_sig.output().is_integral();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for UndefinedTransmutesChecker<'_, 'tcx> {
|
|
||||||
// Check each block's terminator for calls to pointer to integer transmutes
|
|
||||||
// in const functions or associated constants and emit a lint.
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
|
||||||
if let TerminatorKind::Call { func, .. } = &terminator.kind
|
|
||||||
&& let Some((func_def_id, _)) = func.const_fn_def()
|
|
||||||
&& self.tcx.is_intrinsic(func_def_id, sym::transmute)
|
|
||||||
&& self.is_ptr_to_int_in_const(func)
|
|
||||||
&& let Some(call_id) = self.body.source.def_id().as_local()
|
|
||||||
{
|
|
||||||
let hir_id = self.tcx.local_def_id_to_hir_id(call_id);
|
|
||||||
let span = self.body.source_info(location).span;
|
|
||||||
self.tcx.emit_node_span_lint(
|
|
||||||
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
|
||||||
hir_id,
|
|
||||||
span,
|
|
||||||
errors::UndefinedTransmute,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
use rustc_middle::mir::visit::Visitor;
|
|
||||||
use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind};
|
|
||||||
use rustc_middle::ty::*;
|
|
||||||
use rustc_session::lint::builtin::UNNECESSARY_TRANSMUTES;
|
|
||||||
use rustc_span::source_map::Spanned;
|
|
||||||
use rustc_span::{Span, sym};
|
|
||||||
|
|
||||||
use crate::errors::UnnecessaryTransmute as Error;
|
|
||||||
|
|
||||||
/// Check for transmutes that overlap with stdlib methods.
|
|
||||||
/// For example, transmuting `[u8; 4]` to `u32`.
|
|
||||||
/// We chose not to lint u8 -> bool transmutes, see #140431
|
|
||||||
pub(super) struct CheckUnnecessaryTransmutes;
|
|
||||||
|
|
||||||
impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes {
|
|
||||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
|
||||||
let mut checker = UnnecessaryTransmuteChecker { body, tcx };
|
|
||||||
checker.visit_body(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UnnecessaryTransmuteChecker<'a, 'tcx> {
|
|
||||||
body: &'a Body<'tcx>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
|
|
||||||
fn is_unnecessary_transmute(
|
|
||||||
&self,
|
|
||||||
function: &Operand<'tcx>,
|
|
||||||
arg: String,
|
|
||||||
span: Span,
|
|
||||||
is_in_const: bool,
|
|
||||||
) -> Option<Error> {
|
|
||||||
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
|
||||||
let [input] = fn_sig.inputs() else { return None };
|
|
||||||
|
|
||||||
let err = |sugg| Error { span, sugg, help: None };
|
|
||||||
|
|
||||||
Some(match (input.kind(), fn_sig.output().kind()) {
|
|
||||||
// dont check the length; transmute does that for us.
|
|
||||||
// [u8; _] => primitive
|
|
||||||
(Array(t, _), Uint(_) | Float(_) | Int(_)) if *t.kind() == Uint(UintTy::U8) => Error {
|
|
||||||
sugg: format!("{}::from_ne_bytes({arg})", fn_sig.output()),
|
|
||||||
help: Some(
|
|
||||||
"there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order",
|
|
||||||
),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
// primitive => [u8; _]
|
|
||||||
(Uint(_) | Float(_) | Int(_), Array(t, _)) if *t.kind() == Uint(UintTy::U8) => Error {
|
|
||||||
sugg: format!("{input}::to_ne_bytes({arg})"),
|
|
||||||
help: Some(
|
|
||||||
"there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order",
|
|
||||||
),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
// char → u32
|
|
||||||
(Char, Uint(UintTy::U32)) => err(format!("u32::from({arg})")),
|
|
||||||
// char (→ u32) → i32
|
|
||||||
(Char, Int(IntTy::I32)) => err(format!("u32::from({arg}).cast_signed()")),
|
|
||||||
// u32 → char
|
|
||||||
(Uint(UintTy::U32), Char) => Error {
|
|
||||||
sugg: format!("char::from_u32_unchecked({arg})"),
|
|
||||||
help: Some("consider `char::from_u32(…).unwrap()`"),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
// i32 → char
|
|
||||||
(Int(IntTy::I32), Char) => Error {
|
|
||||||
sugg: format!("char::from_u32_unchecked(i32::cast_unsigned({arg}))"),
|
|
||||||
help: Some("consider `char::from_u32(i32::cast_unsigned(…)).unwrap()`"),
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
// uNN → iNN
|
|
||||||
(Uint(ty), Int(_)) => err(format!("{}::cast_signed({arg})", ty.name_str())),
|
|
||||||
// iNN → uNN
|
|
||||||
(Int(ty), Uint(_)) => err(format!("{}::cast_unsigned({arg})", ty.name_str())),
|
|
||||||
// fNN → xsize
|
|
||||||
(Float(ty), Uint(UintTy::Usize)) => {
|
|
||||||
err(format!("{}::to_bits({arg}) as usize", ty.name_str()))
|
|
||||||
}
|
|
||||||
(Float(ty), Int(IntTy::Isize)) => {
|
|
||||||
err(format!("{}::to_bits({arg}) as isize", ty.name_str()))
|
|
||||||
}
|
|
||||||
// fNN (→ uNN) → iNN
|
|
||||||
(Float(ty), Int(..)) => err(format!("{}::to_bits({arg}).cast_signed()", ty.name_str())),
|
|
||||||
// fNN → uNN
|
|
||||||
(Float(ty), Uint(..)) => err(format!("{}::to_bits({arg})", ty.name_str())),
|
|
||||||
// xsize → fNN
|
|
||||||
(Uint(UintTy::Usize) | Int(IntTy::Isize), Float(ty)) => {
|
|
||||||
err(format!("{}::from_bits({arg} as _)", ty.name_str(),))
|
|
||||||
}
|
|
||||||
// iNN (→ uNN) → fNN
|
|
||||||
(Int(int_ty), Float(ty)) => err(format!(
|
|
||||||
"{}::from_bits({}::cast_unsigned({arg}))",
|
|
||||||
ty.name_str(),
|
|
||||||
int_ty.name_str()
|
|
||||||
)),
|
|
||||||
// uNN → fNN
|
|
||||||
(Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())),
|
|
||||||
// bool → { x8 } in const context since `From::from` is not const yet
|
|
||||||
// FIXME: is it possible to know when the parentheses arent necessary?
|
|
||||||
// FIXME(const_traits): Remove this when From::from is constified?
|
|
||||||
(Bool, Int(..) | Uint(..)) if is_in_const => {
|
|
||||||
err(format!("({arg}) as {}", fn_sig.output()))
|
|
||||||
}
|
|
||||||
// " using `x8::from`
|
|
||||||
(Bool, Int(..) | Uint(..)) => err(format!("{}::from({arg})", fn_sig.output())),
|
|
||||||
_ => return None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> {
|
|
||||||
// Check each block's terminator for calls to pointer to integer transmutes
|
|
||||||
// in const functions or associated constants and emit a lint.
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
|
||||||
if let TerminatorKind::Call { func, args, .. } = &terminator.kind
|
|
||||||
&& let [Spanned { span: arg, .. }] = **args
|
|
||||||
&& let Some((func_def_id, _)) = func.const_fn_def()
|
|
||||||
&& self.tcx.is_intrinsic(func_def_id, sym::transmute)
|
|
||||||
&& let span = self.body.source_info(location).span
|
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg)
|
|
||||||
&& let def_id = self.body.source.def_id()
|
|
||||||
&& let Some(lint) = self.is_unnecessary_transmute(
|
|
||||||
func,
|
|
||||||
snippet,
|
|
||||||
span,
|
|
||||||
self.tcx.hir_body_const_context(def_id.expect_local()).is_some(),
|
|
||||||
)
|
|
||||||
&& let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes)
|
|
||||||
{
|
|
||||||
self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -158,33 +158,6 @@ pub(crate) struct MustNotSuspendReason {
|
|||||||
pub reason: String,
|
pub reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct UnnecessaryTransmute {
|
|
||||||
pub span: Span,
|
|
||||||
pub sugg: String,
|
|
||||||
pub help: Option<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed for def_path_str
|
|
||||||
impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute {
|
|
||||||
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
|
||||||
diag.primary_message(fluent::mir_transform_unnecessary_transmute);
|
|
||||||
diag.span_suggestion(
|
|
||||||
self.span,
|
|
||||||
"replace this with",
|
|
||||||
self.sugg,
|
|
||||||
lint::Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
self.help.map(|help| diag.help(help));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(mir_transform_undefined_transmute)]
|
|
||||||
#[note]
|
|
||||||
#[note(mir_transform_note2)]
|
|
||||||
#[help]
|
|
||||||
pub(crate) struct UndefinedTransmute;
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(mir_transform_force_inline)]
|
#[diag(mir_transform_force_inline)]
|
||||||
#[note]
|
#[note]
|
||||||
|
|||||||
@@ -123,8 +123,6 @@ declare_passes! {
|
|||||||
mod check_const_item_mutation : CheckConstItemMutation;
|
mod check_const_item_mutation : CheckConstItemMutation;
|
||||||
mod check_null : CheckNull;
|
mod check_null : CheckNull;
|
||||||
mod check_packed_ref : CheckPackedRef;
|
mod check_packed_ref : CheckPackedRef;
|
||||||
mod check_undefined_transmutes : CheckUndefinedTransmutes;
|
|
||||||
mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes;
|
|
||||||
// This pass is public to allow external drivers to perform MIR cleanup
|
// This pass is public to allow external drivers to perform MIR cleanup
|
||||||
pub mod cleanup_post_borrowck : CleanupPostBorrowck;
|
pub mod cleanup_post_borrowck : CleanupPostBorrowck;
|
||||||
|
|
||||||
@@ -390,8 +388,6 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
|||||||
&Lint(check_packed_ref::CheckPackedRef),
|
&Lint(check_packed_ref::CheckPackedRef),
|
||||||
&Lint(check_const_item_mutation::CheckConstItemMutation),
|
&Lint(check_const_item_mutation::CheckConstItemMutation),
|
||||||
&Lint(function_item_references::FunctionItemReferences),
|
&Lint(function_item_references::FunctionItemReferences),
|
||||||
&Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
|
|
||||||
&Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes),
|
|
||||||
// What we need to do constant evaluation.
|
// What we need to do constant evaluation.
|
||||||
&simplify::SimplifyCfg::Initial,
|
&simplify::SimplifyCfg::Initial,
|
||||||
&Lint(sanity_check::SanityCheck),
|
&Lint(sanity_check::SanityCheck),
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
#![deny(ptr_to_integer_transmute_in_consts)]
|
||||||
|
|
||||||
const fn foo(ptr: *const u8) -> usize {
|
const fn foo(ptr: *const u8) -> usize {
|
||||||
unsafe {
|
unsafe {
|
||||||
std::mem::transmute(ptr)
|
std::mem::transmute(ptr)
|
||||||
//~^ WARN pointers cannot be transmuted to integers
|
//~^ ERROR pointers cannot be transmuted to integers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +13,7 @@ trait Human {
|
|||||||
let ptr: *const usize = &value;
|
let ptr: *const usize = &value;
|
||||||
unsafe {
|
unsafe {
|
||||||
std::mem::transmute(ptr)
|
std::mem::transmute(ptr)
|
||||||
//~^ WARN pointers cannot be transmuted to integers
|
//~^ ERROR pointers cannot be transmuted to integers
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ impl<T> Type<T> {
|
|||||||
let ptr: *const usize = &value;
|
let ptr: *const usize = &value;
|
||||||
unsafe {
|
unsafe {
|
||||||
std::mem::transmute(ptr)
|
std::mem::transmute(ptr)
|
||||||
//~^ WARN pointers cannot be transmuted to integers
|
//~^ ERROR pointers cannot be transmuted to integers
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,9 +40,7 @@ impl<T> Type<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn control(ptr: *const u8) -> usize {
|
fn control(ptr: *const u8) -> usize {
|
||||||
unsafe {
|
unsafe { std::mem::transmute(ptr) }
|
||||||
std::mem::transmute(ptr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ControlStruct;
|
struct ControlStruct;
|
||||||
@@ -49,22 +49,15 @@ impl ControlStruct {
|
|||||||
fn new() -> usize {
|
fn new() -> usize {
|
||||||
let value = 10;
|
let value = 10;
|
||||||
let ptr: *const i32 = &value;
|
let ptr: *const i32 = &value;
|
||||||
unsafe {
|
unsafe { std::mem::transmute(ptr) }
|
||||||
std::mem::transmute(ptr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const fn zoom(ptr: *const u8) -> usize {
|
const fn zoom(ptr: *const u8) -> usize {
|
||||||
unsafe {
|
unsafe {
|
||||||
std::mem::transmute(ptr)
|
std::mem::transmute(ptr)
|
||||||
//~^ WARN pointers cannot be transmuted to integers
|
//~^ ERROR pointers cannot be transmuted to integers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {}
|
||||||
const a: u8 = 10;
|
|
||||||
const value: usize = zoom(&a);
|
|
||||||
//~^ ERROR evaluation of constant value failed
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
warning: pointers cannot be transmuted to integers during const eval
|
error: pointers cannot be transmuted to integers during const eval
|
||||||
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9
|
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:5:9
|
||||||
|
|
|
|
||||||
LL | std::mem::transmute(ptr)
|
LL | std::mem::transmute(ptr)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -7,29 +7,14 @@ LL | std::mem::transmute(ptr)
|
|||||||
= note: at compile-time, pointers do not have an integer value
|
= note: at compile-time, pointers do not have an integer value
|
||||||
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
||||||
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
= note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default
|
note: the lint level is defined here
|
||||||
|
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(ptr_to_integer_transmute_in_consts)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error: pointers cannot be transmuted to integers during const eval
|
||||||
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26
|
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:15:13
|
||||||
|
|
|
||||||
LL | const value: usize = zoom(&a);
|
|
||||||
| ^^^^^^^^ unable to turn pointer into integer
|
|
||||||
|
|
|
||||||
= help: this code performed an operation that depends on the underlying bytes representing a pointer
|
|
||||||
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
|
|
||||||
|
|
||||||
warning: pointers cannot be transmuted to integers during const eval
|
|
||||||
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9
|
|
||||||
|
|
|
||||||
LL | std::mem::transmute(ptr)
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: at compile-time, pointers do not have an integer value
|
|
||||||
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
|
||||||
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
|
||||||
|
|
||||||
warning: pointers cannot be transmuted to integers during const eval
|
|
||||||
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13
|
|
||||||
|
|
|
|
||||||
LL | std::mem::transmute(ptr)
|
LL | std::mem::transmute(ptr)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -38,8 +23,8 @@ LL | std::mem::transmute(ptr)
|
|||||||
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
||||||
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
|
|
||||||
warning: pointers cannot be transmuted to integers during const eval
|
error: pointers cannot be transmuted to integers during const eval
|
||||||
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13
|
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:32:13
|
||||||
|
|
|
|
||||||
LL | std::mem::transmute(ptr)
|
LL | std::mem::transmute(ptr)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -48,6 +33,15 @@ LL | std::mem::transmute(ptr)
|
|||||||
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
||||||
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 4 warnings emitted
|
error: pointers cannot be transmuted to integers during const eval
|
||||||
|
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:58:9
|
||||||
|
|
|
||||||
|
LL | std::mem::transmute(ptr)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: at compile-time, pointers do not have an integer value
|
||||||
|
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
|
||||||
|
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
|
||||||
|
|||||||
@@ -1,46 +1,85 @@
|
|||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:16:29
|
--> $DIR/unnecessary-transmutation.rs:7:14
|
||||||
|
|
|
|
||||||
LL | pub static X: u8 = unsafe { transmute(true) };
|
LL | unsafe { transmute(x) }
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u32::to_ne_bytes`
|
||||||
|
|
|
|
||||||
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unnecessary-transmutation.rs:2:9
|
--> $DIR/unnecessary-transmutation.rs:2:9
|
||||||
|
|
|
|
||||||
LL | #![deny(unnecessary_transmutes)]
|
LL | #![deny(unnecessary_transmutes)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unnecessary transmute
|
|
||||||
--> $DIR/unnecessary-transmutation.rs:18:28
|
|
||||||
|
|
|
||||||
LL | pub const Y: u8 = unsafe { transmute(true) };
|
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
|
||||||
--> $DIR/unnecessary-transmutation.rs:7:14
|
|
||||||
|
|
|
||||||
LL | unsafe { transmute(x) }
|
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
|
|
||||||
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:12:14
|
--> $DIR/unnecessary-transmutation.rs:12:14
|
||||||
|
|
|
|
||||||
LL | unsafe { transmute(from) }
|
LL | unsafe { transmute(from) }
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `(from) as u8`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - unsafe { transmute(from) }
|
||||||
|
LL + unsafe { (from) as u8 }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary transmute
|
||||||
|
--> $DIR/unnecessary-transmutation.rs:16:29
|
||||||
|
|
|
||||||
|
LL | pub static X: u8 = unsafe { transmute(true) };
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - pub static X: u8 = unsafe { transmute(true) };
|
||||||
|
LL + pub static X: u8 = unsafe { (true) as u8 };
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary transmute
|
||||||
|
--> $DIR/unnecessary-transmutation.rs:18:28
|
||||||
|
|
|
||||||
|
LL | pub const Y: u8 = unsafe { transmute(true) };
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - pub const Y: u8 = unsafe { transmute(true) };
|
||||||
|
LL + pub const Y: u8 = unsafe { (true) as u8 };
|
||||||
|
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:24:18
|
--> $DIR/unnecessary-transmutation.rs:24:18
|
||||||
|
|
|
|
||||||
LL | unsafe { transmute(x) }
|
LL | unsafe { transmute(x) }
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `(x) as u8`
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - unsafe { transmute(x) }
|
||||||
|
LL + unsafe { (x) as u8 }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary transmute
|
||||||
|
--> $DIR/unnecessary-transmutation.rs:30:22
|
||||||
|
|
|
||||||
|
LL | const { unsafe { transmute::<_, u8>(true) } };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - const { unsafe { transmute::<_, u8>(true) } };
|
||||||
|
LL + const { unsafe { (true) as u8 } };
|
||||||
|
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:33:22
|
--> $DIR/unnecessary-transmutation.rs:33:22
|
||||||
|
|
|
|
||||||
LL | let x: u16 = transmute(*b"01");
|
LL | let x: u16 = transmute(*b"01");
|
||||||
| ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")`
|
| ---------^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u16::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -48,7 +87,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:35:26
|
--> $DIR/unnecessary-transmutation.rs:35:26
|
||||||
|
|
|
|
||||||
LL | let x: [u8; 2] = transmute(x);
|
LL | let x: [u8; 2] = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u16::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -56,7 +97,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:37:22
|
--> $DIR/unnecessary-transmutation.rs:37:22
|
||||||
|
|
|
|
||||||
LL | let x: u32 = transmute(*b"0123");
|
LL | let x: u32 = transmute(*b"0123");
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")`
|
| ---------^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u32::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -64,7 +107,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:39:26
|
--> $DIR/unnecessary-transmutation.rs:39:26
|
||||||
|
|
|
|
||||||
LL | let x: [u8; 4] = transmute(x);
|
LL | let x: [u8; 4] = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u32::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -72,7 +117,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:41:22
|
--> $DIR/unnecessary-transmutation.rs:41:22
|
||||||
|
|
|
|
||||||
LL | let x: u64 = transmute(*b"feriscat");
|
LL | let x: u64 = transmute(*b"feriscat");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")`
|
| ---------^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u64::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -80,7 +127,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:43:26
|
--> $DIR/unnecessary-transmutation.rs:43:26
|
||||||
|
|
|
|
||||||
LL | let x: [u8; 8] = transmute(x);
|
LL | let x: [u8; 8] = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u64::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -88,7 +137,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:46:22
|
--> $DIR/unnecessary-transmutation.rs:46:22
|
||||||
|
|
|
|
||||||
LL | let y: i16 = transmute(*b"01");
|
LL | let y: i16 = transmute(*b"01");
|
||||||
| ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")`
|
| ---------^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i16::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -96,7 +147,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:48:26
|
--> $DIR/unnecessary-transmutation.rs:48:26
|
||||||
|
|
|
|
||||||
LL | let y: [u8; 2] = transmute(y);
|
LL | let y: [u8; 2] = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i16::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -104,7 +157,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:50:22
|
--> $DIR/unnecessary-transmutation.rs:50:22
|
||||||
|
|
|
|
||||||
LL | let y: i32 = transmute(*b"0123");
|
LL | let y: i32 = transmute(*b"0123");
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")`
|
| ---------^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i32::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -112,7 +167,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:52:26
|
--> $DIR/unnecessary-transmutation.rs:52:26
|
||||||
|
|
|
|
||||||
LL | let y: [u8; 4] = transmute(y);
|
LL | let y: [u8; 4] = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i32::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -120,7 +177,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:54:22
|
--> $DIR/unnecessary-transmutation.rs:54:22
|
||||||
|
|
|
|
||||||
LL | let y: i64 = transmute(*b"feriscat");
|
LL | let y: i64 = transmute(*b"feriscat");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")`
|
| ---------^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i64::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -128,7 +187,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:56:26
|
--> $DIR/unnecessary-transmutation.rs:56:26
|
||||||
|
|
|
|
||||||
LL | let y: [u8; 8] = transmute(y);
|
LL | let y: [u8; 8] = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i64::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -136,7 +197,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:59:22
|
--> $DIR/unnecessary-transmutation.rs:59:22
|
||||||
|
|
|
|
||||||
LL | let z: f32 = transmute(*b"0123");
|
LL | let z: f32 = transmute(*b"0123");
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")`
|
| ---------^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f32::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -144,7 +207,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:61:26
|
--> $DIR/unnecessary-transmutation.rs:61:26
|
||||||
|
|
|
|
||||||
LL | let z: [u8; 4] = transmute(z);
|
LL | let z: [u8; 4] = transmute(z);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f32::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -152,7 +217,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:63:22
|
--> $DIR/unnecessary-transmutation.rs:63:22
|
||||||
|
|
|
|
||||||
LL | let z: f64 = transmute(*b"feriscat");
|
LL | let z: f64 = transmute(*b"feriscat");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")`
|
| ---------^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f64::from_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
= help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -160,7 +227,9 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:65:26
|
--> $DIR/unnecessary-transmutation.rs:65:26
|
||||||
|
|
|
|
||||||
LL | let z: [u8; 8] = transmute(z);
|
LL | let z: [u8; 8] = transmute(z);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f64::to_ne_bytes`
|
||||||
|
|
|
|
||||||
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
= help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
|
||||||
|
|
||||||
@@ -168,119 +237,164 @@ error: unnecessary transmute
|
|||||||
--> $DIR/unnecessary-transmutation.rs:68:22
|
--> $DIR/unnecessary-transmutation.rs:68:22
|
||||||
|
|
|
|
||||||
LL | let y: u32 = transmute('🦀');
|
LL | let y: u32 = transmute('🦀');
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u32::from`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:70:23
|
--> $DIR/unnecessary-transmutation.rs:70:23
|
||||||
|
|
|
|
||||||
LL | let y: char = transmute(y);
|
LL | let y: char = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `char::from_u32_unchecked`
|
||||||
|
|
|
|
||||||
= help: consider `char::from_u32(…).unwrap()`
|
= help: consider using `char::from_u32(…).unwrap()`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:72:22
|
--> $DIR/unnecessary-transmutation.rs:72:22
|
||||||
|
|
|
|
||||||
LL | let y: i32 = transmute('🐱');
|
LL | let y: i32 = transmute('🐱');
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🐱').cast_signed()`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - let y: i32 = transmute('🐱');
|
||||||
|
LL + let y: i32 = u32::from('🐱').cast_signed();
|
||||||
|
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:74:23
|
--> $DIR/unnecessary-transmutation.rs:74:23
|
||||||
|
|
|
|
||||||
LL | let y: char = transmute(y);
|
LL | let y: char = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(i32::cast_unsigned(y))`
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider using `char::from_u32(i32::cast_unsigned(…)).unwrap()`
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - let y: char = transmute(y);
|
||||||
|
LL + let y: char = char::from_u32_unchecked(i32::cast_unsigned(y));
|
||||||
|
|
|
|
||||||
= help: consider `char::from_u32(i32::cast_unsigned(…)).unwrap()`
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:77:22
|
--> $DIR/unnecessary-transmutation.rs:77:22
|
||||||
|
|
|
|
||||||
LL | let x: u16 = transmute(8i16);
|
LL | let x: u16 = transmute(8i16);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i16::cast_unsigned`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:79:22
|
--> $DIR/unnecessary-transmutation.rs:79:22
|
||||||
|
|
|
|
||||||
LL | let x: i16 = transmute(x);
|
LL | let x: i16 = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u16::cast_signed`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:81:22
|
--> $DIR/unnecessary-transmutation.rs:81:22
|
||||||
|
|
|
|
||||||
LL | let x: u32 = transmute(4i32);
|
LL | let x: u32 = transmute(4i32);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i32::cast_unsigned`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:83:22
|
--> $DIR/unnecessary-transmutation.rs:83:22
|
||||||
|
|
|
|
||||||
LL | let x: i32 = transmute(x);
|
LL | let x: i32 = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u32::cast_signed`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:85:22
|
--> $DIR/unnecessary-transmutation.rs:85:22
|
||||||
|
|
|
|
||||||
LL | let x: u64 = transmute(7i64);
|
LL | let x: u64 = transmute(7i64);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `i64::cast_unsigned`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:87:22
|
--> $DIR/unnecessary-transmutation.rs:87:22
|
||||||
|
|
|
|
||||||
LL | let x: i64 = transmute(x);
|
LL | let x: i64 = transmute(x);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u64::cast_signed`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:90:22
|
--> $DIR/unnecessary-transmutation.rs:90:22
|
||||||
|
|
|
|
||||||
LL | let y: f32 = transmute(1u32);
|
LL | let y: f32 = transmute(1u32);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f32::from_bits`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:92:22
|
--> $DIR/unnecessary-transmutation.rs:92:22
|
||||||
|
|
|
|
||||||
LL | let y: u32 = transmute(y);
|
LL | let y: u32 = transmute(y);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f32::to_bits`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:94:22
|
--> $DIR/unnecessary-transmutation.rs:94:22
|
||||||
|
|
|
|
||||||
LL | let y: f64 = transmute(3u64);
|
LL | let y: f64 = transmute(3u64);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)`
|
| ---------^^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f64::from_bits`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:96:22
|
--> $DIR/unnecessary-transmutation.rs:96:22
|
||||||
|
|
|
|
||||||
LL | let y: u64 = transmute(2.0);
|
LL | let y: u64 = transmute(2.0);
|
||||||
| ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)`
|
| ---------^^^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `f64::to_bits`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:99:22
|
--> $DIR/unnecessary-transmutation.rs:99:22
|
||||||
|
|
|
|
||||||
LL | let y: f64 = transmute(1i64);
|
LL | let y: f64 = transmute(1i64);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(i64::cast_unsigned(1i64))`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - let y: f64 = transmute(1i64);
|
||||||
|
LL + let y: f64 = f64::from_bits(i64::cast_unsigned(1i64));
|
||||||
|
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:101:22
|
--> $DIR/unnecessary-transmutation.rs:101:22
|
||||||
|
|
|
|
||||||
LL | let y: i64 = transmute(1f64);
|
LL | let y: i64 = transmute(1f64);
|
||||||
| ^^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(1f64).cast_signed()`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: replace this with
|
||||||
|
|
|
||||||
|
LL - let y: i64 = transmute(1f64);
|
||||||
|
LL + let y: i64 = f64::to_bits(1f64).cast_signed();
|
||||||
|
|
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:106:21
|
--> $DIR/unnecessary-transmutation.rs:106:21
|
||||||
|
|
|
|
||||||
LL | let z: u8 = transmute(z);
|
LL | let z: u8 = transmute(z);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `u8::from(z)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
|
| help: replace this with: `u8::from`
|
||||||
|
|
||||||
error: unnecessary transmute
|
error: unnecessary transmute
|
||||||
--> $DIR/unnecessary-transmutation.rs:111:21
|
--> $DIR/unnecessary-transmutation.rs:111:21
|
||||||
|
|
|
|
||||||
LL | let z: i8 = transmute(z);
|
LL | let z: i8 = transmute(z);
|
||||||
| ^^^^^^^^^^^^ help: replace this with: `i8::from(z)`
|
| ---------^^^
|
||||||
|
| |
|
||||||
error: unnecessary transmute
|
| help: replace this with: `i8::from`
|
||||||
--> $DIR/unnecessary-transmutation.rs:30:22
|
|
||||||
|
|
|
||||||
LL | const { unsafe { transmute::<_, u8>(true) } };
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
|
|
||||||
|
|
||||||
error: aborting due to 40 previous errors
|
error: aborting due to 40 previous errors
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user