Skip to content

"raw pointers cannot be cast to integers in statics" justification is incorrect #30705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mahkoh opened this issue Jan 4, 2016 · 7 comments
Closed

Comments

@mahkoh
Copy link
Contributor

mahkoh commented Jan 4, 2016

pub static mut X: usize = unsafe { &X as *const _ as usize };
The value of static and const variables must be known at compile time. You
can't cast a pointer as an integer because we can't know what value the
address will take.

This is incorrect as the following code shows:

pub static mut X: *const u8 = unsafe { &X as *const _ as *const _ };

The value of X is only known at link time.

@mahkoh
Copy link
Contributor Author

mahkoh commented Jan 4, 2016

If this were true then statics could not take references to each other. Hence casting pointers to integers should be allowed in statics.

@arielb1
Copy link
Contributor

arielb1 commented Jan 4, 2016

@mahkoh

First, the extended diagnostic errors are not written by the core Rust team, so inaccuracies are to be expected (we would still like to fix them to some degree).

Of course, the real reason is that we want the values of statics to be known at compile-time, either as an integer or as a known offset from a symbol, and that if you could cast pointers to integers, you could do arithmetic on these integers and end up with values that are neither.

It certainly would have been possible to prohibit the arithmetic instead of the round-tripping, but at the time it seemed to me that it would be just an insufficiently useful overcomplication.

If you have a sensible use-case for a more lenient model, we would like to know about it. Maybe I should rather attach this post to the error message?

@mahkoh
Copy link
Contributor Author

mahkoh commented Jan 4, 2016

@arielb1

you could do arithmetic on these integers

Of course this cannot work.

If you have a sensible use-case for a more lenient model, we would like to know about it.

I have a single use case namely

pub static SELF_PTR: usize = &SELF_PTR as *const _ as usize;

let real_to_virt = SELF_PTR - (&SELF_PTR as *const _ as usize);

to calculate the difference between the current program counter and the position the linker assumed the program counter to be. In OS dev this can then be used to create the page tables with the correct virtual to physical address mapping. The advantage of usize is that the static doesn't have to be mut because usize is Sync.

It's not that big of an issue.

@arielb1
Copy link
Contributor

arielb1 commented Jan 4, 2016

Making it work would require some significant modification to the const_eval code, but it is going to be refactored soon anyway.

Can't you wrap your pointer with an SyncRawPtr wrapper struct (e.g. current libcore's Unique)?

@mahkoh
Copy link
Contributor Author

mahkoh commented Jan 4, 2016

lrs has deprecated Unique in favor of

  • NoAliasMemPtr,
  • NoAliasMutObjPtr,
  • NoAliasObjPtr,
  • AliasMemPtr,
  • AliasMutObjPtr, and
  • AliasObjPtr.

And none of these implement Sync.

In any case, since this pointer is only used once to calculate real_to_virt, I don't think using a wrapper is worth it. This is not a big issue and it's certainly not necessary to do any modifications to fix this use case.

@GuillaumeGomez
Copy link
Member

If you're speaking of E0018, my bad, I'm the one who wrote it. How would you improve the error explanation?

@zeonin
Copy link

zeonin commented Jan 13, 2017

@arielb1

If you have a sensible use-case for a more lenient model, we would like to know about it.

Personally, I'd find it very useful for things like descriptor handling in OS dev.

What I would like to be able to do is something like this:

type InterruptHandler = fn();

#[repr(C, packed)]
struct Descriptor {
    base_low: u16,
    selector: u16,
    flags: u16,
    base_high:u16,

impl Descriptor
    const fn new(handler: &InterruptHandler, selector: u16, flags: u16) -> Descriptor {
        Descriptor {
            base_low: (handler as *const _ as usize & 0xFFFF) as u16,
            selector: selector,
            flags: flags,
            base_high: ((handler as *const _ as usize >> 16) & 0xFFFF) as u16,
        }
    }
}

The architecture defines the format of a Descriptor, but it has to refer to a valid interrupt handler. Being able to fully generate a table at compile time in rust would be more convenient than doing so in assembly, and it would be nice to not have to set these structures at runtime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants