Skip to content

Can't write generic const fns #116354

Open
Open
@ilyvion

Description

@ilyvion

I was going to leave this as a remark on #80384, but you're apparently supposed to make separate issues instead of leaving comments on tracking issues, so here goes:

I was just playing around and couldn't even get past this simple code before getting yelled at:

const fn foo<T, const N: usize>(values: [T; N]) -> [T; N] {
    let slice = values.as_slice();
    let len = slice.len();
    
    values
}

Both as_slice() and len() are declared as const fn, so you'd think they'd be fine to use in another const fn, but no:

error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
 --> src/lib.rs:2:17
  |
2 |     let slice = values.as_slice();
  |                 ^^^^^^^^^^^^^^^^^
  |
  = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information

I don't even understand what this is trying to tell me. Issue #80384, which is the one linked, does not at all explain the source/cause of this error. I'm not working with UnsafeCell or interior mutability here. I'm attempting to make a &[T] from a [T; N].

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Oct 2, 2023
asquared31415

asquared31415 commented on Oct 2, 2023

@asquared31415
Contributor

Consider the following code:

let arr = [UnsafeCell::new(1_u32)];
foo(arr);

your code would then have T = UnsafeCell<u32>, then make a &[UnsafeCell<u32>] which is rejected because that could potentially be used as interior mutability, which is rejected in const.

ilyvion

ilyvion commented on Oct 3, 2023

@ilyvion
Author

If UnsafeCell can't be used in const, why are some of its methods const fns? This all seems like a rather bad series of choices.

Cerber-Ursi

Cerber-Ursi commented on Oct 3, 2023

@Cerber-Ursi
Contributor

UnsafeCell can't be used in const, but can be (indirectly, with some Sync wrapper, like Mutex) used in static:

use core::cell::UnsafeCell;

struct RacyCell<T>(UnsafeCell<T>);
unsafe impl<T> Sync for RacyCell<T> {}

static CELL: RacyCell<u8> = RacyCell(UnsafeCell::new(42));

And static initializers can't call non-const functions.

workingjubilee

workingjubilee commented on Oct 4, 2023

@workingjubilee
Member

If UnsafeCell can't be used in const, why are some of its methods const fns? This all seems like a rather bad series of choices.

We actually intend to make mutability in const fn possible, and that will probably include UnsafeCell<T> (eventually). This is (mostly) the const_mut_ref feature.

ilyvion

ilyvion commented on Oct 4, 2023

@ilyvion
Author

I don't suppose it'd be possible for the compiler to detect the presence of UnsafeCell in the specific monomorphization of T in const fn foo<T, const N: usize>(values: [T; N]) -> [T; N] rather than just blanket disallow usage of all generics/mutability in const?

For instance,

const fn foo<const N: usize>(values: [String; N]) -> [String; N] {
    let slice = values.as_slice();
    let len = slice.len();
    
    values
}

compiles just fine while

use std::cell::UnsafeCell;

struct Foo(UnsafeCell<()>);

const fn foo<const N: usize>(values: [Foo; N]) -> [Foo; N] {
    let slice = values.as_slice();
    let len = slice.len();
    
    values
}

does not -- clearly the compiler knows that String doesn't have interior mutability and that Foo does; couldn't this same "test" be done on a per-T basis rather than as on a blanket for-all-T basis?

workingjubilee

workingjubilee commented on Oct 4, 2023

@workingjubilee
Member

What you are describing (sometimes called a "post-monomorphization error") is both absurdly controversial (Rust allows them to happen, but it's still controversial in terms of API design), and also will become unnecessary the moment const_mut_refs stabilizes, so, uh,

Probably not?

ilyvion

ilyvion commented on Oct 4, 2023

@ilyvion
Author

Not to put too fine a point on it, but "when feature X stabilizes" in Rust can mean "by the next version" or "in over a decade," so that doesn't mean much and could leave a huge class of useful generic const functions unwritable for a very long time for the sake of making something unnecessary later.

But if it's basically a policy (or at least the uncontroversial approach) that it's better to error out on the basis of "any given T can violate something" rather than on the basis of "a specific T can violate something," there's not much to do about it I suppose.

workingjubilee

workingjubilee commented on Oct 4, 2023

@workingjubilee
Member

Oh, I agree. I'm basically always pushing for more const stuff reaching anywhere near stable precisely because of things like this. There's... currently a lot of "huge class(es) of useful generic const functions (that are) unwritable".

I think the hardest problem here is that even if you PRed the changes necessary to the compiler to make this happen, you'd mostly be trying to convince all the people who are trying to fix the exact problems to simply make this work take a look at your code which may make their work take longer as they now have to work around it as well.

Also it would prooobably be another feature with gating, and probably work to test and stabilize it even if accepted, not just a "hey let's do this" and then in it goes into 1.75? So!

added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
T-langRelevant to the language team
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Oct 5, 2023
self-assigned this
on Oct 5, 2023
removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Oct 6, 2023
added and removed on Mar 14, 2024
added
A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)
and removed on Dec 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)C-enhancementCategory: An issue proposing an enhancement or a PR with one.F-const_refs_to_cell`#[feature(const_refs_to_cell)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @RalfJung@oli-obk@ilyvion@Cerber-Ursi@asquared31415

      Issue actions

        Can't write generic `const fn`s · Issue #116354 · rust-lang/rust