Lint on reference casting to bigger underlying allocation
This commit is contained in:
parent
bdc15928c8
commit
915200fbe0
@ -319,6 +319,11 @@ lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not
|
||||
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_invalid_reference_casting_bigger_layout = casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
.label = casting happend here
|
||||
.alloc = backing allocation comes from here
|
||||
.layout = casting from `{$from_ty}` ({$from_size} bytes) to `{$to_ty}` ({$to_size} bytes)
|
||||
|
||||
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
|
@ -716,7 +716,7 @@ pub enum InvalidFromUtf8Diag {
|
||||
|
||||
// reference_casting.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum InvalidReferenceCastingDiag {
|
||||
pub enum InvalidReferenceCastingDiag<'tcx> {
|
||||
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||
#[note(lint_invalid_reference_casting_note_book)]
|
||||
BorrowAsMut {
|
||||
@ -733,6 +733,18 @@ pub enum InvalidReferenceCastingDiag {
|
||||
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
|
||||
ty_has_interior_mutability: Option<()>,
|
||||
},
|
||||
#[diag(lint_invalid_reference_casting_bigger_layout)]
|
||||
#[note(lint_layout)]
|
||||
BiggerLayout {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
#[label(lint_alloc)]
|
||||
alloc: Span,
|
||||
from_ty: Ty<'tcx>,
|
||||
from_size: u64,
|
||||
to_ty: Ty<'tcx>,
|
||||
to_size: u64,
|
||||
},
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
|
@ -1,6 +1,7 @@
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use rustc_middle::ty::{self, TypeAndMut};
|
||||
use rustc_middle::ty::layout::LayoutOf as _;
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, TypeAndMut};
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
|
||||
@ -38,13 +39,12 @@
|
||||
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if let Some((e, pat)) = borrow_or_assign(cx, expr) {
|
||||
if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) {
|
||||
let init = cx.expr_or_init(e);
|
||||
let init = cx.expr_or_init(e);
|
||||
let orig_cast = if init.span != e.span { Some(init.span) } else { None };
|
||||
|
||||
let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) else {
|
||||
return;
|
||||
};
|
||||
let orig_cast = if init.span != e.span { Some(init.span) } else { None };
|
||||
if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign)
|
||||
&& let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init)
|
||||
{
|
||||
let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
|
||||
|
||||
cx.emit_span_lint(
|
||||
@ -63,6 +63,23 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((from_ty_layout, to_ty_layout, e_alloc)) =
|
||||
is_cast_to_bigger_memory_layout(cx, init)
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
INVALID_REFERENCE_CASTING,
|
||||
expr.span,
|
||||
InvalidReferenceCastingDiag::BiggerLayout {
|
||||
orig_cast,
|
||||
alloc: e_alloc.span,
|
||||
from_ty: from_ty_layout.ty,
|
||||
from_size: from_ty_layout.layout.size().bytes(),
|
||||
to_ty: to_ty_layout.ty,
|
||||
to_size: to_ty_layout.layout.size().bytes(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,6 +168,48 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_cast_to_bigger_memory_layout<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
orig_expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> {
|
||||
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
|
||||
|
||||
let ty::RawPtr(TypeAndMut { ty: inner_end_ty, mutbl: _ }) = end_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let (e, _) = peel_casts(cx, orig_expr);
|
||||
let start_ty = cx.typeck_results().node_type(e.hir_id);
|
||||
|
||||
let ty::Ref(_, inner_start_ty, _) = start_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// try to find the underlying allocation
|
||||
let e_alloc = cx.expr_or_init(e);
|
||||
let e_alloc =
|
||||
if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc };
|
||||
let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id);
|
||||
|
||||
// if we do not find it we bail out, as this may not be UB
|
||||
// see https://github.com/rust-lang/unsafe-code-guidelines/issues/256
|
||||
if alloc_ty.is_any_ptr() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let from_layout = cx.layout_of(*inner_start_ty).ok()?;
|
||||
let alloc_layout = cx.layout_of(alloc_ty).ok()?;
|
||||
let to_layout = cx.layout_of(*inner_end_ty).ok()?;
|
||||
|
||||
if to_layout.layout.size() > from_layout.layout.size()
|
||||
&& to_layout.layout.size() > alloc_layout.layout.size()
|
||||
{
|
||||
Some((from_layout, to_layout, *e_alloc))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
|
||||
let mut gone_trough_unsafe_cell_raw_get = false;
|
||||
|
||||
|
@ -81,14 +81,14 @@ fn main()
|
||||
assert_eq!(u as *const u16, p as *const u16);
|
||||
|
||||
// ptr-ptr-cast (Length vtables)
|
||||
let mut l : [u8; 2] = [0,1];
|
||||
let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
|
||||
let w: *mut [u16] = unsafe {&mut *w};
|
||||
let w_u8 : *const [u8] = w as *const [u8];
|
||||
assert_eq!(unsafe{&*w_u8}, &l);
|
||||
let mut l : [u16; 2] = [0,1];
|
||||
let w: *mut [u8; 2] = &mut l as *mut [u16; 2] as *mut _;
|
||||
let w: *mut [u8] = unsafe {&mut *w};
|
||||
let w_u16 : *const [u16] = w as *const [u16];
|
||||
assert_eq!(unsafe{&*w_u16}, &l);
|
||||
|
||||
let s: *mut str = w as *mut str;
|
||||
let l_via_str = unsafe{&*(s as *const [u8])};
|
||||
let l_via_str = unsafe{&*(s as *const [u16])};
|
||||
assert_eq!(&l, l_via_str);
|
||||
|
||||
// ptr-ptr-cast (Length vtables, check length is preserved)
|
||||
|
@ -30,7 +30,7 @@ unsafe fn ref_to_mut() {
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *(num as *const i32).cast::<i32>().cast_mut().cast_const().cast_mut();
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32);
|
||||
let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i8);
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
|
||||
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
@ -141,6 +141,109 @@ unsafe fn generic_assign_to_ref<T>(this: &T, a: T) {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(align(16))]
|
||||
struct I64(i64);
|
||||
|
||||
#[repr(C)]
|
||||
struct Mat3<T> {
|
||||
a: Vec3<T>,
|
||||
b: Vec3<T>,
|
||||
c: Vec3<T>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Vec3<T>(T, T, T);
|
||||
|
||||
unsafe fn bigger_layout() {
|
||||
{
|
||||
let num = &mut 3i32;
|
||||
|
||||
let _num = &*(num as *const i32 as *const i64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
let _num = &mut *(num as *mut i32 as *mut i64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
let _num = &mut *(num as *mut i32 as *mut I64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
std::ptr::write(num as *mut i32 as *mut i64, 2);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
|
||||
let _num = &mut *(num as *mut i32);
|
||||
}
|
||||
|
||||
{
|
||||
let num = &mut [0i32; 3];
|
||||
|
||||
let _num = &mut *(num as *mut _ as *mut [i64; 2]);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
std::ptr::write_unaligned(num as *mut _ as *mut [i32; 4], [0, 0, 1, 1]);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
|
||||
let _num = &mut *(num as *mut _ as *mut [u32; 3]);
|
||||
let _num = &mut *(num as *mut _ as *mut [u32; 2]);
|
||||
}
|
||||
|
||||
{
|
||||
let num = &mut [0i32; 3] as &mut [i32];
|
||||
|
||||
let _num = &mut *(num as *mut _ as *mut i128);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
let _num = &mut *(num as *mut _ as *mut [i64; 4]);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
|
||||
let _num = &mut *(num as *mut _ as *mut [u32]);
|
||||
let _num = &mut *(num as *mut _ as *mut [i16]);
|
||||
}
|
||||
|
||||
{
|
||||
let mat3 = Mat3 { a: Vec3(0i32, 0, 0), b: Vec3(0, 0, 0), c: Vec3(0, 0, 0) };
|
||||
|
||||
let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]);
|
||||
//~^ ERROR casting `&T` to `&mut T`
|
||||
//~^^ ERROR casting references to a bigger memory layout
|
||||
let _num = &*(&mat3 as *const _ as *mut [[i64; 3]; 3]);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
|
||||
let _num = &*(&mat3 as *const _ as *mut [[i32; 3]; 3]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut l: [u8; 2] = [0,1];
|
||||
let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
|
||||
let w: *mut [u16] = unsafe {&mut *w};
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
}
|
||||
|
||||
{
|
||||
fn foo() -> [i32; 1] { todo!() }
|
||||
|
||||
let num = foo();
|
||||
let _num = &*(&num as *const i32 as *const i64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
let _num = &*(&foo() as *const i32 as *const i64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
}
|
||||
|
||||
{
|
||||
fn bar(_a: &[i32; 2]) -> &[i32; 1] { todo!() }
|
||||
|
||||
let num = bar(&[0, 0]);
|
||||
let _num = &*(num as *const i32 as *const i64);
|
||||
let _num = &*(bar(&[0, 0]) as *const i32 as *const i64);
|
||||
}
|
||||
|
||||
{
|
||||
fn foi<T>() -> T { todo!() }
|
||||
|
||||
let num = foi::<i32>();
|
||||
let _num = &*(&num as *const i32 as *const i64);
|
||||
//~^ ERROR casting references to a bigger memory layout
|
||||
}
|
||||
|
||||
unsafe fn from_ref(this: &i32) -> &i64 {
|
||||
&*(this as *const i32 as *const i64)
|
||||
}
|
||||
}
|
||||
|
||||
const RAW_PTR: *mut u8 = 1 as *mut u8;
|
||||
unsafe fn no_warn() {
|
||||
let num = &3i32;
|
||||
|
@ -66,8 +66,8 @@ LL | let _num = &mut *(num as *const i32).cast::<i32>().cast_mut().cast_cons
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:33:16
|
||||
|
|
||||
LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i8);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
|
||||
|
||||
@ -373,5 +373,164 @@ LL | *(this as *const _ as *mut _) = a;
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
|
||||
|
||||
error: aborting due to 42 previous errors
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:161:20
|
||||
|
|
||||
LL | let num = &mut 3i32;
|
||||
| ---- backing allocation comes from here
|
||||
LL |
|
||||
LL | let _num = &*(num as *const i32 as *const i64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `i32` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:163:20
|
||||
|
|
||||
LL | let num = &mut 3i32;
|
||||
| ---- backing allocation comes from here
|
||||
...
|
||||
LL | let _num = &mut *(num as *mut i32 as *mut i64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `i32` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:165:20
|
||||
|
|
||||
LL | let num = &mut 3i32;
|
||||
| ---- backing allocation comes from here
|
||||
...
|
||||
LL | let _num = &mut *(num as *mut i32 as *mut I64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `i32` (4 bytes) to `I64` (16 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:167:9
|
||||
|
|
||||
LL | let num = &mut 3i32;
|
||||
| ---- backing allocation comes from here
|
||||
...
|
||||
LL | std::ptr::write(num as *mut i32 as *mut i64, 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `i32` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:176:20
|
||||
|
|
||||
LL | let num = &mut [0i32; 3];
|
||||
| --------- backing allocation comes from here
|
||||
LL |
|
||||
LL | let _num = &mut *(num as *mut _ as *mut [i64; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `[i32; 3]` (12 bytes) to `[i64; 2]` (16 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:178:9
|
||||
|
|
||||
LL | let num = &mut [0i32; 3];
|
||||
| --------- backing allocation comes from here
|
||||
...
|
||||
LL | std::ptr::write_unaligned(num as *mut _ as *mut [i32; 4], [0, 0, 1, 1]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `[i32; 3]` (12 bytes) to `[i32; 4]` (16 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:188:20
|
||||
|
|
||||
LL | let num = &mut [0i32; 3] as &mut [i32];
|
||||
| --------- backing allocation comes from here
|
||||
LL |
|
||||
LL | let _num = &mut *(num as *mut _ as *mut i128);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `[i32; 3]` (12 bytes) to `i128` (16 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:190:20
|
||||
|
|
||||
LL | let num = &mut [0i32; 3] as &mut [i32];
|
||||
| --------- backing allocation comes from here
|
||||
...
|
||||
LL | let _num = &mut *(num as *mut _ as *mut [i64; 4]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: casting from `[i32; 3]` (12 bytes) to `[i64; 4]` (32 bytes)
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/reference_casting.rs:200:20
|
||||
|
|
||||
LL | let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:200:20
|
||||
|
|
||||
LL | let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]);
|
||||
| ^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| backing allocation comes from here
|
||||
|
|
||||
= note: casting from `Mat3<i32>` (36 bytes) to `[[i64; 3]; 3]` (72 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:203:20
|
||||
|
|
||||
LL | let _num = &*(&mat3 as *const _ as *mut [[i64; 3]; 3]);
|
||||
| ^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| backing allocation comes from here
|
||||
|
|
||||
= note: casting from `Mat3<i32>` (36 bytes) to `[[i64; 3]; 3]` (72 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:212:37
|
||||
|
|
||||
LL | let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
|
||||
| --------------------------------
|
||||
| | |
|
||||
| | backing allocation comes from here
|
||||
| casting happend here
|
||||
LL | let w: *mut [u16] = unsafe {&mut *w};
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: casting from `[u8; 2]` (2 bytes) to `[u16; 2]` (4 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:220:20
|
||||
|
|
||||
LL | let _num = &*(&num as *const i32 as *const i64);
|
||||
| ^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| backing allocation comes from here
|
||||
|
|
||||
= note: casting from `[i32; 1]` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:222:20
|
||||
|
|
||||
LL | let _num = &*(&foo() as *const i32 as *const i64);
|
||||
| ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| backing allocation comes from here
|
||||
|
|
||||
= note: casting from `[i32; 1]` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
|
||||
--> $DIR/reference_casting.rs:238:20
|
||||
|
|
||||
LL | let _num = &*(&num as *const i32 as *const i64);
|
||||
| ^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| backing allocation comes from here
|
||||
|
|
||||
= note: casting from `i32` (4 bytes) to `i64` (8 bytes)
|
||||
|
||||
error: aborting due to 57 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user