jeiea
jeiea

Reputation: 2385

How can I cast a struct reference to isize?

I want to get b in the following code.

unsafe {
    struct Test {
        num: i32,
    }
    let a = Test { num: 0 };
    let b = &mut a as isize;
}

But it results in the following error message.

error: casting `&on_create::Test` as `isize` is invalid
   --> main.rs:181:15
    |
181 |       let b = &a as isize;
    |    

I thought it would be coerced to *const _, then applied ptr-addr-cast. What have I missed on this? Should I use mem::transmute?

Upvotes: 5

Views: 1094

Answers (2)

kennytm
kennytm

Reputation: 523184

I thought it would be coerced to *const _, then applied ptr-addr-cast. ...

Firstly, implicit coercion doesn't happen everywhere, and certainly not inside part of an expression like e as T as you have noticed. The places where coercion happens, called coercion sites, are usually where you've done evaluating the expression, e.g.

  • RHS of let/const/static statements:

    let x = foo
    //      ^~~
    
  • Arguments to functions:

    foo(bar)
    //  ^~~
    
  • Returned expressions:

    fn f() -> u32 {
        foo
    //  ^~~
    }
    
  • struct/array/tuple literals:

       [foo, bar, baz]
    //  ^~~  ^~~  ^~~
       (foo, bar, baz)
    //  ^~~  ^~~  ^~~
       Foo { field: foo }
    //              ^~~
    
  • Last expression in a block:

    { ...; foo }
    //     ^~~
    

foo as isize is not among this list.

Secondly, even if implicit coercion were allowed everywhere, that does not mean Rust should choose to coerce to a type that makes the conversion valid. An &mut Test can be coerced to &Test or *mut Test or *const Test or &mut SomeTrait etc, the compiler will need to check all of them! This can only work if you tell what type the expression should coerce to:

#![feature(type_ascription)]

let b = {&a}: *const _ as isize;
//       ^~ ^~~~~~~~~~
//        |   we explicitly make the type a const raw pointer
//        |                             using type-ascription
//        a coercion site

But this has not much of a difference than the canonical solution &a as *const _ as isize.

Upvotes: 6

Shepmaster
Shepmaster

Reputation: 430426

You need to use explicit conversion; "chains" of conversions / coercions don't usually (ever?) work:

struct Test {
    num: i32,
}
let a = Test { num: 0 };
let b = &a as *const _ as isize;

Since there's no reason for mutability, I've removed it. There's also no unsafe behavior in this code snippet, so the unsafe block is not needed.

Upvotes: 4

Related Questions