rust icon indicating copy to clipboard operation
rust copied to clipboard

const fns cannot have fn pointer arguments that take mutable references, even if they aren't called

Open chitoyuu opened this issue 3 years ago • 3 comments

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.

chitoyuu avatar Aug 04 '22 08:08 chitoyuu

@rustbot claim

chenyukang avatar Aug 05 '22 03:08 chenyukang

@chitoyuu Add #![feature(const_mut_refs)] in source file will be OK.

chenyukang avatar Aug 05 '22 09:08 chenyukang

@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!

chitoyuu avatar Aug 05 '22 09:08 chitoyuu

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?

compiler-errors avatar Aug 09 '22 02:08 compiler-errors

IIRC, a walk on ADT fields would have been more correct..

fee1-dead avatar Aug 09 '22 03:08 fee1-dead

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.

compiler-errors avatar Aug 09 '22 03:08 compiler-errors

Hmm, can we add the feature() then?

fee1-dead avatar Aug 09 '22 03:08 fee1-dead

maybe we should just start allowing mutable references but not dereferencing them ^^

oli-obk avatar Aug 22 '22 18:08 oli-obk

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.

compiler-errors avatar Aug 22 '22 18:08 compiler-errors

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?

RalfJung avatar Aug 22 '22 18:08 RalfJung

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)

oli-obk avatar Aug 22 '22 21:08 oli-obk

The code now compiles successfully. Closing as fixed.

fmease avatar Jan 25 '24 21:01 fmease