rust
rust copied to clipboard
const fns cannot have fn pointer arguments that take mutable references, even if they aren't called
I tried this code:
struct Foo {
bar: fn(i: &mut i32),
}
impl Foo {
const fn new(bar: fn(i: &mut i32)) -> Self {
Foo {
bar,
}
}
}
I expected to see this happen: code compiles.
Instead, this happened: error[E0658]: mutable references are not allowed in constant functions
However, putting the function pointer in a simple newtype compiles without problem:
struct Bar(fn(i: &mut i32));
struct Foo {
bar: Bar,
}
impl Foo {
const fn new(bar: Bar) -> Self {
Foo {
bar,
}
}
}
This should indicate that:
- Either merely having an argument of a fn pointer type is not problematic, even if said fn pointer takes a mutable reference as an argument for itself, if it is not called.
- Or that rustc is allowing possibly unsound code to compile.
Meta
rustc --version --verbose:
binary: rustc
commit-hash: e092d0b6b43f2de967af0887873151bb1c0b18d3
commit-date: 2022-07-16
host: x86_64-unknown-linux-gnu
release: 1.62.1
LLVM version: 14.0.5
rustc 1.64.0-nightly (1b57946a4 2022-08-03)
binary: rustc
commit-hash: 1b57946a405d5b2a87e612335db033edb2c3427f
commit-date: 2022-08-03
host: x86_64-unknown-linux-gnu
release: 1.64.0-nightly
LLVM version: 14.0.6
rustc produced no backtrace.
@rustbot claim
@chitoyuu
Add #![feature(const_mut_refs)] in source file will be OK.
@chenyukang I have already opted for the newtype workaround, since while I'm relatively sure that this use case is sound, there are probably reasons to disallow mutable references by default in others, and I'm not sure I understand all the nuances. Thanks for the suggestion regardless!
hm, @rust-lang/wg-const-eval does anyone know if we're being too aggressive by denying fn(&mut T) in const fns? I think this is a side-effect of using Ty::walk when checking for mut ptrs and not intentionally being denied, or at least couldn't find a UI test exercising this case (which obviously means very little, just putting that for extra context).
Should I put up a PR to call skip_current_subtree when we encounter a fn ptr to allow something like this to compile?
IIRC, a walk on ADT fields would have been more correct..
I was actually thinking of whether we want to make this more restrictive (seems more correct) by checking ADT fields -- but walking into the ADT fields actually causes core to fail to bootstrap because of &mut pointers being revealed now (something in the format_args macro, I think).
I didn't look too much into it, but I can produce a minimal example of that failure if others want to know.
Hmm, can we add the feature() then?
maybe we should just start allowing mutable references but not dereferencing them ^^
I was thinking about that yesterday. It should be easy to deny just the derefs in MIR right? I can get that implemented if so.
So basically, the same thing we did for function pointers themselves?
I don't have a good idea for which doors we might be closing that way, so it might be slightly safer to just stop traversing the types inside fn? Are there any types other than &mut that we are currently rejecting in this way?
Immutable references to interior mut data are checked the same way. About a month ago @amanjeev was trying to replicate and add tests for the issues we had around mutable references, and we can't reproduce any of the examples even via godbolt on older compilers. So before I disappeared for 3 weeks I was planning on proposing stabilization of mutable references after documenting all the things we're testing and the effects on future language design (mostly around const heap)
The code now compiles successfully. Closing as fixed.