Skip to content
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

Initial start at summarizing unstable const discussion #46

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Mark-Simulacrum
Copy link
Member

I think this is a decent initial start, but might be a bit longer than we want -- maybe could use a TL;DR or checklist of some kind.

r? @m-ou-se

Comment on lines +97 to +100
**Replacing a derive with a manual impl**: generally not permitted, see
[#102371](https://github.com/rust-lang/rust/issues/102371) for context. We are
waiting on const-derive being implemented to avoid an increase in manual
implementations throughout the standard library.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does rust-lang/rust#102049 mean this section can be removed

Does making this API const require that code be hand-written which was previously automatic?

Does the new code require duplicating, for example through `#[cfg(bootstrap)]`,
increasing the risk of diverging between the two implementations (and
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik this has never happened before. tests are run on not(bootstrap) mode, and that is the only relevant mode afaict.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's pretty clear that duplicating ~100+ lines of code is a recipe for editing only one of those copies. We don't always have a regression test (e.g., for performance improvements), and due to git these edits may happen entirely in parallel in terms of PRs.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but we have never seen this happen to my knowledge.

Comment on lines +38 to +39
example, if a trait is made const, that likely means all implementations in the
standard library have to be const too. It may not be the case that this is easy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is never and will never be true. A const trait can have non-const impls, otherwise we'd not be able to mark any traits as const.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, maybe a poor example. I suspect there are some things like this though? e.g., my understanding is that today a const impl is either all const (for every method). I'm happy to reword with help on where the limitation actually is.

(Obviously future work may remove those constraints, but this document is very much emphasizing current reality - or even cfg(bootstrap) reality).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, yes, that makes a lot more sense ^^. Either all default methods on a trait are const or none.

While I disagree with the policy (we could just make them all const for now and revert the constness if it becomes a problem), I'm fine following it to save everyone headaches

Comment on lines +45 to +55
When making an internal (or external) API `const`, it becomes harder to
evaluate whether a given standard library function is safe to stabilize as
const. One of its dependencies may take a long time to stabilize for
const-evaluation, even though its API doesn't obviously reference unstable
surface area.

For example, a function like `[T]::get_many_mut` may rely on
sorting to guarantee distinct indices. If sorting is made unstably const, it is
difficult to know when looking at `get_many_mut` whether it is OK to
const-stabilize it: you have to inspect the full dependency tree with knowledge
of the "fully determined" const surface area.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have logic to automate this. You cannot stabilize a const fn's constness if it calls unstable const fns unless you explicitly add #[rustc_allow_const_fn_unstable(foo, bar)]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all transitively called const fns required to be either stable or unstable by annotation? It was my impression that private helpers are sometimes const but not tagged with a const stability marker. Maybe bad memory on my part though.

Copy link
Member

@fee1-dead fee1-dead Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

untagged functions are const stable by default, so you can't call unstable functions in the body unless you tag it

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm... I should add tests, but I'm fairly certain you can only avoid the stability marker if you're already unstable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compiles fine today (just threw this into library/core/src/lib.rs). To me that looks like it's exposing in a const-stable function functionality that might depend on const-eval-select (obviously this example doesn't but it's no guarantee).

Even if we forbid this, we'll want some language here about the thought process for adding const_stable to internal functions -- I suspect we're not very good at having rules there yet.

  const fn foo() {
      unsafe { crate::intrinsics::const_eval_select((), comp, run) }
  }

  const fn comp() {}
  fn run() {}

  #[stable(feature = "unreachable", since = "1.27.0")]
  #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
  pub const fn hidden_danger() {
      foo();
  }

Copy link

@oli-obk oli-obk Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes. I remember that there was some issue with not being able to add those attributes to functions that don't already have stable/unstable attributes, but that seems to have gotten fixed: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9df5e879c896456abcf21973709242b8 so we could now start checking that internal functions have const stability attributes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cc rust-lang/rust#103193 - looks like a practical example of this case, presumably there's more hiding.

Comment on lines +45 to +49
When making an internal (or external) API `const`, it becomes harder to
evaluate whether a given standard library function is safe to stabilize as
const. One of its dependencies may take a long time to stabilize for
const-evaluation, even though its API doesn't obviously reference unstable
surface area.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused by this point here. If an API isn't const in the first place, then we don't need to evaluate whether it is okay to stabilize as const. If it is, then we can always split the feature up if unsure.

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

Successfully merging this pull request may close these issues.

4 participants