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

Make slice->str conversion and related functions const #90607

Merged
merged 2 commits into from
Nov 18, 2021

Conversation

WaffleLapkin
Copy link
Member

This PR marks the following APIs as const:

// core::str
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>;
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error>;
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str;

impl Utf8Error {
    pub const fn valid_up_to(&self) -> usize;
    pub const fn error_len(&self) -> Option<usize>;
}

Everything but from_utf8_unchecked_mut uses const_str_from_utf8 feature gate, from_utf8_unchecked_mut uses const_str_from_utf8_unchecked_mut feature gate.


I'm not sure why from_utf8_unchecked_mut was left out being non-const, considering that from_utf8_unchecked is not only const, but const stable.


r? @oli-obk (performance-only const_eval_select use)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 5, 2021
// algorithm correctness can not depend on `align_offset` returning non-max values.
//
// As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
let align = unsafe { const_eval_select((v, usize_bytes), ctfe_align, rt_align) };
Copy link
Member

Choose a reason for hiding this comment

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

It seems better to put this inside align_offset itself, since the justification should work for all calls to it, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

While I think it would be great to put this inside align_offset itself, wouldn't this allow for user code to behave differently in const and non-const context?

const fn is_likely_called_in_ctfe() -> bool {
    let arr = [0u8; 2];
    (&arr[0] as *const u8).align_offset(2) == usize::MAX 
        && (&arr[1] as *const u8).align_offset(2) == usize::MAX
}

(playground)

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually even (&0u8 as *const u8).align_offset(1) == usize::MAX will do. Basically while const_eval_select in the caller of align_offset shouldn't change behaviour, const_eval_select in align_offset itself clearly changes it's return value depending on whatever it's called at runtime or compile time.

Sadly, it seems that we don't want to allow this, right? :(

Copy link
Contributor

Choose a reason for hiding this comment

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

const_eval_select in align_offset itself clearly changes it's return value depending on whatever it's called at runtime or compile time.

Sadly, it seems that we don't want to allow this, right? :(

Actually, the docs specifically state

If it is not possible to align the pointer, the implementation returns usize::MAX. It is permissible for the implementation to always return usize::MAX. Only your algorithm’s performance can depend on getting a usable offset here, not its correctness.
There are no guarantees whatsoever that offsetting the pointer will not overflow or go beyond the allocation that the pointer points into. It is up to the caller to ensure that the returned offset is correct in all terms other than alignment.

The only reason align_offset even exists is because I wanted to enable miri to do such trickery back when it wasn't able to do ptr2int conversions.

So, we can definitely make align_offset behave this way in const fn, as long as we have a tracking issue for the const stabilization that specifically raises this concern before we bake it into a stabilized function.

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 can make a follow-up PR then

Copy link
Contributor

Choose a reason for hiding this comment

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

I have a slight preference for doing a PR for just align_offset first, since then this PR does less work, but if you prefer to first merge this one I'm ok with that.

Copy link
Member Author

@WaffleLapkin WaffleLapkin Nov 16, 2021

Choose a reason for hiding this comment

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

I can do either way if you prefer align_offset first, then so be it :)

Upd: I've opened #90958

@apiraino apiraino added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Nov 11, 2021
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Nov 16, 2021
…oli-obk

Mark `<*const _>::align_offset` and `<*mut _>::align_offset` as `const fn`

This PR marks the following APIs as `const`:
```rust
impl<T> *const T {
    pub const fn align_offset(self, align: usize) -> usize;
}

impl<T> *mut T {
    pub const fn align_offset(self, align: usize) -> usize;
}
```

`const` implementation simply returns `usize::MAX`.

---

Previous discussion: rust-lang#90607 (comment)

---

r? `@oli-obk`
This commit makes the following functions from `core::str` `const fn`:
- `from_utf8[_mut]` (`feature(const_str_from_utf8)`)
- `from_utf8_unchecked_mut` (`feature(const_str_from_utf8_unchecked_mut)`)
- `Utf8Error::{valid_up_to,error_len}` (`feature(const_str_from_utf8)`)
@WaffleLapkin
Copy link
Member Author

@oli-obk I've rebased to use #90958 & applied suggestions from your review

@oli-obk
Copy link
Contributor

oli-obk commented Nov 18, 2021

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Nov 18, 2021

📌 Commit cf6f64a has been approved by oli-obk

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 18, 2021
@WaffleLapkin
Copy link
Member Author

WaffleLapkin commented Nov 18, 2021

wait, shouldn't we create a tracking issue first?

Upd: I've filled in the tracking issues, not sure how bors will work with this

@oli-obk
Copy link
Contributor

oli-obk commented Nov 18, 2021

Oops thanks!

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Nov 18, 2021

📌 Commit 573a00e has been approved by oli-obk

JohnTitor added a commit to JohnTitor/rust that referenced this pull request Nov 18, 2021
…=oli-obk

Make slice->str conversion and related functions `const`

This PR marks the following APIs as `const`:
```rust
// core::str
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>;
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error>;
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str;

impl Utf8Error {
    pub const fn valid_up_to(&self) -> usize;
    pub const fn error_len(&self) -> Option<usize>;
}
```

Everything but `from_utf8_unchecked_mut` uses `const_str_from_utf8` feature gate, `from_utf8_unchecked_mut` uses `const_str_from_utf8_unchecked_mut` feature gate.

---

I'm not sure why `from_utf8_unchecked_mut` was left out being  non-`const`, considering that `from_utf8_unchecked` is not only `const`, but **`const` stable**.

---

r? `@oli-obk` (performance-only `const_eval_select` use)
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Nov 18, 2021
…=oli-obk

Make slice->str conversion and related functions `const`

This PR marks the following APIs as `const`:
```rust
// core::str
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>;
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error>;
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str;

impl Utf8Error {
    pub const fn valid_up_to(&self) -> usize;
    pub const fn error_len(&self) -> Option<usize>;
}
```

Everything but `from_utf8_unchecked_mut` uses `const_str_from_utf8` feature gate, `from_utf8_unchecked_mut` uses `const_str_from_utf8_unchecked_mut` feature gate.

---

I'm not sure why `from_utf8_unchecked_mut` was left out being  non-`const`, considering that `from_utf8_unchecked` is not only `const`, but **`const` stable**.

---

r? ``@oli-obk`` (performance-only `const_eval_select` use)
bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 18, 2021
Rollup of 8 pull requests

Successful merges:

 - rust-lang#90386 (Add `-Zassert-incr-state` to assert state of incremental cache)
 - rust-lang#90438 (Clean up mess for --show-coverage documentation)
 - rust-lang#90480 (Mention `Vec::remove` in `Vec::swap_remove`'s docs)
 - rust-lang#90607 (Make slice->str conversion and related functions `const`)
 - rust-lang#90750 (rustdoc: Replace where-bounded Clean impl with simple function)
 - rust-lang#90895 (require full validity when determining the discriminant of a value)
 - rust-lang#90989 (Avoid suggesting literal formatting that turns into member access)
 - rust-lang#91002 (rustc: Remove `#[rustc_synthetic]`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 77c985f into rust-lang:master Nov 18, 2021
@rustbot rustbot added this to the 1.58.0 milestone Nov 18, 2021
@WaffleLapkin WaffleLapkin deleted the const_str_from_utf8 branch November 19, 2021 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants