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

const-eval interning: get rid of type-driven traversal #119044

Merged
merged 4 commits into from
Jan 23, 2024

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented Dec 17, 2023

This entirely replaces our const-eval interner, i.e. the code that takes the final result of a constant evaluation from the local memory of the const-eval machine to the global tcx memory. The main goal of this change is to ensure that we can detect mutable references that sneak into this final value -- this is something we want to reject for static and const, and while const-checking performs some static analysis to ensure this, I would be much more comfortable stabilizing const_mut_refs if we had a dynamic check that sanitizes the final value. (This is generally the approach we have been using on const-eval: do a static check to give nice errors upfront, and then do a dynamic check to be really sure that the properties we need for soundness, actually hold.)

We can do this now that #118324 landed and each pointer comes with a bit (completely independent of its type) storing whether mutation is permitted through this pointer or not.

The new interner is a lot simpler than the old one: previously we did a complete type-driven traversal to determine the mutability of all memory we see, and then a second pass to intern any leftover raw pointers. The new interner simply recursively traverses the allocation holding the final result, and all allocations reachable from it (which can be determined from the raw bytes of the result, without knowing anything about types), and ensures they all get interned. The initial allocation is interned as immutable for const and pomoted and non-interior-mutable static; all other allocations are interned as immutable for static, const, and promoted. The main subtlety is justifying that those inner allocations may indeed be interned immutably, i.e., that mutating them later would anyway already be UB:

  • for promoteds, we rely on the analysis that does promotion to ensure that this is sound.
  • for const and static, we check that all pointers in the final result that point to things that are new (i.e., part of this const evaluation) are immutable, i.e., were created via &<expr> at a non-interior-mutable type. Mutation through immutable pointers is UB so we are free to intern that memory as immutable.

Interning raises an error if it encounters a dangling pointer or a mutable pointer that violates the above rules.

I also extended our type-driven const validity checks to ensure that &mut T in the final value of a const points to mutable memory, at least if T is not zero-sized. This catches cases of people turning &i32 into &mut i32 (which would still be considered a read-only pointer). Similarly, when these checks encounter an UnsafeCell, they are checking that it lives in mutable memory. (Both of these only traverse the newly created values; if those point to other consts/promoteds, the check stops there. But that's okay, we don't have to catch all the UB.) I co-developed this with the stricter interner changes but I can split it out into a separate PR if you prefer.

This PR does have the immediate effect of allowing some new code on stable, for instance:

const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;

Previously that code got rejected since the type-based interner didn't know what to do with that pointer. It's a raw pointer, we cannot trust its type. The new interner does not care about types so it sees no issue with this code; there's an immutable pointer pointing to some read-only memory (storing a Vec<i32>), all is good. Accepting this code pretty much commits us to non-type-based interning, but I think that's the better strategy anyway.

This PR also leads to slightly worse error messages when the final value of a const contains a dangling reference. Previously we would complete interning and then the type-based validation would detect this dangling reference and show a nice error saying where in the value (i.e., in which field) the dangling reference is located. However, the new interner cannot distinguish dangling references from dangling raw pointers, so it must throw an error when it encounters either of them. It doesn't have an understanding of the value structure so all it can say is "somewhere in this constant there's a dangling pointer". (Later parts of the compiler don't like dangling pointers/references so we have to reject them either during interning or during validation.) This could potentially be improved by doing validation before interning, but that's a larger change that I have not attempted yet. (It's also subtle since we do want validation to use the final mutability bits of all involved allocations, and currently it is interning that marks a bunch of allocations as immutable -- that would have to still happen before validation.)

@rust-lang/wg-const-eval I hope you are okay with this plan. :)
@rust-lang/lang paging you in since this accepts new code on stable as explained above. Please let me know if you think FCP is necessary.

This is a successor to #116745.

@rustbot
Copy link
Collaborator

rustbot commented Dec 17, 2023

r? @wesleywiser

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 17, 2023
@rustbot
Copy link
Collaborator

rustbot commented Dec 17, 2023

Some changes occurred to the CTFE / Miri engine

cc @rust-lang/miri

The Miri subtree was changed

cc @rust-lang/miri

Some changes occurred to the CTFE / Miri engine

cc @rust-lang/miri

@RalfJung
Copy link
Member Author

There are perf results here, and they look quite positive. :)

@RalfJung RalfJung added T-lang Relevant to the language team, which will review and decide on the PR/issue. A-const-eval Area: constant evaluation (mir interpretation) I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. labels Dec 17, 2023
@tmandry
Copy link
Member

