Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ mod break_keyword {}
/// to be most things that would be reasonable to have in a constant (barring `const fn`s). For
/// example, you can't have a [`File`] as a `const`.
///
/// [`File`]: crate::fs::File
/// [`File`]: ../std/fs/struct.File.html
///
/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses
/// all others in a Rust program. For example, if you wanted to define a constant string, it would
Expand Down Expand Up @@ -484,7 +484,7 @@ mod extern_keyword {}

#[doc(keyword = "false")]
//
/// A value of type [`bool`] representing logical **false**.
/// A value of type [`prim@bool`] representing logical **false**.
///
/// `false` is the logical opposite of [`true`].
///
Expand Down Expand Up @@ -1235,31 +1235,18 @@ mod ref_keyword {}
/// `return` returns from the function immediately (an "early return"):
///
/// ```no_run
/// use std::fs::File;
/// use std::io::{Error, ErrorKind, Read, Result};
/// fn main() -> Result<(), &'static str> {
/// let contents = "Hello, world!";
///
/// fn main() -> Result<()> {
/// let mut file = match File::open("foo.txt") {
/// Ok(f) => f,
/// Err(e) => return Err(e),
/// };
///
/// let mut contents = String::new();
/// let size = match file.read_to_string(&mut contents) {
/// Ok(s) => s,
/// Err(e) => return Err(e),
/// };
/// if contents.contains("impossible!") {
/// return Err("oh no!");
/// }
///
/// if contents.contains("impossible!") {
/// return Err(Error::new(ErrorKind::Other, "oh no!"));
/// }
/// if contents.len() > 9000 {
/// return Err("over 9000!");
/// }
///
/// if size > 9000 {
/// return Err(Error::new(ErrorKind::Other, "over 9000!"));
/// }
///
/// assert_eq!(contents, "Hello, world!");
/// Ok(())
/// Ok(())
/// }
/// ```
///
Expand Down Expand Up @@ -1306,7 +1293,7 @@ mod return_keyword {}
/// manner to computed goto).
///
/// Example of using `become` to implement functional-style `fold`:
/// ```
/// ```ignore (explicit_tail_calls not supported on wasm targets)

@RalfJung RalfJung Jun 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks like a test coverage regression, since it will be ignored on all targets now

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is there a way to ignore a doc test for a specific target?

When these docs were in std, the test did not run for the wasm32-wasip1 target in CI. However in core it does. The log of the failed try run earlier indicated that the explicit_tail_calls feature is not supported for this target.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes:

#[cfg_attr(target_os = "linux", doc = "```")]
#[cfg_attr(not(target_os = "linux"), doc = "```ignore (not supporting  on this target)")]

/// #![feature(explicit_tail_calls)]
/// #![expect(incomplete_features)]
///
Expand Down Expand Up @@ -1360,7 +1347,7 @@ mod return_keyword {}
/// (unless it's coerced to a function pointer)
///
/// It is possible to tail-call a function pointer:
/// ```
/// ```ignore (explicit_tail_calls not supported on wasm targets)
/// #![feature(explicit_tail_calls)]
/// #![expect(incomplete_features)]
///
Expand Down Expand Up @@ -1631,8 +1618,8 @@ mod self_upper_keyword {}
/// [`extern`]: keyword.extern.html
/// [`mut`]: keyword.mut.html
/// [`unsafe`]: keyword.unsafe.html
/// [`Mutex`]: sync::Mutex
/// [`OnceLock`]: sync::OnceLock
/// [`Mutex`]: ../std/sync/struct.Mutex.html
/// [`OnceLock`]: ../std/sync/struct.OnceLock.html
/// [`RefCell`]: cell::RefCell
/// [atomic]: sync::atomic
/// [Reference]: ../reference/items/static-items.html
Expand Down Expand Up @@ -1959,7 +1946,7 @@ mod trait_keyword {}

#[doc(keyword = "true")]
//
/// A value of type [`bool`] representing logical **true**.
/// A value of type [`prim@bool`] representing logical **true**.
///
/// Logically `true` is not equal to [`false`].
///
Expand Down Expand Up @@ -2146,22 +2133,30 @@ mod type_keyword {}
/// Since `unsafe fn` and `unsafe trait` indicate that there is a safety
/// contract that the compiler cannot enforce, documenting it is important. The
/// standard library has many examples of this, like the following which is an
/// extract from [`Vec::set_len`]. The `# Safety` section explains the contract
/// extract from [`ptr::replace`]. The `# Safety` section explains the contract

@RalfJung RalfJung Jun 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd prefer to stick to the original example here -- ptr::replace is a raw pointer method which "feels" quite different from an unsafe method on a typically "safe" type. Also ptr::replace's condition is harder to understand.

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I agree and the goal with changing it was to make the example reference an unsafe method in core instead of std.

I spoke with @GuillaumeGomez about this AlPR. With the move to core, ideally the examples should minimize links to std.

I'll try and find a simpler method in core, and revert if I can't find one.

@RalfJung RalfJung Jun 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think we should artificially limit our discussion of things like the unsafe keyword to examples that can be found in core. Instead, we should write the best docs we can write, using examples from any part of the standard library. unsafe is a language keyword, it's not part of any library, it's placement in core vs std is entirely incidental.

Arguably these docs really should be in the Reference, and then obviously they could use examples from std.

/// that must be fulfilled to safely call the function.
///
/// ```rust,ignore (stub-to-show-doc-example)
/// /// Forces the length of the vector to `new_len`.
/// /// Moves `src` into the pointed `dst`, returning the previous `dst` value.
/// ///
/// /// Neither value is dropped.
/// ///
/// /// This is a low-level operation that maintains none of the normal
/// /// invariants of the type. Normally changing the length of a vector
/// /// is done using one of the safe operations instead, such as
/// /// `truncate`, `resize`, `extend`, or `clear`.
/// /// This function is semantically equivalent to [`mem::replace`] except that it
/// /// operates on raw pointers instead of references. When references are
/// /// available, [`mem::replace`] should be preferred.
/// ///
/// /// # Safety
/// ///
/// /// - `new_len` must be less than or equal to `capacity()`.
/// /// - The elements at `old_len..new_len` must be initialized.
/// pub unsafe fn set_len(&mut self, new_len: usize)
/// /// Behavior is undefined if any of the following conditions are violated:
/// ///
/// /// * `dst` must be [valid] for both reads and writes or `T` must be a ZST.
/// ///
/// /// * `dst` must be properly aligned.
/// ///
/// /// * `dst` must point to a properly initialized value of type `T`.
/// ///
/// /// Note that even if `T` has size `0`, the pointer must be properly aligned.
/// pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T
/// ```
///
/// ## Using `unsafe {}` blocks and `impl`s
Expand Down Expand Up @@ -2502,7 +2497,7 @@ mod use_keyword {}
/// ```
///
/// `where` is available anywhere generic and lifetime parameters are available,
/// as can be seen with the [`Cow`](crate::borrow::Cow) type from the standard
/// as can be seen with the [`Cow`](../std/borrow/enum.Cow.html) type from the standard
/// library:
///
/// ```rust
Expand Down
13 changes: 13 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,17 @@ pub mod simd {
pub use crate::core_simd::simd::*;
}

// Include private modules that exist solely to provide rustdoc
// documentation for built-in attributes. Using `include!` because rustdoc
// only looks for these modules at the crate level.
include!("attribute_docs.rs");

// Include a number of private modules that exist solely to provide
// the rustdoc documentation for the existing keywords. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("keyword_docs.rs");

// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("primitive_docs.rs");
18 changes: 9 additions & 9 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,20 +778,20 @@ pub mod from {
pub use core::from::From;
}

// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("../../core/src/primitive_docs.rs");
// Include private modules that exist solely to provide rustdoc
// documentation for built-in attributes. Using `include!` because rustdoc
// only looks for these modules at the crate level.
include!("../../core/src/attribute_docs.rs");

@RalfJung RalfJung Jun 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are these files included both in libcore and libstd? I guess this is to keep existing links like https://doc.rust-lang.org/nightly/std/keyword.unsafe.html working?

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This pattern was in place for the primitives docs already.

I spoke with some folks during the lang-docs office hour and the assumption is for visibility. Most people will be looking in the std documentation, however it should likely be in both. Additionally yes to avoid breaking existing links.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When you are in the std docs, you have access to core in any case, so no need to make them appear in both core and std.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This pattern was in place for the primitives docs already.

Yeah I saw that.

Still, would be good to add a brief comment explaining it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Including in both was already set for primitive_docs.rs. I'm assuming this was added for just visibility reasons. But removing attributes and keywords from also being included in std, should I leave primitive_docs.rs included?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That will mean that looking for fn or any other items will show two items in the search results. Not great.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thinking out loud, infra team can likely add redirections for these items.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That will mean that looking for fn or any other items will show two items in the search results. Not great.

Would it? We don't get duplicates for e.g. bool currently.

@jschillem jschillem Jun 26, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I believe it's only searching in the crate you're in currently. So if if the includes are removed from std, these docs will not be searchable. The user would have to explicitly go to core to find them.

So I don't believe it's show up twice. If anything removing from std would reduce overall visibility as most people are already searching within std.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would it? We don't get duplicates for e.g. bool currently.

Ah indeed. That is... surprising. Oh well, if it works let's use it then. =D


// Include a number of private modules that exist solely to provide
// the rustdoc documentation for the existing keywords. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("keyword_docs.rs");
include!("../../core/src/keyword_docs.rs");

// Include private modules that exist solely to provide rustdoc
// documentation for built-in attributes. Using `include!` because rustdoc
// only looks for these modules at the crate level.
include!("attribute_docs.rs");
// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("../../core/src/primitive_docs.rs");

// This is required to avoid an unstable error when `restricted-std` is not
// enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std
Expand Down
Loading