Repository navigation
Storing a function pointer in a const usize works on nightly #51559
Description
Activity
- changed the title
[-]Storing a function pointer in a static usize works on nightly[/-][+]Storing a function pointer in a const usize works on nightly[/+]on Jun 14, 2018 cc @RalfJung
Some people were of the opinion that this shouldn't work
It should work,it's just super scary.EDIT: it should not and does not work. If we allowed this, various surprising things can happen, especially around implicit promotion. If you want to store pointers and integers, you can use a raw pointer.
It should work
For my own education, can you elaborate on why function pointers are ok? I'd thought that the runtime addresses of things -- including functions -- shouldn't be accessible at const-time since we don't know where they'll live at runtime. Could I make a const array that usize long?
When compiling to LLVM, the real function handle or pointer address is obtained. If you try doing anything weird with pointers at compile time, you will quickly notice that you are not at runtime. For example, you cannot divide such a usize by anything. You can add or subtract integers, because that's just pointer offsetting, but you can't inspect the address in any way.
This also means that no, you cannot use this usize for array lengths or enum discriminants. This is due to the fact that miri pointers are not just addresses, but abstract pointers that are in a separate layer from the bytes of normal memory like the one of integers.
Thanks for the explanation.
I guess that means that such a
usizecouldn't be passed to a const generic either?I guess that means that such a usize couldn't be passed to a const generic either?
The thing is const generics don't know where the usize comes from, so they could try to do something with it that is not allowed if it is just a pointer address. Until monomorphization we can't know if there is an issue.
Note that converting a pointer to an usize and back just to be able to put it in const, statics, or use it with const generics, is a real pain. We would be better off in this case with an
AtomicPtr<T>type, such that I can writeAtomicPtr<fn()->i32>and avoid the conversion to usize.For const generics, C++ accepts function pointers at the type level and that works just fine with clang, so I expect
fn bar<const PTR: fn()->i32>() {}to work fine as well.How would
AtomicPtr<T>work?- is
AtomicPtr<i32>disallowed butAtomicPtr<*const i32>andAtomicPtr<fn(&str) -> &str>work? that seems very weird and special cased (especially for fn types that involve higher rank lifetimes, as in my example) - or is
AtomicPtr<T>~=*mut T? thenAtomicPtr<fn()>is a double indirection and to use it you need to worry about managing the memory it points to (which contains thefn())
- is
How would AtomicPtr work?
I haven't thought this through beyond having used the atomic pointers in the C++ standard library: http://en.cppreference.com/w/cpp/atomic/atomic
One way to implement this could be
AtomicPtr<T> where T: AtomicPtrConstraintwhere we provide blanket impls for&'a,&'a mut,*const,*mut,fn() -> T,fn(T) -> U,fn(T, U) -> V, ... or use some compiler magic to achieve a similar effect...This is a bit offtopic, but regarding
AtomicPtr, @nikomatsakis mentioned at least once the possibility of introducing some new type, to makefn(A) -> Bsugar for&ThatType<(A,), B>.
I guess it can't entirely be "sugar", because of existing impls, but at least both could work the same.Hehe, this is cute. :) And I agree it is working as intended. (Nice that the translation to LLVM actually gets this right, should there be a testcase to make sure it stays that way? :D )
- addedE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)Area: Constant evaluation, covers all const contexts (static, const fn, ...)
on Jun 19, 2018 So... other than testing this, all we need is a PR that adds
*const T->usizecasts in constants under a feature gate (and makes those casts unsafe in constants andconst fn)Reacted by Mazdak FarrokhzadI've opened rust-lang/rfcs#2481 to brainstorm how to either add an
AtomicFnPtrtype or retrofitAtomicPtrto supportfnitems.These kind of operations are now unsafe in
constcontexts (impl PR: #55009)So do we have a test that you cannot use such usize as array length? :D
hmm... apparently not...
Test-instructions:
- use
transmute(via theconst_transmutefeature gate) to turn various kinds of references and function pointers intousize - use these expressions in
- array length,
- repeat lengths
- and enum discriminant initializers (e.g.
enum Foo { Bar = unsafe { transmute(main) } })
Note: Do not use
constitems, everything needs to be inline in the use site to be properly tested- use
- addedE-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
on Jan 28, 2019 It seems this is no longer allowed by any means:
#![feature(const_raw_ptr_to_usize_cast)] const BAR: *mut () = ((|| 3) as fn() -> i32) as *mut (); pub const FOO: usize = unsafe { BAR as usize }; fn main() {}Compiling playground v0.0.1 (/playground) error[E0080]: it is undefined behavior to use this value --> src/main.rs:4:1 | 4 | pub const FOO: usize = unsafe { BAR as usize }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. error: Could not compile `playground`. To learn more, run the command again with --verbose.Yes that is intended. This issue is for adding a regression test testing what happens when you use a pointer casted to a usize in an array length.
- added a commit that references this issue
on Jul 24, 2019 - added a commit that references this issue
on Jul 25, 2019
Some people were of the opinion that this shouldn't work, but it currently does. playground:
cc @rkruppe @eddyb @oli-obk