tmandry commented Dec 20, 2023

We discussed this in the lang team meeting but didn't entirely grok what it does from the description.

@RalfJung Can you give an algorithmic summary of the check we used to do and the check this PR implements, along with an example of something that wouldn't compile under this PR?

@traviscross
Copy link
Contributor

@RalfJung: In terms of the algorithmic summary mentioned by @tmandry, it may help if you could step us carefully through why...

const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;

...this example does not compile today and the theory and algorithm of why it would under this PR.

@RalfJung
Copy link
Member Author

RalfJung commented Dec 21, 2023

To give some context, the only non-trivial job the interner has is to decide with which mutability the allocations found in the just-evaluated constant should be interned. Allocations generally start out mutable (after all, they are uninitialized at first and then have their initial value written into them during const-eval, which requires them to be mutable), but we want to put them in read-only memory in the final binary if possible.

Usually there is only a single allocation to be interned: the one that holds the final value of the constant. However, there is some code we accept where there is more than one allocation to intern. For instance:

const CONST_VEC: &Vec<i32> = &Vec::new();

There are two allocations to intern here, the one that stores the Vec and the one that stores the reference to the Vec. We sometimes call these secondary allocations that also need interning "inner" allocations.

(This is not promotion! Vec does not get promoted since it has a destructor. Instead this is the "outer scope rule" that gives certain expressions the lifetime of the "outer" scope. For const/static, the "outer" scope is 'static, i.e., this implicitly creates another global. This seems to be somewhat accidental, or at least it was never properly specified or discussed to my knowledge. It also causes some subtle bugs since we do not have a system in place to manage the identity of these globals.)

Old interner

The old interner works as follows: we do a type-based traversal of the final value of the const. That means we recursively go through fields of structs, tuples, enums, ... and when we encounter a reference we also descend into that.

During this descend, we keep track of the current mutability. We start out immutable (except for static mut where we start mutable). When we go into an UnsafeCell we switch to mutable. When we encounter a shared reference we switch to immutable. When we hit a reference to a not-yet-interned allocation, we use the current mutability plus a Freeze check to determine whether to intern that as mutable or immutable.

We also keep track of any other pointer values we find that are not references (raw pointers, things in union fields, and in theory there could also be pointers stored in padding between fields and similar nasty things). These are the "leftover" pointers. In static, we intern everything from that list as mutable; in const, we raise an error if there are any leftover pointers.

New interner

The new internet is a lot simpler. Our goal with static and const is to intern everything as immutable, except possibly the original allocation storing the value itself: a static A: AtomicUisze must be put in mutable memory, of course. We just have to verify that this is sound. To this end we recursively traverse all pointers that we find (this doesn't require type-based traversal, pointers are special magic values and we can easily find them all -- we just don't know their type). All pointers to newly interned "inner" allocations must be immutable, i.e., they must be derived from a shared reference without interior mutability.

This relies on #118324, where we now track at const-eval time, using provenance, whether a pointer is mutable or not. When evaluating an &<place> expression, if the pointee is Freeze, we set that pointer as immutable, and all pointers derived from this inherit that bit.

This allows us to reject, for instance

const NOT_ACTUALLY_CONST_VEC: *const Vec<i32> = &mut Vec::new() as *mut _ as *const _;

We have to reject that code since if we accepted it, arguably we should say that NOT_ACTUALLY_CONST_VEC.cast_mut().write(...) is allowed -- there's nothing that would cause UB here, the pointer we are writing to was created via &mut after all. But we don't want const to implicitly create global mutable state.

Changes in behavior

This example used to be rejected due to leftover pointers:

const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;

The concept of a leftover pointer no longer exists, so we no longer reject this.

Note that this is still rejected:

const CONST_RAW: *const Vec<i32> = ptr::addr_of!(Vec::new());

Raw pointers to temporaries are not allowed; only references. (This is not even a const-check I think, but a more general rule.)

I am not aware of any code that we currently accept, that would get rejected after this change. We already refuse all code that would cause inner allocations with interior mutability to be created. However, the checks for that are a bit scattered and indirect; the new interner serves as a second line of defense to ensure that we really do not ever accept such code. We have "miri unleashed" tests to ensure this. (These tests disable many of the usual const checks, accepting basically anything in a const fn that the interpreter is able to execute.)

There might be things you can do with const_mut_refs or const_refs_to_cell that would be rejected now, but those are unstable features and we want to restrict them to ensure that nothing mutable leaks into the final value. Anything we currently accept there would be a bug. Closing any holes that we might currently have in these unstable features is the main motivation for this PR.

@bors
Copy link
Contributor

bors commented Dec 26, 2023

☔ The latest upstream changes (presumably #119146) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung RalfJung force-pushed the intern-without-types branch 2 times, most recently from 5050583 to a97ab84 Compare December 26, 2023 07:57
compiler/rustc_const_eval/src/interpret/validity.rs Outdated Show resolved Hide resolved
compiler/rustc_const_eval/src/interpret/validity.rs Outdated Show resolved Hide resolved
// Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory.
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
if !op.layout.is_zst() && !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
if !self.in_mutable_memory(op) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why this additional check? Won't this also allow more code to compile?

Copy link
Member Author

Choose a reason for hiding this comment

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

How can this allow more code to compile? It rejects !Freeze unions in immutable memory. This is basically the union version of what we are checking here.

We could debate whether we should have that check; such UnsafeCell are actually fine if you don't write to them. They are certainly suspicious though.

compiler/rustc_const_eval/src/interpret/intern.rs Outdated Show resolved Hide resolved
@tmandry tmandry removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jan 3, 2024
@tmandry
Copy link
Member

tmandry commented Jan 3, 2024

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Jan 3, 2024

Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jan 3, 2024
@tmandry tmandry added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jan 3, 2024
@rust-log-analyzer

This comment has been minimized.

@nikomatsakis
Copy link
Contributor

@rfcbot reviewed

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Jan 4, 2024
@rfcbot
Copy link

rfcbot commented Jan 4, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@nikomatsakis
Copy link
Contributor

One thing that seems important to me here is that we already have precedent for "value-based" restrictions, since e.g. I believe const X: Option<Foo> = None works for any Foo.

@RalfJung
Copy link
Member Author

RalfJung commented Jan 5, 2024 via email

RalfJung and others added 2 commits January 22, 2024 09:28
@RalfJung
Copy link
Member Author

@bors r=oli-obk

@bors
Copy link
Contributor

bors commented Jan 22, 2024

📌 Commit 2ab85e4 has been approved by oli-obk

It is now in the queue for this repository.

@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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 22, 2024
@bors
Copy link
Contributor

bors commented Jan 23, 2024

⌛ Testing commit 2ab85e4 with merge 6265a95...

@bors
Copy link
Contributor

bors commented Jan 23, 2024

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing 6265a95 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jan 23, 2024
@bors bors merged commit 6265a95 into rust-lang:master Jan 23, 2024
12 checks passed
@rustbot rustbot added this to the 1.77.0 milestone Jan 23, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (6265a95): comparison URL.

Overall result: ✅ improvements - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.9% [-1.1%, -0.8%] 3
Improvements ✅
(secondary)
-3.8% [-8.0%, -0.6%] 14
All ❌✅ (primary) -0.9% [-1.1%, -0.8%] 3

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.0% [3.0%, 3.0%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-6.0% [-8.8%, -3.5%] 9
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 661.891s -> 662.447s (0.08%)
Artifact size: 308.33 MiB -> 308.28 MiB (-0.01%)

@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Jan 25, 2024
@RalfJung RalfJung deleted the intern-without-types branch January 26, 2024 06:43
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 6, 2024
…li-obk

unstably allow constants to refer to statics and read from immutable statics

I am not aware of any fundamental reason why we cannot allow constants to mention statics. What we really need is that constants do not *read from* statics that can change their value:
- This would break the principle that "constants behave as-if their expression was inlined everywhere and executed at runtime". This is enforced by halting const-eval interpretation when a read from a mutable global occurs.
- When building a valtree we want to be sure that the constant and everything it refers to is truly immutable. This is enforced by aborting valtree construction when a read from a mutable global occurs.

r? `@oli-obk` -- if you are okay with experimenting with this feature, I will create a tracking issue.
Based on and blocked on rust-lang#119044; only the last commit is new.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 6, 2024
…alfJung

various const interning cleanups

After rust-lang#119044 I noticed that some things can be simplified and refactored.

This is also a requirement for rust-lang#116564 as there we'll need to treat the base allocation differently from the others

r? `@RalfJung`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 6, 2024
…alfJung

various const interning cleanups

After rust-lang#119044 I noticed that some things can be simplified and refactored.

This is also a requirement for rust-lang#116564 as there we'll need to treat the base allocation differently from the others

r? ``@RalfJung``
Nadrieril added a commit to Nadrieril/rust that referenced this pull request Feb 7, 2024
…alfJung

various const interning cleanups

After rust-lang#119044 I noticed that some things can be simplified and refactored.

This is also a requirement for rust-lang#116564 as there we'll need to treat the base allocation differently from the others

r? ```@RalfJung```
Nadrieril added a commit to Nadrieril/rust that referenced this pull request Feb 7, 2024
…alfJung

various const interning cleanups

After rust-lang#119044 I noticed that some things can be simplified and refactored.

This is also a requirement for rust-lang#116564 as there we'll need to treat the base allocation differently from the others

r? ````@RalfJung````
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 7, 2024
Rollup merge of rust-lang#120302 - oli-obk:const_intern_cleanups, r=RalfJung

various const interning cleanups

After rust-lang#119044 I noticed that some things can be simplified and refactored.

This is also a requirement for rust-lang#116564 as there we'll need to treat the base allocation differently from the others

r? ````@RalfJung````
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 10, 2024
…-obk

unstably allow constants to refer to statics and read from immutable statics

I am not aware of any fundamental reason why we cannot allow constants to mention statics. What we really need is that constants do not *read from* statics that can change their value:
- This would break the principle that "constants behave as-if their expression was inlined everywhere and executed at runtime". This is enforced by halting const-eval interpretation when a read from a mutable global occurs.
- When building a valtree we want to be sure that the constant and everything it refers to is truly immutable. This is enforced by aborting valtree construction when a read from a mutable global occurs.

r? `@oli-obk` -- if you are okay with experimenting with this feature, I will create a tracking issue.
Based on and blocked on rust-lang#119044; only the last commit is new.
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 10, 2024
…-obk

unstably allow constants to refer to statics and read from immutable statics

I am not aware of any fundamental reason why we cannot allow constants to mention statics. What we really need is that constants do not *read from* statics that can change their value:
- This would break the principle that "constants behave as-if their expression was inlined everywhere and executed at runtime". This is enforced by halting const-eval interpretation when a read from a mutable global occurs.
- When building a valtree we want to be sure that the constant and everything it refers to is truly immutable. This is enforced by aborting valtree construction when a read from a mutable global occurs.

r? `@oli-obk` -- if you are okay with experimenting with this feature, I will create a tracking issue.
Based on and blocked on rust-lang#119044; only the last commit is new.
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Feb 11, 2024
unstably allow constants to refer to statics and read from immutable statics

I am not aware of any fundamental reason why we cannot allow constants to mention statics. What we really need is that constants do not *read from* statics that can change their value:
- This would break the principle that "constants behave as-if their expression was inlined everywhere and executed at runtime". This is enforced by halting const-eval interpretation when a read from a mutable global occurs.
- When building a valtree we want to be sure that the constant and everything it refers to is truly immutable. This is enforced by aborting valtree construction when a read from a mutable global occurs.

r? `@oli-obk` -- if you are okay with experimenting with this feature, I will create a tracking issue.
Based on and blocked on rust-lang/rust#119044; only the last commit is new.
@RalfJung
Copy link
Member Author

Turns out this was actually an accidental breaking change: #121610.

wip-sync pushed a commit to NetBSD/pkgsrc-wip that referenced this pull request Mar 29, 2024
Pkgsrc changes:
 * Adapt checksums and patches.

Upstream chnages:

Version 1.77.0 (2024-03-21)
==========================

- [Reveal opaque types within the defining body for exhaustiveness checking.]
  (rust-lang/rust#116821)
- [Stabilize C-string literals.]
  (rust-lang/rust#117472)
- [Stabilize THIR unsafeck.]
  (rust-lang/rust#117673)
- [Add lint `static_mut_refs` to warn on references to mutable statics.]
  (rust-lang/rust#117556)
- [Support async recursive calls (as long as they have indirection).]
  (rust-lang/rust#117703)
- [Undeprecate lint `unstable_features` and make use of it in the compiler.]
  (rust-lang/rust#118639)
- [Make inductive cycles in coherence ambiguous always.]
  (rust-lang/rust#118649)
- [Get rid of type-driven traversal in const-eval interning]
  (rust-lang/rust#119044),
  only as a [future compatiblity lint]
  (rust-lang/rust#122204) for now.
- [Deny braced macro invocations in let-else.]
  (rust-lang/rust#119062)

Compiler
--------

- [Include lint `soft_unstable` in future breakage reports.]
  (rust-lang/rust#116274)
- [Make `i128` and `u128` 16-byte aligned on x86-based targets.]
  (rust-lang/rust#116672)
- [Use `--verbose` in diagnostic output.]
  (rust-lang/rust#119129)
- [Improve spacing between printed tokens.]
  (rust-lang/rust#120227)
- [Merge the `unused_tuple_struct_fields` lint into `dead_code`.]
  (rust-lang/rust#118297)
- [Error on incorrect implied bounds in well-formedness check]
  (rust-lang/rust#118553),
  with a temporary exception for Bevy.
- [Fix coverage instrumentation/reports for non-ASCII source code.]
  (rust-lang/rust#119033)
- [Fix `fn`/`const` items implied bounds and well-formedness check.]
  (rust-lang/rust#120019)
- [Promote `riscv32{im|imafc}-unknown-none-elf` targets to tier 2.]
  (rust-lang/rust#118704)
- Add several new tier 3 targets:
  - [`aarch64-unknown-illumos`]
    (rust-lang/rust#112936)
  - [`hexagon-unknown-none-elf`]
    (rust-lang/rust#117601)
  - [`riscv32imafc-esp-espidf`]
    (rust-lang/rust#119738)
  - [`riscv32im-risc0-zkvm-elf`]
    (rust-lang/rust#117958)

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

Libraries
---------

- [Implement `From<&[T; N]>` for `Cow<[T]>`.]
  (rust-lang/rust#113489)
- [Remove special-case handling of `vec.split_off
  (0)`.](rust-lang/rust#119917)

Stabilized APIs
---------------

- [`array::each_ref`]
  (https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_ref)
- [`array::each_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_mut)
- [`core::net`]
  (https://doc.rust-lang.org/stable/core/net/index.html)
- [`f32::round_ties_even`]
  (https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even)
- [`f64::round_ties_even`]
  (https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even)
- [`mem::offset_of!`]
  (https://doc.rust-lang.org/stable/std/mem/macro.offset_of.html)
- [`slice::first_chunk`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first_chunk)
- [`slice::first_chunk_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first_chunk_mut)
- [`slice::split_first_chunk`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first_chunk)
- [`slice::split_first_chunk_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first_chunk_mut)
- [`slice::last_chunk`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last_chunk)
- [`slice::last_chunk_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last_chunk_mut)
- [`slice::split_last_chunk`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last_chunk)
- [`slice::split_last_chunk_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last_chunk_mut)
- [`slice::chunk_by`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.chunk_by)
- [`slice::chunk_by_mut`]
  (https://doc.rust-lang.org/stable/std/primitive.slice.html#method.chunk_by_mut)
- [`Bound::map`]
  (https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.map)
- [`File::create_new`]
  (https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create_new)
- [`Mutex::clear_poison`]
  (https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#method.clear_poison)
- [`RwLock::clear_poison`]
  (https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html#method.clear_poison)

Cargo
-----

- [Extend the build directive syntax with `cargo::`.]
  (rust-lang/cargo#12201)
- [Stabilize metadata `id` format as `PackageIDSpec`.]
  (rust-lang/cargo#12914)
- [Pull out as `cargo-util-schemas` as a crate.]
  (rust-lang/cargo#13178)
- [Strip all debuginfo when debuginfo is not requested.]
  (rust-lang/cargo#13257)
- [Inherit jobserver from env for all kinds of runners.]
  (rust-lang/cargo#12776)
- [Deprecate rustc plugin support in cargo.]
  (rust-lang/cargo#13248)

Rustdoc
-----

- [Allows links in markdown headings.]
  (rust-lang/rust#117662)
- [Search for tuples and unit by type with `()`.]
  (rust-lang/rust#118194)
- [Clean up the source sidebar's hide button.]
  (rust-lang/rust#119066)
- [Prevent JS injection from `localStorage`.]
  (rust-lang/rust#120250)

Misc
----

- [Recommend version-sorting for all sorting in style guide.]
  (rust-lang/rust#115046)

Internal Changes
----------------

These changes do not affect any public interfaces of Rust, but they represent
significant improvements to the performance or internals of rustc and related
tools.

- [Add more weirdness to `weird-exprs.rs`.]
  (rust-lang/rust#119028)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: constant evaluation (mir interpretation) disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet