From 2cfef78218487fdca0b66c4755050fcb36fa14aa Mon Sep 17 00:00:00 2001 From: ltdk Date: Fri, 18 Sep 2026 14:30:56 -0400 Subject: [PATCH] Commiting work on docs --- src/SUMMARY.md | 17 +- src/libs/apis/changing.md | 159 ++++++++++++ src/libs/apis/fixing.md | 57 +++++ src/libs/apis/index.md | 20 ++ src/libs/apis/proposals.md | 62 +++++ src/libs/apis/stabilization.md | 60 +++++ src/libs/impls/crates.md | 3 + src/libs/impls/index.md | 24 ++ src/libs/impls/perf-benchmarking.md | 109 +++++++++ src/libs/impls/review.md | 13 + src/libs/impls/targets.md | 3 + src/libs/impls/testing-debugging.md | 7 + src/libs/index.md | 23 +- src/libs/maintaining-std.md | 358 ---------------------------- src/libs/meetings.md | 23 ++ src/libs/membership.md | 124 ++++++++++ src/libs/repositories.md | 89 +++++++ 17 files changed, 783 insertions(+), 368 deletions(-) create mode 100644 src/libs/apis/changing.md create mode 100644 src/libs/apis/fixing.md create mode 100644 src/libs/apis/index.md create mode 100644 src/libs/apis/proposals.md create mode 100644 src/libs/apis/stabilization.md create mode 100644 src/libs/impls/crates.md create mode 100644 src/libs/impls/index.md create mode 100644 src/libs/impls/perf-benchmarking.md create mode 100644 src/libs/impls/review.md create mode 100644 src/libs/impls/targets.md create mode 100644 src/libs/impls/testing-debugging.md delete mode 100644 src/libs/maintaining-std.md create mode 100644 src/libs/meetings.md create mode 100644 src/libs/membership.md create mode 100644 src/libs/repositories.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3628f53e1..d125ae62d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -124,8 +124,21 @@ - [Language](./lang/index.md) - [RFC Merge Procedure](./lang/rfc-merge-procedure.md) - [Stabilization procedure](./lang/stabilization-procedure.md) -- [Libs](./libs/index.md) - - [Maintaining the standard library](./libs/maintaining-std.md) +- [Library](./libs/index.md) + - [Maintaining APIs](./libs/apis/index.md) + - [API Change Proposals (ACPs)](./libs/apis/proposals.md) + - [Changing APIs](./libs/apis/changing.md) + - [API stabilization](./libs/apis/stabilization.md) + - [Fixing APIs](./libs/apis/fixing.md) + - [Maintaining Implementations](./libs/impls/index.md) + - [Code review](./libs/impls/review.md) + - [Crate maintenance](./libs/impls/crates.md) + - [Target tiers](./libs/impls/targets.md) + - [Testing and debugging](./libs/impls/testing-debugging.md) + - [Performance and benchmarking](./libs/impls/perf-benchmarking.md) + - [Meetings](./libs/meetings.md) + - [Membership](./libs/membership.md) + - [Repositories](./libs/repositories.md) - [Release](./release/index.md) - [Backporting](./release/backporting.md) - [Preparing Release Notes](./release/release-notes.md) diff --git a/src/libs/apis/changing.md b/src/libs/apis/changing.md new file mode 100644 index 000000000..4c2c9a6fb --- /dev/null +++ b/src/libs/apis/changing.md @@ -0,0 +1,159 @@ +# Changing APIs + +All new guarantees made by the standard library need [an FCP](../membership.md#fcp-process), but what constitutes a new guarantee or breaking change is extremely unclear. This list attempts to cover as many cases as possible that need stabilization based upon experience, although it definitely may be incomplete. + +For changes which aren't of concern for API surface, see the section on [code review]. + +[code review]: ../impls/review.md + +## API surface + +Any new API added to the standard library needs an FCP. New types, new methods, new traits, and new trait implementations all represent changes that need an FCP to make. These will usually, but not always, involve changing an `#[unstable]` attribute to a `#[stable]` attribute, or a `#[rustc_const_unstable]` attribute to a `#[rustc_const_stable]` attribute. Note that stability attributes will also change from including a tracking issue to a Rust version, and the special `CURRENT_RUSTC_VERSION` string should be used for new stabilizations; these will be replaced with the correct version when the version is actually released. + +## Implementation-derived guarantees + +There are several ways that changing Rust code can unintentionally make new guarantees for an API. For example, changing trait bounds *usually* represents a new guarantee, although some bounds can never be changed due to them *removing* guarantees. Changing [restrictions] (unstable) can also affect guarantees. + +[restrictions]: https://github.com/rust-lang/rust/issues/105077 + +Even outside trait bounds, changing the inner contents of a type may affect its [variance] in ways which are publicly noticeable, which are new guarantees. The contents of a type may also subtly affect its implementation of [auto traits] like [`Send`] and [`Sync`] which can cause publicly noticeable changes. + +[variance]: https://doc.rust-lang.org/nightly/reference/subtyping.html#subtyping.variance +[auto traits]: https://doc.rust-lang.org/nightly/reference/special-types-and-traits.html#auto-traits +[`Send`]: https://doc.rust-lang.org/nightly/std/marker/trait.Send.html +[`Sync`]: https://doc.rust-lang.org/nightly/std/marker/trait.Sync.html + +## Type inference + +[RFC 1105] explicitly details what kinds of breakages are considered acceptable, and one of those breakages is adding new trait implementations. Unfortunately, things aren't that easy. + +[RFC 1105]: https://rust-lang.github.io/rfcs/1105-api-evolution.html + +Due to the way the type system works, type inference can break if new trait implementations are added. For example, imagine the following trait impl: + +```rust +impl From<&str> for Arc { /* ... */ } +``` + +With only this impl, the following code works and will correctly infer a conversion from `&str` to `Arc`: + +```rust +let b = Arc::from("a"); +``` + +However, if we add a new impl: + +```rust +impl From<&str> for Arc<[u8]> { /* ... */ } +``` + +All of a sudden, the code becomes ambiguous; the type of the result cannot be inferred from the method call. Technically, breakages like this are allowed by our guarantees, but if too many Rust users rely on it, we may decide to disallow them anyway. Similarly, generalizing methods with traits can *also* have this kind of issue, for example: + +```rust +fn new(a: &str) -> Arc +where + Arc: From<&str> +{ /* ... */ } +``` + +has the same issue. Sometimes, even adding *unstable* features can still result in inference failures. + +While [crater] can be used to determine the exact impact of a change on the larger ecosystem, it is not bulletproof and the team may choose to be overly cautious when accepting changes. + +## Deref coercion + +In addition to type inference, deref coercion can also break depending on new implementations. For example, with just the following: + +```rust +impl Deref for String { type Target = str; /* ... */ } +impl Add<&str> for String { /* ... */ } +``` + +The following code works, since `b` is deref-coerced from `&String` into `&str`: + +```rust +let a = String::from("a"); +let b = String::from("b"); +let c = a + &b; +``` + +However, if we add a new impl: + +```rust +impl Add for String { /* ... */ } +``` + +Suddenly, Rust won't perform deref coercion and complain about `Add<&String>` missing instead. These types of cases are especially tricky to notice. + +## Method resolution + +New methods can sometimes affect code in unpredictable ways. For example, unstable methods added to `Iterator` with the same name as methods on other popular crates like [`itertools`] can cause unintended side effects. In general, these cases will trigger the [`unstable-name-collisions` lint], but libs can still be reluctant to make changes for extremely common method names. In the past, we've even made [dedicated compiler workarounds], [multiple times] to get around method resolution issues. + +[`Iterator`]: https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html +[`itertools`]: https://docs.rs/itertools +[`unstable-name-collisions` lint]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unstable-name-collisions +[dedicated compiler workarounds]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html +[multiple times]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/IntoIterator-box-slice.html + +This also includes the case where `TryFrom` and `TryInto` were added to the prelude for [future editions] due to method resolution issues. + +[future editions]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html + +## Macro resolution + +Due to a current bug in the compiler(?), unstable macros have the same priority as stable macros and macro additions can have noticeable effects on crates *even when unstable*. This was encountered when attempting to create the [`assert_matches!` macro]. + +[`assert_matches!` macro]: https://github.com/rust-lang/rust/issues/82913 + +## Unspecified behavior + +In general, users of the standard library shouldn't rely on undocumented guarantees of APIs, but sometimes, it happens anyway. Every beta release of Rust is run through [crater] to find regressions across the ecosystem, and sometimes, this means that the library team will need to FCP changes that already were made, or ones that can technically be made within our guarantees. + +[crater]: https://rustc-dev-guide.rust-lang.org/tests/crater.html + +In general, any documentation change which represents a new guarantee for an API should have FCP approval, and any implementation change which might substantially affect users should *also* have FCP approval, at the discretion of the [FCP team]. + +[FCP team]: ../membership.md#fcp-membership + +If a change does get made but crater reports too many breakages, the team may opt to work with crate maintainers to fix the issue before stabilizing a feature, or implement [dedicated compiler workarounds](./changing.md#edition-dependent-resolution). + +## `#[fundamental]` + +Normally, the orphan rule allows adding new trait implementations to types defined in a crate without worrying about ecosystem breakage. However, for some types, this actually becomes impossible, as is the case with: + +* `&T` +* `&mut T` +* `Box` +* `Pin` + +In all of these cases, even though the parent type (`&_`, `&mut _`, `Box<_>`, and `Pin<_>`) is defined in the standard library, downstream crates can +add trait implementations as long as `T` is a type added in their own crates. + +This means that all of a sudden, stabilizations for traits are a very big deal, since we need to decide before stabilization whether *any* fundamental types should be included, or risk never being able to include them. + +## `#[non_exhaustive]` + +`#[non_exhaustive]` is a useful tool that should be applied to enums, structs, and enum variants *before* stabilization, or else it might be impossible to add. + +`#[non_exhaustive]` enums specifically allow for extra variants to be added in the future without any breaking changes. This is especially important for [`std::io::ErrorKind`], which has new variants added all the time. + +[`std::io::ErrorKind`]: https://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html + +`#[non_exhaustive]` structs specifically allow for extra fields to be added in the future, if the struct otherwise has only public fields. For enum variants, this is especially important, since their fields are always public. + +## Compiler intrinsics + +Compiler intrinsics, located in [`std::intrinsics`], provide special features that Rust would otherwise not be able to do normally. For example, atomic operations in [`std::sync::atomic`] are implemented using compiler intrinsics, since these otherwise have no way of being represented in Rust. Despite the name being *compiler* intrinsics, in general, intrinsics that are exposed by standard library APIs are guarantees of the *language* and have to be approved by the language team when stably exposed for the first time. + +[`std::intrinsics`]: https://doc.rust-lang.org/nightly/std/intrinsics/index.html +[`std::sync::atomic`]: https://doc.rust-lang.org/nightly/std/sync/atomic/index.html + +Although the exact naming of compiler intrinsics is left unstable, any implementation of a compiler for Rust has to have them to implement the standard library, and thus they represent a language-level guarantee. Additionally, the specific behavior of intrinsics may be of interest to the operational semantics (opsem) subteam of lang as well. + +That said, some compiler intrinsics are just implementation details and *do not* have to be implemented by every compiler to work correctly. These intrinsics are tagged with the `#[miri::intrinsic_fallback_is_spec]` and have a relevant pure-Rust implementation that can be used by `miri` without changing any language-level guarantees. The language team did a blanket FCP allowing the stabilization of these intrinsics without their approval in [#161081]. + +[#161081]: https://github.com/rust-lang/rust/pull/161081#issuecomment-5344298013 + +A good rule of thumb for telling the difference between *internal* intrinsics and *language-level* intrinsics is that internal intrinsics will generally depend on target-specific behavior (for example, floating-point arithmetic) whereas internal intrinsics will not (for example, integer arithmetic). + +In addition to the initial FCP of intrinsics from the lang team, an additional FCP is required for stabilizing the use of intrinsics in `const` context. The first FCP involves changing the `#[unstable]` attribute to `#[stable]`, and the second FCP involves changing the `#[rustc_const_unstable]` attribute to `#[rustc_const_stable]`. Sometimes, these two FCPs may be combined if `const`-stabilizing an intrinsic is uncontroversial. diff --git a/src/libs/apis/fixing.md b/src/libs/apis/fixing.md new file mode 100644 index 000000000..00197956a --- /dev/null +++ b/src/libs/apis/fixing.md @@ -0,0 +1,57 @@ +# Fixing APIs + +So, we actually lied: some breaking changes can actually be made in the standard library, assuming we do so very carefully. This page lists the shenanigans the library team has performed to get around stability teams, to hopefully be expanded infrequently. + +## Deprecation + +Sometimes, an API is just bad, and we want to forget it happened. For example, [`std::fs::soft_link`] was deprecated in Rust 1.1.0 and replaced by OS-specific functions, since Windows needs to distinguish between directory and file links. + +[`std::fs::soft_link`]: https://doc.rust-lang.org/std/fs/fn.soft_link.html + +Other times, we make a feature better and want to forget when it wasn't. For example, the [`try!`] macro was deprecated in Rust 1.39.0 and replaced by the dedicated `?` operator, which allows types like [`Option`] in addition to [`Result`]. + +[`try!`]: https://doc.rust-lang.org/std/macro.try.html +[`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html +[`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + +## Deprecated safety + +Sometimes, making a function safe was a mistake, and we want to mark it as unsafe after the fact. For example, [`std::env::set_var`] is genuinely unsafe, potentially beyond the point of usability on some platforms. And yet, before Rust 2024, this method was completely safe to call, and its unsafety was only added on an edition boundary. + +[`std::env::set_var`]: https://doc.rust-lang.org/std/env/fn.set_var.html + +## Edition-dependent prelude + +Some traits are so useful to Rust that we add them to the prelude, including them in all Rust code by default. However, [this can sometimes break code](./stabilization.md#method-resolution), and thus be a breaking change. + +To get around this, the standard library prelude depends on the current edition of Rust, and traits can be added or removed at an edition boundary: + +* [Rust 2021] added [`TryFrom`], [`TryInto`], and [`FromIterator`] to the prelude. +* [Rust 2024] added [`Future`] and [`IntoFuture`] to the prelude. + +[Rust 2021]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html +[Rust 2024]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html +[`TryFrom`]: https://doc.rust-lang.org/nightly/std/convert/trait.TryFrom.html +[`TryInto`]: https://doc.rust-lang.org/nightly/std/convert/trait.TryInto.html +[`FromIterator`]: https://doc.rust-lang.org/nightly/std/iter/trait.FromIterator.html +[`Future`]: https://doc.rust-lang.org/nightly/std/future/trait.Future.html +[`IntoFuture`]: https://doc.rust-lang.org/nightly/std/future/trait.IntoFuture.html + +## Edition-dependent resolution + +Sometimes, adding a new trait implementation or method breaks existing code in ways we really can't ignore, and we want to add them anyway. In these cases, we explicitly modify the compiler to avoid a method before an edition boundary: + +* [Before Rust 2021], [`IntoIterator`] for arrays is hidden. +* [Before Rust 2024], [`IntoIterator`] for boxed slices is hidden. + +[`IntoIterator`]: https://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html +[Before Rust 2021]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html +[Before Rust 2024]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/intoiterator-box-slice.html + +## Edition redirects + +In the future, the standard library will be able to "redirect" paths to different places based upon the edition. This unlocks many new possibilities. + +However, it is not yet implemented: [#160227] + +[#160227]: https://github.com/rust-lang/rust/pull/160227 diff --git a/src/libs/apis/index.md b/src/libs/apis/index.md new file mode 100644 index 000000000..c808f0dc7 --- /dev/null +++ b/src/libs/apis/index.md @@ -0,0 +1,20 @@ +# Maintaining APIs + +Compared to third-party crates on crates.io, the Rust standard library has much stronger stability guarantees. Any stable API that's added to the standard library can *never* be removed or modified in a backwards-incompatible way, even if we do have [a few ways to get around this](./changing.md). + +In some cases, APIs will need special language or compiler support, and these have to exist in the standard library. For example, the `include!` macro is a standard library API, but the API exposes a feature specified in the language and implemented in the compiler. The library team works closely with the language and compiler teams on these kinds of features. + +This also indicates a few more cases where standard library support makes sense, since the compiler has very robust testing infrastructure: if an API is performance-sensitive, we can add additional compiler intrinsics to support it, or codegen tests to verify its correctness. We also run tests for several different systems and generally have the capacity to maintain cross-platform functionality better than most crates. + +APIs can also be substantially more ergonomic in the standard library. If you want to use a new method on a primitive type like `u32` without importing a separate trait, it has to live in the standard library. + +As nice as standard library APIs can be, as mentioned earlier, they represent a very strong commitment that has to be taken seriously. And here are some of the ways we do that: + +- [API Change Proposals (ACPs)](./proposals.md) + - *Most API changes start with an API Change Proposal.* +- [Changing APIs](./changing.md) + - *Not all API changes are obvious, or even API-related.* +- [API stabilization](./stabilization.md) + - *Every new guarantee requires team consensus.* +- [Fixing APIs](./fixing.md) + - *We can't break APIs, but can we fix them?* diff --git a/src/libs/apis/proposals.md b/src/libs/apis/proposals.md new file mode 100644 index 000000000..9954b86bb --- /dev/null +++ b/src/libs/apis/proposals.md @@ -0,0 +1,62 @@ +# API Change Proposals (ACPs) + +API Change Proposals are the recommended process for proposing new APIs to the library team. By investing a small amount of work first to discuss a problem, the library team can work together with contributors to ensure an API's best chance of success. Although an accepted ACP does not guarantee that an API will be accepted, it represents a signal from the team that a change can be implemented and merged into the nightly compiler so people can try it out. + +ACPs are submitted via an [issue template][ACP template] on the [`libs-team`] repository, and anyone can submit an ACP. You don't have to fully sketch out a feature with an ACP, but it should at least include enough information for the teak to work with. + +ACPs are also technically optional, even though they are recommended in most cases. New APIs can always be proposed directly with a pull request to the [`rust-lang/rust`] repository, but in general, you should only do this for small, uncontroversial changes where the effort to create the implementation is less than the effort to make the ACP. If an implementation is proposed for an API we aren't confident in, we may ask you to write an ACP anyway, or reject the change entirely. Even though ACP-accepted changes aren't guaranteed to make it to [stabilization], at least the chance of wasted work is much lower, and at that point, the "wasted work" might translate into valuable insights anyway. + +[ACP template]: https://github.com/rust-lang/libs-team/issues/new?template=api-change-proposal.md&title=ACP:+Insert+Title+Here +[`libs-team`]: https://github.com/rust-lang/libs-team +[`rust-lang/rust`]: https://github.com/rust-lang/rust +[stabilization]: ./stabilization.md + +## Choosing an API + +Since the standard library has strong stability guarantees, proposed APIs should ideally be as simple as possible and unlikely to change. Similarly, if there are a lot of valid options for an API, the standard library is probably not a good fit; people can create separate crates and choose which option they'd like instead. We tend to prefer simpler, concrete APIs over complex, abstract APIs since crates can add new abstractions, but we can't remove abstractions. + +You can already see this principle in action in the standard library itself: [it actually had `Num` and `Int` traits that were removed before 1.0][RFC 369: Num Reform]. While these traits are unquestionably useful, they lead to a very large number of questions that don't have good answers: where should the boundaries between traits be drawn, what methods should be required and which should be optional, should people be allowed to implement the trait for their own types, etc. Instead of the standard library making these decisions, we just use the same method names across primitive types and let crates implement their own traits instead. Sure, it's annoying, but it's a whole lot more annoying to make a decision you can't walk back. + +[RFC 369: Num Reform]: https://rust-lang.github.io/rfcs/0369-num-reform.html + +In general, the very first question that you should ask of any API proposal is why it shouldn't exist as a third-party crate, and why it should have standard library support. This is an annoying bar to pass, since things are generally nicer in the standard library, but our stability guarantees make us reluctant to change things by default. + +## Portable APIs + +Since the standard library supports many different platforms, it also has to take care when adding platform-specific APIs. If we're not careful, we can offer APIs that are easy to use, but which aren't clearly distinguished as not working on certain platforms, which can cause code to break in interesting ways. + +One way we've decided to solve this in the standard library is by using platform-specific extension traits that must be manually imported, rather than as inherent methods on types. For example, instead of adding an inherent method to get the POSIX permissions ("mode") of a file, you need to explicitly import [`std::os::unix::fs::PermissionsExt`] to be able to call the method. + +[`std::os::unix::fs::PermissionsExt`]: https://doc.rust-lang.org/nightly/std/os/unix/fs/trait.PermissionsExt.html + +Done properly, libraries can easily be audited for non-portable code by scanning for [`std::os`] imports instead of having to know all the specific cases and methods that aren't portable. + +[`std::os`]: https://doc.rust-lang.org/nightly/std/os/index.html + +## Accepting APIs + +After an ACP is submitted to the `libs-team` repo, any libs team member can approve the ACP. By this same logic, *unstable* changes to the standard library can be accepted by any libs team member without an ACP at their discretion, regardless of whether they're on the [review rotation](../membership.md#review-rotation). Nontrivial and/or potentially controversial API changes should go through the ACP process. + +In general, if an API is significant enough to deserve an ACP, there should be at least ten (10) days for it to gather feedback before being accepted. ACPs are approved by adding the `ACP-accepted` label, although they should not be closed until a corresponding [tracking issue](./stabilization.md#tracking-issues) is opened in [`rust-lang/rust`] (or, rarely, another repo like [`rust-lang/stdarch`]). + +[`rust-lang/stdarch`]: https://github.com/rust-lang/stdarch + +Similarly, in order to merge a change to an unstable API without an ACP, it should have a tracking issue opened to track the unstable feature. After being implemented, the tracking issue should be represented in the `#[unstable]` attribute for the feature, alongside any other relevant stability attributes. + +At any time, an author can choose to voluntarily withdraw their ACP by closing the issue. People are encouraged to file new ACPs if no open ACP exists for a proposal they'd like to make, although searching through the `libs-team` repository is recommended to avoid duplicating open ACPs. + +## Controversial APIs + +Any libs team member may object to an ACP, blocking its approval. Note that objections should only be for larger aspects like a proposal's structure, since smaller concerns like naming can be resolved before the final stabilization. + +If any libs team member has a concern about a potential API change, including both PRs and ACPs, they can nominate it for discussion at a [libs team meeting](../meetings.md) by adding the `I-libs-nominated` label. In general, the participants at the meeting will decide upon the course of action at the next meeting, which could mean rejecting the API, gathering more feedback, or offering changes. + +If there is difficulty in resolving concerns for an ACP, [the FCP team](../membership.md#fcp-membership) can override them. + +Besides approval, the only valid reasons for closing an ACP are: + +* The proposal was withdrawn by the author +* The proposal was accepted elsewhere, or made impossible due to another change +* An *effectively identical* proposal exists; competing proposals can coexist, but copies of the same proposal should join forces + +While the libs FCP team can ultimately decide the process for closing ACPs they think will never be accepted, in general, the form of that process will depend on the specific rules of a specific FCP team and shouldn't be relied upon. An FCP team closing an ACP does not necessarily mean that an ACP will never be possible, just that it's unlikely to be accepted by that particular FCP team. diff --git a/src/libs/apis/stabilization.md b/src/libs/apis/stabilization.md new file mode 100644 index 000000000..dd6bb2f53 --- /dev/null +++ b/src/libs/apis/stabilization.md @@ -0,0 +1,60 @@ +# API stabilization + +Whenever we make a new API guarantee, it needs to go through a [Final Comment Period (FCP)][FCP] to ensure that there are no pending issues. This will require approval from all but 2 members of the [FCP team] and no outstanding objections from anyone on the larger libs team. + +[FCP]: ../membership.md#fcp-process +[FCP team]: ../membership.md#fcp-membership + +## Tracking issues + +Changes that are marked as *unstable* should all have tracking issues to indicate their full history and status. Unstable APIs, marked via the `#[unstable]` attribute, are generally usable on the beta and nightly channels of the compiler and can be tested out before their final stabilization. Standard library tracking issues can be created [via a template][tracking issue template]. + +[tracking issue template]: https://github.com/rust-lang/rust/issues/new?template=library-tracking-issue.md&title=Tracking+issue+for+XXX + +In general, tracking issues should include a full list of PRs made when implementing an issue as well as a description of the public API being offered. + +## Preparing for stabilization + +There are no strict guidelines for stabilization, but generally, APIs should "cook" for some time in an unstable version and see some use by the community. Since many community members test changes on the nightly compiler channel, this will help justify APIs as useful and discover their shortcomings. This "cook" time generally resets whenever an API is changed, except in trivial cases like renaming where the extra time isn't useful. + +Depending on the size of a particular API, some changes may be stabilized immediately without even creating a tracking issue. Historically, all trait implementations where stabilized due to a compiler limitation; even though this limitation has been lifted, many trait implementations still go immediately through the [FCP process] instead of creating a tracking issue. Similarly, changes to documentation which offer new guarantees about APIs are difficult to implement unstably and instead go through FCP immediately. + +[FCP process]: ../membership.md#fcp-process + +For large APIs, a proposal for stabilization should come with an associated stabilization report that summarizes the implementation history, API, and community desire for a feature in a more digestible format than the tracking issue summary. An example of a simple stabilization report can be found in [#88581]. + +[#88581]: https://github.com/rust-lang/rust/issues/88581#issuecomment-1054642118 + +## Scoping stabilization + +Before stabilization, a decision should be made about whether the entire API is being stabilized, or only part of it. If only part of an API is being stabilized, the to-be-stable and to-remain-unstable APIs should be split into separate tracking issues, usually with a PR modifying the `#[unstable]` attributes. This can also be done as part of a stabilization PR, although this is not recommended. + +Before proposing stabilization, it should be decided whether only the library team needs to FCP the change, or if other teams should participate in the FCP. Depending on the change, different teams may need to be involved: + +* If the change requires a new compiler intrinsic or language feature, it needs `T-lang` approval. +* If the change involves new aspects of the trait solver or type system, it needs `T-types` approval. +* If the change affects the behavior of unsafe code or the language itself, it needs `T-opsem` approval. + +If the involvement of a team in a proposal is ever unclear, you should seek additional guidance from that team or a libs team lead before stabilization. Specific rules for including teams may be included on the [changing APIs page](./changing.md). + +## FCP proposal + +If the [FCP team] (and other relevant teams) seem likely to accept a stabilization proposal, anyone (including non-team-members) can open a PR to stabilize the feature, which usually involves converting `#[unstable]` attributes into `#[stable]` ones. A stabilization PR will also need to remove `#![feature(...)]` attributes from standard library crates, compiler crates, and documentation tests. + +Once a stabilization PR is opened, any member of the libs team can propose FCP to merge the feature. FCPs can be proposed by `@rfcbot fcp merge libs` for libs-only FCPs, or `libs` can be replaced with a comma-separated list of all necessary teams. + +While FCPs can be proposed on tracking issues and were historically done there, all new FCPs should be proposed in stabilization PRs instead. This helps ensure that the documentation for stabilized APIs is accurate, since team members can check the code to verify the API changes. + +Sometimes, an FCP for the standard library may be blocked by relevant documentation in unexpected places, and the author of the stabilization PR should be prepared to make these changes if necessary. This can include, but is not limited to: + +* [The reference], if the stabilized API has an associated language feature or behavior. +* [The book], if the stabilized API adds new functionality for an edition or fundamental language feature. +* [Rust By Example], if relevant. + +[The reference]: https://github.com/rust-lang/reference +[The book]: https://github.com/rust-lang/book +[Rust By Example]: https://github.com/rust-lang/rust-by-example + +Additionally, the author of the PR should be expected to make any changes requested by the FCP team as needed, which are usually naming or other minor changes. Sometimes, an FCP proposal may also be premature and the PR may be closed instead, at which point future changes should point back to the tracking issue. People wishing to propose stabilization without the commitment of maintaining the stabilization PR can discuss the proposal on the tracking issue or in the [`#t-libs`] Zulip stream. + +[`#t-libs`]: https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs diff --git a/src/libs/impls/crates.md b/src/libs/impls/crates.md new file mode 100644 index 000000000..dfa576b51 --- /dev/null +++ b/src/libs/impls/crates.md @@ -0,0 +1,3 @@ +# Crate maintenance + +Wow, can you believe I didn't write this yet? diff --git a/src/libs/impls/index.md b/src/libs/impls/index.md new file mode 100644 index 000000000..931ba881b --- /dev/null +++ b/src/libs/impls/index.md @@ -0,0 +1,24 @@ +# Maintaining implementations + +In addition the standard library's API surface, the library team also maintains the standard library for a growing number of [platforms] supported by Rust for an ever-increasing set of use cases. Rust is supposed to be blazingly fast, not set your computer ablaze. + +[platforms]: https://doc.rust-lang.org/nightly/rustc/platform-support.html + +Here are just a few ways the library team does that: + +- [Code review] + - *What does it mean to be a standard librarian?* +- [Crate maintenance] + - *In addition to the standard library, we have other libraries too.* +- [Target tiers] + - *How can I enable thread-local storage on my toaster?* +- [Testing and debugging] + - *What are some of the issues with testing the standard library?* +- [Performance and benchmarking] + - *Again, for the toaster, its CPU isn't very fast. My toast is blazing.* + +[Code review]: ./review.md +[Crate maintenance]: ./crates.md +[Target tiers]: ./targets.md +[testing and debugging]: ./testing-debugging.md +[Performance and benchmarking]: ./perf-benchmarking.md diff --git a/src/libs/impls/perf-benchmarking.md b/src/libs/impls/perf-benchmarking.md new file mode 100644 index 000000000..74ec16305 --- /dev/null +++ b/src/libs/impls/perf-benchmarking.md @@ -0,0 +1,109 @@ +# Performance and benchmarking + +The performance of the standard library is a topic of frequent discussion, and people frequently propose changes that allege better performance or code generation. How do we tell apart an actually good change from a bad one? + +## Codegen tests + +For small functions, [codegen tests] are the most reliable way to ensure that a function is compiled in the most optimal way. For example, the [`checked-ilog`] test ensures that the `checked_ilog` function can be compiled such that it doesn't actually perform any division or multiplication instructions, which are very expensive to perform. + +[codegen tests]: https://rustc-dev-guide.rust-lang.org/tests/compiletest.html#codegen-tests +[`checked-ilog`]: https://github.com/rust-lang/rust/blob/f45772eb69d6ed3cc23be40625411a75f9f32c9d/tests/codegen-llvm/checked_ilog.rs + +In general, codegen tests should match against the generated LLVM IR to ensure that compilation is optimal for all targets, although target-specific optimizations can be checked against the generated assembly instructions instead. + +Additionally, it's worth mentioning that the presence of a codegen test with the change doesn't actually mean that the change improved the code generation, just that the code is generating correctly *with* the change. In some cases, it's best to verify that the codegen test actually fails without a change before accepting it, since the test may be useful to include even if the associated change isn't. + +## Benchmarking the compiler + +If a part of the standard library is used heavily by the compiler itself, the [`@rust-timer`] tool can be used to run compiler benchmarks and check the effect of changes. + +[`@rust-timer`]: https://rustc-dev-guide.rust-lang.org/tests/perf.html#manual-perf-runs + +Note that this only checks the *compile time* of various crates and not their actual runtime, and thus it won't report any changes if code isn't used by the compiler, like floating-point arithmetic, linked lists, MPSC channels, etc. + +Additionally, note that even the compiler's benchmarking tool can be unreliable in some cases, although it is definitely much more reliable than the alternatives. + +## Manual benchmarks + +In some cases, benchmarks are added directly to the standard library and can be run directly for changes. Additionally, the compiler can be built with standard library changes and then used to benchmark popular crates which have their own benchmarks. + +Unfortunately, these benchmarks can be very limited in their usefulness, especially on systems with a lot of noise. Here are a few ways you can help: + +* Setting `rust.incremental = false` in [`bootstrap.toml`]. +* Ensure the system is as idle as possible. +* Disable [address space layout randomization]. +* [Pin the benchmark process] to a single core. +* Change the [CPU scaling governor] to a fixed frequency. +* Disable [CPU clock boosts]. + +[`bootstrap.toml`]: https://github.com/rust-lang/rust/blob/main/bootstrap.example.toml +[address space layout randomization]: https://man7.org/linux/man-pages/man8/setarch.8.html +[Pin the benchmark process]: https://man7.org/linux/man-pages/man8/taskset.8.html +[CPU scaling governor]: https://wiki.archlinux.org/title/CPU_frequency_scaling#Scaling_governors +[CPU clock boosts]: https://wiki.archlinux.org/title/CPU_frequency_scaling#Configuring_frequency_boosting + +However, in general, performance checks via manual benchmarking are discouraged unless changes are extremely noticeable, since they can be extremely unreliable. Performance can be *extremely* hard to determine, specific to hardware, misleading, and generally unintuitive. + +## `#[inline]` + +One of the most powerful and most misleading tools for improving performance is `#[inline]`, since Rust relies heavily on multiple ways to inline function calls. That said, the circumstances in which inlining are helpful are very unintuitive and can effect unrelated things in unintended ways, and in general, the compiler probably knows better than you do in terms of when inlining is helpful. + +To start, it's important to remember that in general, inlining is already considered for all functions *inside the same crate*. This means that private functions are effectively already marked with `#[inline]` and adding the attribute likely won't do anything. Additionally, this guarantee is extended to functions that are generic, including default trait methods, and thus adding the attribute won't do anything there either. + +All `#[inline]` does is give a nudge to the compiler to inline more often, so, generally the worst effect it can have is longer compile times, and usually it will just have no effect. In general, this means that substantial effort doesn't need to go into ensuring that `#[inline]` won't have a *negative* effect, but that at least some effort should be put into ensuring that its effect is *positive*. + +## `#[inline]`'s evil twins + +There are other methods of inlining that can be used, but should always be associated with strong motivation and, ideally, real data supporting that motivation. + +### Manual inlining + +The first one is a bit weird, but you can technically *manually* inline things. For example, instead of using [`Option::map`], it can sometimes be beneficial to just use a `match` statement and effectively "inline" the `map` function directly into a method. This is because every function call layer makes the compiler that much less inclined to inline things, and closures in particular can generate a lot of code that then has to be optimized out. Simply removing the closure entirely can, in some cases, make the difference for optimizations. + +[`Option::map`]: https://doc.rust-lang.org/nightly/std/option/enum.Option.html#method.map + +### `#[inline(always)]` + +`#[inline(always)]` is the much-stronger version of `#[inline]` that effectively tells the compiler to *always* inline the function, and it can have very unintuitive effects. These changes should almost always be associated with real data, and particularly data which shows a *strong* improvement with the attribute, since it can be unreliable. + +In general, the cases where this applies most are debug builds, which usually don't inline anything. However, note that `#[inline(always)]` doesn't mean `#[inline(but apply in the debug profile too)]`, it means `#[inline(always)]`. These annotations are also particularly helpful for overcoming the compiler's aversion to inlining deeply nested call stacks, but usually it's better to avoid having such deeply nested calls in the first place, like via manual inlining. + +### `#[inline(never)]` + +Similar to `#[inline(always)]`, there is also `#[inline(never)]`, which always prevents inlining. For very similar reasons, this should be avoided unless you absolutely know what you're doing, and have data to prove that. + +The most common use case for `#[inline(never)]` is on cold functions, however, there is another attribute you can use for those: `#[cold]`, to indicate they're rarely run. The two can be combined, but in general, the addition of `#[inline(never)]` is not necessary and should be avoided unless accompanied by motivated reasoning. + +## `assert_unchecked` + +One of the biggest hammers the standard library offers is [`std::hint::assert_unchecked`], which informs the compiler that a logical statement is always true. In pretty much all cases, this hammer should be avoided over other types of unsafe code, since these types of conditions are very difficult for the optimizer to use appropriately, and sometimes result in fewer optimizations being run. + +[`std::hint::assert_unchecked`]: https://doc.rust-lang.org/nightly/std/hint/fn.assert_unchecked.html + +Not only should uses of this function be associated with motivated reasoning and data, but you should attempt to exhaust all other avenues of achieving the same effect *before* relying on this function, since generally other forms of reasoning are more useful to the optimizer. + +### Pattern types + +[Pattern types] currently exist as a compiler-internal way to convey range information to the optimizer. This allows marking specific values as being contained in a particular range, and is particularly used for the built-in [`NonNull`] and [`NonZero`] types. + +[Pattern types]: https://github.com/rust-lang/rust/issues/123646 +[`NonNull`]: https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html +[`NonZero`]: https://doc.rust-lang.org/nightly/std/num/struct.NonZero.html + +While pattern types are unstable, they are okay to use in the standard library to achieve range information and better optimization in some cases. For example, the internal-only [`UsizeNoHighBit`] type is used for [`RawVec`] to enforce the invariant that memory allocations [cannot be larger than `isize::MAX`][`isize::MAX`]. + +[`UsizeNoHighBit`]: https://github.com/rust-lang/rust/blob/f45772eb69d6ed3cc23be40625411a75f9f32c9d/library/core/src/num/niche_types.rs#L129 +[`RawVec`]: https://github.com/rust-lang/rust/blob/f45772eb69d6ed3cc23be40625411a75f9f32c9d/library/alloc/src/raw_vec/mod.rs#L40 +[`isize::MAX`]: https://doc.rust-lang.org/nightly/std/ptr/index.html#allocation + +### Unsafe arithmetic + +Unsafe arithmetic functions are also a valid avenue for optimization, since they tell the compiler that certain cases cannot occur. For example, [`unchecked_sub`] is used for unsafe indexing operations ssince they can implicitly assume that the end of a range is greater than the start, and thus won't overflow. + +[`unchecked_sub`]: https://github.com/rust-lang/rust/blob/f45772eb69d6ed3cc23be40625411a75f9f32c9d/library/core/src/str/traits.rs#L221 + +## Placeholder + +* Removing redundant UB checks +* Funrolling loops +* Autovectorization diff --git a/src/libs/impls/review.md b/src/libs/impls/review.md new file mode 100644 index 000000000..46491d01b --- /dev/null +++ b/src/libs/impls/review.md @@ -0,0 +1,13 @@ +# Code review + +Wow, can you believe I didn't write this yet? + +* `#[may_dangle]` +* `mem::forget` pitfalls +* `mem::replace` with *any* value (e.g. `MaybeUninit`) +* unstable features (e.g. specialization) +* doc alias policy +* `#[must_use]` +* Safety comments +* Target-specific code +* Unsafe generics diff --git a/src/libs/impls/targets.md b/src/libs/impls/targets.md new file mode 100644 index 000000000..f87e5ee85 --- /dev/null +++ b/src/libs/impls/targets.md @@ -0,0 +1,3 @@ +# Target tiers + +Wow, can you believe I didn't write this yet? diff --git a/src/libs/impls/testing-debugging.md b/src/libs/impls/testing-debugging.md new file mode 100644 index 000000000..d3410f048 --- /dev/null +++ b/src/libs/impls/testing-debugging.md @@ -0,0 +1,7 @@ +# Testing and debugging + +Wow, can you believe I didn't write this yet? + +* println-debugging in core/alloc +* separated test crates +* const-asserts diff --git a/src/libs/index.md b/src/libs/index.md index 3120d2f43..3251026c8 100644 --- a/src/libs/index.md +++ b/src/libs/index.md @@ -1,12 +1,19 @@ -# Libs +# Library -This section documents meta processes by the Libs team. +Rust's library team are responsible for maintaining the Rust standard library and various crates owned by the project, some of which are dependencies for the Rust itself. -## Where to find us +We use the Forge to document the team's processes, policies, and working practices. Currently, documentation on developing the standard library is split between the [rustc-dev-guide] and [std-dev-guide], although this may change in the future. Similarly, some processes are shared between the compiler and library team, and you may need to check the documentation for the compiler team's processes in order to fully understand how the library team works, at least for now. -The [`rust-lang/libs-team`](https://github.com/rust-lang/libs-team) GitHub repository is the home of the Libs team. -It has details on current project groups, upcoming meetings, and the status of tracking issues. +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org +[std-dev-guide]: https://std-dev-guide.rust-lang.org -The Libs team hangs out primarily in [the rust-lang Zulip](https://rust-lang.zulipchat.com/) these days in the `#t-libs` stream. - -You can also find out more details about [Zulip and how the Rust community uses it](../platforms/zulip.md). +- [APIs](./apis/index.md) + - *How do we maintain and stabilize standard library APIs?* +- [Implementations](./impls/index.md) + - *How do we maintain code that does not affect API surface area?* +- [Meetings](./meetings.md) + - *What goes on in those weekly library meetings?* +- [Membership](./membership.md) + - *What is expected of library team members and how do I join?* +- [Repositories](./repositories.md) + - *What repositories are owned by the library team and the crate maintainers subteam?* diff --git a/src/libs/maintaining-std.md b/src/libs/maintaining-std.md deleted file mode 100644 index fca24ce42..000000000 --- a/src/libs/maintaining-std.md +++ /dev/null @@ -1,358 +0,0 @@ -# Maintaining the standard library - -> Everything I wish I knew before somebody gave me `r+` - -This document is an effort to capture some of the context needed to develop and maintain the Rust standard library. It’s goal is to help members of the Libs team share the process and experience they bring to working on the standard library so other members can benefit. It’ll probably accumulate a lot of trivia that might also be interesting to members of the wider Rust community. - -This document doesn't attempt to discuss best practices or good style. For that, see the [API Guidelines]. - -## Contributing - -If you spot anything that is outdated, under specified, missing, or just plain incorrect then feel free to open up a PR on the [`rust-lang/rust-forge`] repository! - -## Terms - -- Libs. That's us! The team responsible for development and maintenance of the standard library (among other things). -- Pull request (PR). A regular GitHub pull request against [`rust-lang/rust`]. -- Request for Comment (RFC). A formal document created in [`rust-lang/rfcs`] that introduces new features. -- Tracking Issue. A regular issue on GitHub that’s tagged with `C-tracking-issue`. -- Final Comment Period (FCP). Coordinated by [`rfcbot`] that gives relevant teams a chance to review RFCs and PRs. - -## If you’re ever unsure… - -Maintaining the standard library can feel like a daunting responsibility! Through automated reviewer assignment via [`triagebot`][pr_assignment], you’ll find yourself dropped into a lot of new contexts. - -Ping the `@rust-lang/libs` team on GitHub anytime. We’re all here to help! - -If you don’t think you’re the best person to review a PR then use [`triagebot`][pr_assignment] to assign it to somebody else. - -## Finding reviews waiting for your input - -Please remember to regularly check https://rfcbot.rs/. Click on any occurrence of your nickname to go to a page like https://rfcbot.rs/fcp/SimonSapin that only shows the reviews that are waiting for your input. - -## Reviewing PRs - -As a member of the Libs team you’ll find yourself assigned to PRs that need reviewing, and your input requested on issues in the Rust project. - -### When is an RFC needed? - -New unstable features don't need an RFC before they can be merged. If the feature is small, and the design space is straightforward, stabilizing it usually only requires the feature to go through FCP. Sometimes however, you may ask for an RFC before stabilizing. - -### Is there any `unsafe`? - -Unsafe code blocks in the standard library need a comment explaining why they're [ok](https://doc.rust-lang.org/nomicon). There's a `tidy` lint that checks this. The unsafe code also needs to actually be ok. - -The rules around what's sound and what's not can be subtle. See the [Unsafe Code Guidelines WG] for current thinking, and consider pinging `@rust-lang/libs`, `@rust-lang/lang`, and/or somebody from the WG if you're in _any_ doubt. We love debating the soundness of unsafe code, and the more eyes on it the better! - -### Is that `#[inline]` right? - -Inlining is a trade-off between potential execution speed, compile time and code size. There's some discussion about it in [this PR to the `hashbrown` crate][hashbrown/pull/119]. From the thread: - -> `#[inline]` is very different than simply just an inline hint. As I mentioned before, there's no equivalent in C++ for what `#[inline]` does. In debug mode rustc basically ignores `#[inline]`, pretending you didn't even write it. In release mode the compiler will, by default, codegen an `#[inline]` function into every single referencing codegen unit, and then it will also add `inlinehint`. This means that if you have 16 CGUs and they all reference an item, every single one is getting the entire item's implementation inlined into it. - -You can add `#[inline]`: - -- To public, small, non-generic functions. - -You shouldn't need `#[inline]`: - -- On methods that have any generics in scope. -- On methods on traits that don't have a default implementation. - -`#[inline]` can always be introduced later, so if you're in doubt they can just be removed. - -#### What about `#[inline(always)]`? - -You should just about never need `#[inline(always)]`. It may be beneficial for private helper methods that are used in a limited number of places or for trivial operators. A micro benchmark should justify the attribute. - -### Is there any potential breakage? - -Breaking changes should be avoided when possible. [RFC 1105] lays the foundations for what constitutes a breaking change. Breakage may be deemed acceptable or not based on its actual impact, which can be approximated with a [`crater`] run. - -There are strategies for mitigating breakage depending on the impact. - -For changes where the value is high and the impact is high too: - -- Using compiler lints to try phase out broken behavior. - -If the impact isn't too high: - -- Looping in maintainers of broken crates and submitting PRs to fix them. - -### Is behavior changed? - -Breaking changes aren't just limited to compilation failures. Behavioral changes to stable functions generally can't be accepted. See [the `home_dir` issue][rust/pull/46799] for an example. - -### Are there new impls for stable traits? - -A lot of PRs to the standard library are adding new impls for already stable traits, which can break consumers in many weird and wonderful ways. The following sections gives some examples of breakage from new trait impls that may not be obvious just from the change made to the standard library. - -#### Inference breaks when a second generic impl is introduced - -Rust will use the fact that there's only a single impl for a generic trait during inference. This breaks once a second impl makes the type of that generic ambiguous. Say we have: - -```rust -// in `std` -impl From<&str> for Arc { .. } -``` - -```rust -// in an external `lib` -let b = Arc::from("a"); -``` - -then we add: - -```diff -impl From<&str> for Arc { .. } -+ impl From<&str> for Arc { .. } -``` - -then - -```rust -let b = Arc::from("a"); -``` - -will no longer compile, because we've previously been relying on inference to figure out the `T` in `Box`. - -This kind of breakage can be ok, but a [`crater`] run should estimate the scope. - -#### Deref coercion breaks when a new impl is introduced - -Rust will use deref coercion to find a valid trait impl if the arguments don't type check directly. This only seems to occur if there's a single impl so introducing a new one may break consumers relying on deref coercion. Say we have: - -```rust -// in `std` -impl Add<&str> for String { .. } - -impl Deref for String { type Target = str; .. } -``` - -```rust -// in an external `lib` -let a = String::from("a"); -let b = String::from("b"); - -let c = a + &b; -``` - -then we add: - -```diff -impl Add<&str> for String { .. } -+ impl Add for String { .. } -``` - -then - -```rust -let c = a + &b; -``` - -will no longer compile, because we won't attempt to use deref to coerce the `&String` into `&str`. - -This kind of breakage can be ok, but a [`crater`] run should estimate the scope. - -### Could an implementation use existing functionality? - -Types like `String` are implemented in terms of `Vec` and can use methods on `str` through deref coercion. `Vec` can use methods on `[T]` through deref coercion. When possible, methods on a wrapping type like `String` should defer to methods that already exist on their underlying storage or deref target. - -### Are there `#[fundamental]` items involved? - -Blanket trait impls can't be added to `#[fundamental]` types because they have different coherence rules. See [RFC 1023] for details. That includes: - -- `&T` -- `&mut T` -- `Box` -- `Pin` - -### Is specialization involved? - -Specialization is currently unstable. You can track its progress [here][rust/issues/31844]. - -We try to avoid leaning on specialization too heavily, limiting its use to optimizing specific implementations. These specialized optimizations use a private trait to find the correct implementation, rather than specializing the public method itself. Any use of specialization that changes how methods are dispatched for external callers should be carefully considered. - -As an example of how to use specialization in the standard library, consider the case of creating an `Rc<[T]>` from a `&[T]`: - -```rust -impl From<&[T]> for Rc<[T]> { - #[inline] - fn from(v: &[T]) -> Rc<[T]> { - unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } - } -} -``` - -It would be nice to have an optimized implementation for the case where `T: Copy`: - -```rust -impl From<&[T]> for Rc<[T]> { - #[inline] - fn from(v: &[T]) -> Rc<[T]> { - unsafe { Self::copy_from_slice(v) } - } -} -``` - -Unfortunately we couldn't have both of these impls normally, because they'd overlap. This is where private specialization can be used to choose the right implementation internally. In this case, we use a trait called `RcFromSlice` that switches the implementation: - -```rust -impl From<&[T]> for Rc<[T]> { - #[inline] - fn from(v: &[T]) -> Rc<[T]> { - >::from_slice(v) - } -} - -/// Specialization trait used for `From<&[T]>`. -trait RcFromSlice { - fn from_slice(slice: &[T]) -> Self; -} - -impl RcFromSlice for Rc<[T]> { - #[inline] - default fn from_slice(v: &[T]) -> Self { - unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) } - } -} - -impl RcFromSlice for Rc<[T]> { - #[inline] - fn from_slice(v: &[T]) -> Self { - unsafe { Self::copy_from_slice(v) } - } -} -``` - -Only specialization using the `min_specialization` feature should be used. The full `specialization` feature is known to be unsound. - -### Are there public enums? - -Public enums should have a `#[non_exhaustive]` attribute if there's any possibility of new variants being introduced, so that they can be added without causing breakage. - -### Does this change drop order? - -Changes to collection internals may affect the order their items are dropped in. This has been accepted in the past, but should be noted. - -### Is there a manual `Drop` implementation? - -A generic `Type` that manually implements `Drop` should consider whether a `#[may_dangle]` attribute is appropriate on `T`. The [Nomicon][dropck] has some details on what `#[may_dangle]` is all about. - -If a generic `Type` has a manual drop implementation that may also involve dropping `T` then dropck needs to know about it. If `Type`'s ownership of `T` is expressed through types that don't drop `T` themselves such as `ManuallyDrop`, `*mut T`, or `MaybeUninit` then `Type` also [needs a `PhantomData` field][RFC 0769 PhantomData] to tell dropck that `T` may be dropped. Types in the standard library that use the internal `Unique` pointer type don't need a `PhantomData` marker field. That's taken care of for them by `Unique`. - -As a real-world example of where this can go wrong, consider an `OptionCell` that looks something like this: - -```rust -struct OptionCell { - is_init: bool, - value: MaybeUninit, -} - -impl Drop for OptionCell { - fn drop(&mut self) { - if self.is_init { - // Safety: `value` is guaranteed to be fully initialized when `is_init` is true. - // Safety: The cell is being dropped, so it can't be accessed again. - unsafe { self.value.assume_init_drop() }; - } - } -} -``` - -Adding a `#[may_dangle]` attribute to this `OptionCell` that didn't have a `PhantomData` marker field opened up [a soundness hole][rust/issues/76367] for `T`'s that didn't strictly outlive the `OptionCell`, and so could be accessed after being dropped in their own `Drop` implementations. The correct application of `#[may_dangle]` also required a `PhantomData` field: - -```diff -struct OptionCell { - is_init: bool, - value: MaybeUninit, -+ _marker: PhantomData, -} - -- impl Drop for OptionCell { -+ unsafe impl<#[may_dangle] T> Drop for OptionCell { -``` - -### How could `mem` break assumptions? - -#### `mem::replace` and `mem::swap` - -Any `Sized` value behind a `&mut` reference can be replaced with a new one using `mem::replace` or `mem::swap`, so code shouldn't assume any reachable mutable references can't have their internals changed by replacing. - -#### `mem::forget` - -Rust doesn't guarantee destructors will run when a value is leaked (which can be done with `mem::forget`), so code should avoid relying on them for maintaining safety. Remember, [everyone poops][Everyone Poops]. - -It's ok not to run a destructor when a value is leaked because its storage isn't deallocated or repurposed. If the storage is initialized and is being deallocated or repurposed then destructors need to be run first, because [memory may be pinned][Drop guarantee]. Having said that, there can still be exceptions for skipping destructors when deallocating if you can guarantee there's never pinning involved. - -### How is performance impacted? - -Changes to hot code might impact performance in consumers, for better or for worse. Appropriate benchmarks should give an idea of how performance characteristics change. For changes that affect `rustc` itself, you can also do a [`rust-timer`] run. - -### Is the commit log tidy? - -PRs shouldn’t have merge commits in them. If they become out of date with the default branch then they need to be rebased. - -## Merging PRs - -PRs to [`rust-lang/rust`] aren’t merged manually using GitHub’s UI or by pushing remote branches. Everything goes through [`bors`]. - -### When to `rollup` - -For Libs PRs, rolling up is usually fine, in particular if it's only a new unstable addition or if it only touches docs. - -See the [rollup guidelines] for more details on when to rollup. The idea is to try collect a number of PRs together and merge them all at once, rather than individually. This can get things merged faster, but might not be appropriate for some PRs that are likely to conflict, or have performance characteristics that would be obscured in a rollup. - -### When there's new public items - -If the feature is new, then a tracking issue should be opened for it. Have a look at some previous [tracking issues][Libs tracking issues] to get an idea of what needs to go in there. The `issue` field on `#[unstable]` attributes should be updated with the tracking issue number. - -Unstable features can be merged as normal through [`bors`] once they look ready. - -### When there's new trait impls - -There’s no way to make a trait impl for a stable trait unstable, so **any PRs that add new impls for already stable traits must go through a FCP before merging.** If the trait itself is unstable though, then the impl needs to be unstable too. - -### When a feature is being stabilized - -Features can be stabilized in a PR that replaces `#[unstable]` attributes with `#[stable]` ones. The feature needs to have an accepted RFC before stabilizing. They also need to go through a FCP before merging. - -You can find the right version to use in the `#[stable]` attribute by checking the [Forge]. - -### When a `const` function is being stabilized - -Const functions can be stabilized in a PR that replaces `#[rustc_const_unstable]` attributes with `#[rustc_const_stable]` ones. The [Constant Evaluation WG] should be pinged for input on whether or not the `const`-ness is something we want to commit to. If it is an intrinsic being exposed that is const-stabilized then `@rust-lang/lang` should also be included in the FCP. - -Check whether the function internally depends on other unstable `const` functions through `#[allow_internal_unstable]` attributes and consider how the function could be implemented if its internally unstable calls were removed. See the _Stability attributes_ page for more details on `#[allow_internal_unstable]`. - -Where `unsafe` and `const` is involved, e.g., for operations which are "unconst", that the const safety argument for the usage also be documented. That is, a `const fn` has additional determinism (e.g. run-time/compile-time results must correspond and the function's output only depends on its inputs...) restrictions that must be preserved, and those should be argued when `unsafe` is used. - -### When a feature is being deprecated - -To try reduce noise in the docs from deprecated items, they should be moved to the bottom of the module or `impl` block so they're rendered at the bottom of the docs page. The docs should then be cut down to focus on why the item is deprecated rather than how you might use it. - -[API Guidelines]: https://rust-lang.github.io/api-guidelines -[Unsafe Code Guidelines WG]: https://github.com/rust-lang/unsafe-code-guidelines -[Constant Evaluation WG]: https://github.com/rust-lang/const-eval -[`rust-lang/rust`]: https://github.com/rust-lang/rust -[`rust-lang/rfcs`]: https://github.com/rust-lang/rfcs -[`rust-lang/rust-forge`]: https://github.com/rust-lang/rust-forge -[`rfcbot`]: https://github.com/rust-lang/rfcbot-rs -[`bors`]: https://github.com/rust-lang/bors -[pr_assignment]: ../triagebot/pr-assignment.md -[`crater`]: https://github.com/rust-lang/crater -[`rust-timer`]: https://github.com/rust-lang-nursery/rustc-perf -[Libs tracking issues]: https://github.com/rust-lang/rust/issues?q=label%3AC-tracking-issue+label%3AT-libs -[Drop guarantee]: https://doc.rust-lang.org/nightly/std/pin/index.html#drop-guarantee -[dropck]: https://doc.rust-lang.org/nomicon/dropck.html -[Forge]: https://forge.rust-lang.org/ -[RFC 1023]: https://rust-lang.github.io/rfcs/1023-rebalancing-coherence.html -[RFC 1105]: https://rust-lang.github.io/rfcs/1105-api-evolution.html -[RFC 0769 PhantomData]: https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data -[Everyone Poops]: https://faultlore.com/blah/everyone-poops/ -[rust/pull/46799]: https://github.com/rust-lang/rust/pull/46799 -[rust/issues/76367]: https://github.com/rust-lang/rust/issues/76367 -[rust/issues/31844]: https://github.com/rust-lang/rust/issues/31844 -[rust/issues/44580]: https://github.com/rust-lang/rust/issues/44580 -[hashbrown/pull/119]: https://github.com/rust-lang/hashbrown/pull/119 -[rollup guidelines]: ../compiler/reviews.md#rollups diff --git a/src/libs/meetings.md b/src/libs/meetings.md new file mode 100644 index 000000000..2b01a911c --- /dev/null +++ b/src/libs/meetings.md @@ -0,0 +1,23 @@ +# Meetings + +The library team holds weekly meetings, with the exact schedule and timing determined by the current [libs FCP team] and [team leads]. The schedule for the meetings is configured in [`rust-lang/calendar`] and anyone can subscribe [via public ICS link][ICS]. + +[libs FCP team]: ./membership.md#fcp-membership +[team leads]: ./membership.md#team-leads +[`rust-lang/calendar`]: https://github.com/rust-lang/calendar/blob/main/libs.toml +[ICS]: https://rust-lang.github.io/calendar/libs.ics + +Currently, the agenda is generated using the [`agenda-generator` in the `libs-team` repo][`agenda-generator`] and generally posted to [`#t-libs/meetings`] on Zulip at least a day before the meeting. The generated agenda includes issues with the `I-libs-nominated` tag, medium-or-higher regressions, [FCPs](./membership.md#fcp-process), and [ACPs](./apis/proposals.md), although other topics can be discussed during the meetings. + +[`agenda-generator`]: https://github.com/rust-lang/libs-team/blob/main/tools/agenda-generator +[`#t-libs/meetings`]: https://rust-lang.zulipchat.com/#narrow/channel/259402-t-libs.2Fmeetings + +Anyone, regardless of team membership, is welcome to [join the meeting on jit.si][jitsi] to participate, and people who wish to specifically discuss things can ask ahead of the meeting so their items can be discussed first. While the meeting will occur via audio/video call, meeting minutes will be written on the agenda in text, and people can interact entirely via text chat on jitsi without having to participate via audio or video. Additionally, meeting attendees will never be expected to participate and can simply observe without being mentioned, although participation is always welcome. + +[jitsi]: https://meet.jit.si/rust-libs-meeting-crxoz2at8hiccp7b3ixf89qgxfymlbwr + +Because team members are generally across the world, latency on the call is a real issue and you are encouraged to use the built-in hand-raise function to indicate you'd like to speak next. The participants sidebar (next to the hand-raise button) will show the order in which people raised their hands. The meeting facilitator will attempt to ensure everyone gets the chance to speak and that meeting time is used semi-efficiently. + +Minutes for past meetings will be committed to the [`libs-team` repo] after every meeting. + +[`libs-team` repo]: https://github.com/rust-lang/libs-team/tree/main/minutes diff --git a/src/libs/membership.md b/src/libs/membership.md new file mode 100644 index 000000000..854bb24a3 --- /dev/null +++ b/src/libs/membership.md @@ -0,0 +1,124 @@ +# Membership + +Members of the library team are given extra privileges to help maintain the standard library. + +## Testing and triage + +Library team members get extra permissions specifically for the [`rust-lang/rust`] repository, which allow them to use tools like [`@bors try`] (testing builds), [`@rust-timer`] (performance benchmarking), and [`@crater`] (ecosystem testing). Additionally, they have access to the [developer desktops](../infra/docs/dev-desktop.md) for faster build times. + +[`@bors try`]: https://rustc-dev-guide.rust-lang.org/tests/ci.html#try-builds +[`@rust-timer`]: https://rustc-dev-guide.rust-lang.org/tests/perf.html#manual-perf-runs +[`@crater`]: https://rustc-dev-guide.rust-lang.org/tests/crater.html + +They also are members of the [`rust-lang`] organization on GitHub and have special permissions to manage issues and pull requests in [many different repositories](./repositories.md). They also get shown with a "Member" badge in GitHub comments on the org. + +[`rust-lang`]: https://github.com/rust-lang + +## Merging changes + +Any library team member can approve changes to the [repositories owned by the library team](./repositories.md). Depending on the situation, this may involve a `@bors r+` command or the ability to add changes to the merge queue. In general, team members are expected to adequately review changes before merging, not merge their own changes, and not merge changes to things outside the purview of the library team, within reason. + +All of the above are relative to reasonable judgment, since one of the primary requirements for team members is that they know their limits and abilities and won't approve changes they can't responsibly approve. For example, a library team member who isn't strictly on the compiler team can approve a library change that involves small, related compiler changes, but in general, library team members should at least get informal approval from other teams before the merge changes that affect them. + +Similarly, library team members are not expected to know every aspect of API design and target-specific implementation details, but they should know when to call in someone else to do review if there's something they're not familiar with. + +## Review rotation + +Any library team member can join the review rotation for repositories the team owns, particularly [`rust-lang/rust`] where most of the standard library is located. Being on the review rotation is one of the best ways for members to help the team and learn more about the standard library, and it's one of the team's important resources. + +[`rust-lang/rust`]: https://github.com/rust-lang/rust + +When on the review rotation, members will be randomly assigned by [triagebot](../triagebot/index.md) to new pull requests for review, subject to [individual settings](../triagebot/review-queue-tracking.md#usage). Members can also temporarily remove themselves from review rotations or specifically libs reviews in those settings. + +Members are encouraged to perform reviews regardless of whether they're on the rotation or not, though this is not required. Members are also allowed to merge PRs if they have sufficiently reviewed them, although they should generally coordinate with the assigned reviewer if said reviewer may have already done some review. + +More information on reviewing library changes is detailed in the [maintaining implementations] section. + +[maintaining implementations]: ./impls/review.md + +## FCP process + +Whenever an API change is [stabilized](./apis/stabilization.md) or another large decision has to be made by the library team, it undergoes a Final Comment Period (FCP) where people are given time to comment on the change. All team members have the ability to raise blocking concerns for FCP decisions, and passing the FCP without any concerns allows the change to be made. + +Before FCP, however, a smaller subset of the team, the [libs FCP team], must acknowledge the proposal to move into FCP. Per current configuration, all but two libs FCP members must check their box on the proposal before FCP can continue. Non-FCP libs members may need libs FCP members to register their concerns for them to actually block FCP from happening. + +[libs FCP team]: #fcp-membership + +Participation in the FCP process is voluntary, although interested members can add themselves to the [`libs-ping`] group to be notified whenever new FCPs are proposed. Members are allowed to add or remove themselves from the ping group at any time, although libs FCP members and team leads are required to be part of the group. + +[`libs-ping`]: https://github.com/rust-lang/team/blob/main/teams/libs-ping.toml + +## Joining the libs + +All team members are encouraged to nominate members of the community to join the team in the [`#t-libs/private`] Zulip stream. While all members must be able to be trusted with the above privileges, they are explicitly not required to be an expert in everything the library team does or participate in all library team activities. While contributions of code are the most common, members who productively contribute to documentation, ACP, and FCP discussions are very appreciated. + +[`#t-libs/private`]: https://rust-lang.zulipchat.com/#narrow/channel/275122-t-libs.2Fprivate + +Membership is explicitly up to team discretion, and the process is left intentionally vague to allow flexibility in who to accept. Once a member is nominated, another member must *second* the nomination in order for it to proceed. Similarly, any member can also block a nomination from proceeding with an objection either in the Zulip thread or via private feedback to a team lead, which can then be anonymized. + +Again, no explicit motivation is required for the initial nomination or second, although team members are encouraged to talk about what value new members can provide for the team. All objections should ideally be associated with some form of feedback that can be communicated to the team, so they can understand if a nomination should be blocked indefinitely or just delayed until some later point. + +If a period of 10 days passes in which a nominee is seconded and has no outstanding objections, the nomination is tentatively approved. At this point, team leads must assess whether the nomination has been sufficiently discussed by team membership, allowing the option to delay the nomination if more feedback is needed. If the nominee is not currently part of the Rust project, the team leads should consult with the moderation team to verify there are no potential issues, which can also block a nomination. Without any outstanding issues, the team leads can extend the invitation to the nominee and merge a change to the [`rust-lang/team`] repository to approve the nomination. + +[`rust-lang/team`]: https://github.com/rust-lang/team + +20 days after a nomination, if there are no seconds and/or there are still outstanding objections, a countdown of 10 days begins. If objections persist, or, lacking objections, no seconds are put forward, the nomination is automatically withdrawn. Note that this requires that there exists some singular objection which is outstanding for the entirety of these 10 days. + +Per the configuration of the `#t-libs/private` channel, new members only see messages after they joined, and members should be honest about their feelings on nominees while remaining respectful. Feedback can be given via a team lead and anonymized if a member doesn't feel comfortable sharing it directly. + +## Expectations + +Team members are expected to remain engaged with the Rust project in some capacity, although there are no explicit criteria for participation. Engagement in PR/issue discussions, being on the review rotation, activity in team meetings, activity on Zulip threads, or activity on other official platforms of the project, are all relevant ways to participate, but they should ideally at least sometimes relate to the library team. + +Additionally, members of the team are bound by the Rust project itself and expected to follow [the spirit and the letter of the Code of Conduct][Code of Conduct]. + +[Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct + +If a team member is inactive for at least twelve months, they can be asked if they wish to remain on the team or be moved into the alumni list, with privileges revoked. Team leads can decide how long to wait after giving notice before they move someone to the alumni list. An alum may at any point self-nominate to be reinstated, requiring only a second from a team member and no objections to rejoin the team, subject to the normal 10-day/20-day period restrictions. + +## FCP membership + +Members of the libs FCP team hold an important role in the [FCP process] and thus have higher expectations than normal libs members. All FCP members are expected to respond to outstanding FCP proposals in a timely manner, and the FCP team should regularly attempt to resolve concerns on FCP proposals. They’re also expected to regularly attend [weekly meetings](./meetings.md) or at least participate regularly enough in conversation to help ensure progress on relevant topics. + +[FCP process]: #fcp-process + +Every 12 months, the FCP team should be entirely reshuffled, allowing new members to join. As of 2026, this will happen in September around the time of [Leadership Council] and [Project Director] elections, but this may change over time. Similar to Council elections, the FCP team may elect to choose a facilitator to decide the makeup of the new team, although they are also allowed to make the decision as a group. Unlike Council elections, the facilitator may be a nominee on the new FCP team; the main benefit of a facilitator is to easily collect feedback and make executive decisions, not to be a completely unbiased party. + +[Leadership Council]: https://github.com/rust-lang/leadership-council/blob/main/guides/representative-selection.md +[Project Director]: https://github.com/rust-lang/leadership-council/blob/main/policies/project-directorship/election-process.md + +The process starts with self-nomination, which should last at least 14 days. During this point, any team member, including members of the old FCP team, are allowed to self-nominate to be chosen for the new team. After this point, the facilitator and/or the old FCP team have 14 more days to decide upon their final candidates for the new new FCP team. The facilitator and/or the old FCP team should additionally consult the moderation team for any chosen candidates who have never held a leadership role in the project in case moderation have any concerns. + +The final composition of the FCP team should be `5..=8` members, although FCP members are allowed to resign, which may drop the number below 5. Below the minimum amount, unanimous consensus of the FCP team (and potential OK from the moderation team) is allowed to invite libs members immediately without any waiting period. While below the minimum amount, the FCP team is also encouraged to nominate other promising members from the project to join the libs team with the hope of recruiting them onto the FCP team. + +Below the maximum amount, the FCP team is similarly allowed to invite more members to join the team via the same mechanism. + +## Ad-hoc subteams + +At any point, the FCP team may decide to delegate its FCP power to dedicated subteams or working groups. This is allowed with consensus from the FCP team and does not require approval from the team lead. + +In general, enthusiastic members of the libs team are allowed to create their own working groups without libs FCP privileges to organize their work; the FCP team specifically has the power to delegate FCP abilities as well. + +## Team leads + +One or two members of the team are explicitly team leads, who have permissions to sign off on changes for the larger project on behalf of the team, like [permission changes in the `rust-lang/team` repo][`rust-lang/team`]. Team leads are also generally expected to act as backup facilitators during FCP team reshuffling and Leadership Council elections, aid in coordinating team projects, and act as a moderator in meetings, although they are always allowed to delegate these actions. + +In general, team leads should be at least as active in the project as FCP members, although being a team lead does not grant FCP team membership. + +Similar to the FCP team selection, when a team lead steps down, members of the team may self-nominate to the remaining team lead for the position, and the remaining team lead is the one to choose the new team lead. Team leads should consult moderation for any potential leads that have not before held a leadership role in the Rust project. + +[`rust-lang/team`]: https://github.com/rust-lang/team + +Once a nominee for team lead is chosen, the current team lead should wait 10 days for feedback from the team, allowing for blocking objections. Without any blocking objections for 10 days, the nominee becomes a new team lead. + +Team leads may resign like FCP members, although the team must at any point have at least one team lead. A singular team lead looking to resign should nominate a new lead before resigning, to ensure longevity of the team. Team leads are strongly encouraged to ensure that the team has multiple team leads whenever possible, and leads are additionally encouraged to rotate out (alternatingly) every few years. + +## Last-resort reselection + +Since the FCP team and the team lead choose their own successors, ossification of team membership is a real concern. For this situation, there is a mechanism for the majority of the team to replace the FCP team and team lead, although we hope that this mechanism will never be needed, instead resolving issues without the last-resort mechanism. + +At any point, a team member may initiate a vote of no confidence for team leadership. Once initiated and seconded, the team has 14 days to cast votes. Non-FCP, non-lead members can vote to abstain, replace leadership, or keep leadership. Votes may be, but aren't required to be accompanied by motivating reasoning. + +If 14 days pass, at least 50% of the team has voted (including abstentions), and at least 60% of the non-abstain votes prefer replacement, the FCP team and leadership is immediately dissolved. At this point, the libs team must vote on two new leads, with 2/3 support required to elect leads. The new leads then propose a new FCP team to be selected after 10 days with no active concerns, similar to the process for selecting new team leads. + +This mechanism is intentionally not perfect and may be subject to degenerate corner-cases, but it is written with the understanding that such a case likely warrants outside intervention from Rust Project leadership and/or moderation. diff --git a/src/libs/repositories.md b/src/libs/repositories.md new file mode 100644 index 000000000..d7d0bc732 --- /dev/null +++ b/src/libs/repositories.md @@ -0,0 +1,89 @@ +# Repositories + +While the [`rust-lang/rust`] repository contains the standard library, the library team also maintains other repositories alongside the [crate maintainers] subteam. Although crate maintainers are given an open invitation to become regular library team members, they are technically a separate team with their own rules for membership, which are generally based upon contributions and vibes instead of formal policy. + +[crate maintainers]: https://rust-lang.org/governance/teams/library/#team-crate-maintainers + +The following repositories are shared by the entire project: + +* [`rust-lang/calendar`] holds all team calendars, including the calendar for libs. +* [`rust-lang/calendar-generation`] as a weird/historical case implements the above and is managed by the whole project. +* [`rust-lang/goals`] holds project goals, some of which may be relevant to libs. +* [`rust-lang/rfcs`] holds RFCs for the project, some of which may be relevant to libs. +* [`rust-lang/rust-forge`] contains this page, along with other project policies. + +[`rust-lang/calendar`]: https://github.com/rust-lang/calendar +[`rust-lang/calendar-generation`]: https://github.com/rust-lang/calendar-generation +[`rust-lang/goals`]: https://github.com/rust-lang/goals +[`rust-lang/rfcs`]: https://github.com/rust-lang/rfcs +[`rust-lang/rust-forge`]: https://github.com/rust-lang/rust-forge + +The following repositories contain parts of the standard library, managed by libs. + +* [`rust-lang/rust`] contains the standard library in addition to the compiler and other tools. +* [`rust-lang/enzyme`] contains the enzyme fork used for [`std::autodiff`]. +* [`rust-lang/stdarch`] contains the [`std::arch`] module. +* [`rust-lang/portable-simd`] contains the [`std::simd`] module.[^project-portable-simd] + +[`rust-lang/rust`]: https://github.com/rust-lang/rust +[`rust-lang/enzyme`]: https://github.com/rust-lang/enzyme +[`rust-lang/stdarch`]: https://github.com/rust-lang/stdarch +[`rust-lang/portable-simd`]: https://github.com/rust-lang/portable-simd +[`std::autodiff`]: https://doc.rust-lang.org/nightly/std/autodiff/index.html +[`std::arch`]: https://doc.rust-lang.org/nightly/std/arch/index.html +[`std::simd`]: https://doc.rust-lang.org/nightly/std/simd/index.html + +The following contain documentation for the libs team: + +* [`rust-lang/api-guidelines`] contains API guidelines. +* [`rust-lang/libs-team`] contains meeting minutes, ACPs, and other team-specific tools and documentation. +* [`rust-lang/std-dev-guide`] contains the [standard library developers guide]. +* [`rust-lang/wg-allocators`] contains documentation for the allocators working group.[^wg-allocators] + +[`rust-lang/api-guidelines`]: https://github.com/rust-lang/api-guidelines +[`rust-lang/libs-team`]: https://github.com/rust-lang/libs-team +[`rust-lang/std-dev-guide`]: https://github.com/rust-lang/std-dev-guide +[`rust-lang/wg-allocators`]: https://github.com/rust-lang/wg-allocators +[standard library developers guide]: https://std-dev-guide.rust-lang.org/ + +[^project-portable-simd]: Owned by the `project-portable-simd` subteam; only subteam members can merge changes. +[^wg-allocators]: Owned by the `wg-allocators` subteam; only subteam members can merge changes. + +The following crates are managed by the crate maintainers subteam: + +* [`backtrace-rs`] +* [`cc-rs`] +* [`cmake-rs`] +* [`compiler-builtins`] +* [`ferris-says`] +* [`flate2-rs`] +* [`getopts`] +* [`glob`] +* [`hashbrown`][^hashbrown] +* [`libc`] +* [`libz-sys`] +* [`log`] +* [`pkg-config-rs`] +* [`regex`][^regex] +* [`socket2`] + +[`backtrace-rs`]: https://github.com/rust-lang/backtrace-rs +[`cc-rs`]: https://github.com/rust-lang/cc-rs +[`cmake-rs`]: https://github.com/rust-lang/cmake-rs +[`compiler-builtins`]: https://github.com/rust-lang/compiler-builtins +[`ferris-says`]: https://github.com/rust-lang/ferris-says +[`flate2-rs`]: https://github.com/rust-lang/flate2-rs +[`getopts`]: https://github.com/rust-lang/getopts +[`glob`]: https://github.com/rust-lang/glob +[`hashbrown`]: https://github.com/rust-lang/hashbrown +[`libc`]: https://github.com/rust-lang/libc +[`libz-sys`]: https://github.com/rust-lang/libz-sys +[`log`]: https://github.com/rust-lang/log +[`pkg-config-rs`]: https://github.com/rust-lang/pkg-config-rs +[`regex`]: https://github.com/rust-lang/regex +[`socket2`]: https://github.com/rust-lang/socket2 + +[^hashbrown]: Since [`std::collections::HashMap`] is implemented via `hashbrown`, it is managed by the larger libs team instead of crate maintainers, currently. This may change in the future. +[^regex]: As a historical case, `regex` has a dedicated subteam controlling its membership. + +[`std::collections::HashMap`]: https://doc.rust-lang.org/nightly/std/collections/struct.HashMap.html