From 059b4678135ca3acb4c907642909f67303cda92d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 19 Mar 2025 20:47:14 -0700 Subject: [PATCH 1/2] Add edition admonitions This adds admonition syntax for edition differences blocks so that they have a uniform formatting. This also slightly changes the naming rules so that the block is labeled with the edition where the behavior *changed*, so that it syncs up with how we document editions in the edition guide. --- docs/authoring.md | 10 ++++++++-- mdbook-spec/src/lib.rs | 12 ++++++++++++ src/abi.md | 9 ++++++--- src/destructors.md | 3 ++- src/expressions/await-expr.md | 4 +++- src/expressions/block-expr.md | 4 +++- src/expressions/closure-expr.md | 3 ++- src/expressions/method-call-expr.md | 4 +++- src/introduction.md | 5 +++-- src/items/associated-items.md | 5 +++-- src/items/external-blocks.md | 3 ++- src/items/functions.md | 3 ++- src/items/use-declarations.md | 15 +++++++++------ src/macros-by-example.md | 11 +++++++---- src/names/preludes.md | 6 ++++-- src/paths.md | 5 +++-- src/patterns.md | 9 ++++++--- src/tokens.md | 15 ++++++++++----- src/types/impl-trait.md | 3 ++- src/types/trait-object.md | 8 +++++--- src/unsafe-keyword.md | 3 ++- src/visibility-and-privacy.md | 3 ++- theme/reference.css | 19 +++++++++++++++++++ 23 files changed, 118 insertions(+), 44 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index a37f7b214..6654af11e 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -95,7 +95,7 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s). * Other than Rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule". * Whenever possible, do not repeat previous components of the rule. - * Edition differences admonitions should typically be named by the edition referenced directly by the rule. If multiple editions are named, use the one for which the behavior is defined by the admonition, and not by a previous paragraph. + * Edition differences admonitions should typically be named by the edition where the behavior changed. You should be able to correspond the dates to the chapters in . * Target specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 CPUs, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF OS). * Use an appropriately descriptive, but short, name if the language does not provide one. @@ -197,4 +197,10 @@ The reference does not document which targets exist, or the properties of specif ### Editions -The main text and flow should document only the current edition. Whenever there is a difference between editions, the differences should be called out with an "Edition differences" block. +The main text and flow should document only the current edition. Whenever there is a difference between editions, the differences should be called out with an edition block, such as: + +```markdown +r[foo.bar.edition2021] +> [!EDITION-2021] +> Describe what changed in 2021. +``` diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 7a624d9a5..9eac0e4ed 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -155,6 +155,18 @@ impl Spec { let blockquote = &caps["blockquote"]; let initial_spaces = blockquote.chars().position(|ch| ch != ' ').unwrap_or(0); let space = &blockquote[..initial_spaces]; + if lower.starts_with("edition-") { + let edition = &lower[8..]; + return format!("{space}
\n\ + \n\ + {space}>

\ + {edition} Edition differences

\n\ + {space} >\n\ + {blockquote}\n\ + \n\ + {space}
\n"); + } + // These icons are from GitHub, MIT License, see https://github.com/primer/octicons let svg = match lower.as_str() { "note" => "", diff --git a/src/abi.md b/src/abi.md index b28457ad9..172da01f2 100644 --- a/src/abi.md +++ b/src/abi.md @@ -74,7 +74,8 @@ with the same name (or with a well-known symbol), leading to undefined behavior. extern "C" fn foo() {} ``` -> **Edition differences**: Before the 2024 edition it is allowed to use the `no_mangle` attribute without the `unsafe` qualification. +> [!EDITION-2024] +> Before the 2024 edition it is allowed to use the `no_mangle` attribute without the `unsafe` qualification. ## The `link_section` attribute @@ -92,7 +93,8 @@ of memory not expecting them, such as mutable data into read-only areas. pub static VAR1: u32 = 1; ``` -> **Edition differences**: Before the 2024 edition it is allowed to use the `link_section` attribute without the `unsafe` qualification. +> [!EDITION-2024] +> Before the 2024 edition it is allowed to use the `link_section` attribute without the `unsafe` qualification. ## The `export_name` attribute @@ -109,7 +111,8 @@ behavior. pub fn name_in_rust() { } ``` -> **Edition differences**: Before the 2024 edition it is allowed to use the `export_name` attribute without the `unsafe` qualification. +> [!EDITION-2024] +> Before the 2024 edition it is allowed to use the `export_name` attribute without the `unsafe` qualification. [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md diff --git a/src/destructors.md b/src/destructors.md index 5467c5abb..d4e698721 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -215,7 +215,8 @@ smallest scope that contains the expression and is one of the following: > The [scrutinee] of a `match` expression is not a temporary scope, so temporaries in the scrutinee can be dropped after the `match` expression. For example, the temporary for `1` in `match 1 { ref mut z => z };` lives until the end of the statement. r[destructors.scope.temporary.edition2024] -> **Edition differences**: The 2024 edition added two new temporary scope narrowing rules: `if let` temporaries are dropped before the `else` block, and temporaries of tail expressions of blocks are dropped immediately after the tail expression is evaluated. +> [!EDITION-2024] +> The 2024 edition added two new temporary scope narrowing rules: `if let` temporaries are dropped before the `else` block, and temporaries of tail expressions of blocks are dropped immediately after the tail expression is evaluated. Some examples: diff --git a/src/expressions/await-expr.md b/src/expressions/await-expr.md index 4d262620f..6283de95f 100644 --- a/src/expressions/await-expr.md +++ b/src/expressions/await-expr.md @@ -27,7 +27,9 @@ More specifically, an await expression has the following effect. 5. If the call to `poll` returns [`Poll::Pending`], then the future returns `Poll::Pending`, suspending its state so that, when the surrounding async context is re-polled,execution returns to step 3; 6. Otherwise the call to `poll` must have returned [`Poll::Ready`], in which case the value contained in the [`Poll::Ready`] variant is used as the result of the `await` expression itself. -> **Edition differences**: Await expressions are only available beginning with Rust 2018. +r[expr.await.edition2018] +> [!EDITION-2018] +> Await expressions are only available beginning with Rust 2018. r[expr.await.task] ## Task context diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 3d6936bc8..a0ea1419a 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -114,7 +114,9 @@ The actual data format for this type is unspecified. > [!NOTE] > The future type that rustc generates is roughly equivalent to an enum with one variant per `await` point, where each variant stores the data needed to resume from its corresponding point. -> **Edition differences**: Async blocks are only available beginning with Rust 2018. +r[expr.block.async.edition2018] +> [!EDITION-2018] +> Async blocks are only available beginning with Rust 2018. r[expr.block.async.capture] ### Capture modes diff --git a/src/expressions/closure-expr.md b/src/expressions/closure-expr.md index 534b6ac49..bb2ba76ef 100644 --- a/src/expressions/closure-expr.md +++ b/src/expressions/closure-expr.md @@ -78,7 +78,8 @@ async fn example() { ``` r[expr.closure.async.edition2018] -> **Edition differences**: Async closures are only available beginning with Rust 2018. +> [!EDITION-2018] +> Async closures are only available beginning with Rust 2018. ## Example diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index f35e9210a..d89f58f0d 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -79,7 +79,9 @@ r[expr.method.ambiguous-search] If a step is reached where there is more than one possible method, such as where generic methods or traits are considered the same, then it is a compiler error. These cases require a [disambiguating function call syntax] for method and function invocation. -> **Edition differences**: Before the 2021 edition, during the search for visible methods, if the candidate receiver type is an [array type], methods provided by the standard library [`IntoIterator`] trait are ignored. +r[expr.method.edition2021] +> [!EDITION-2021] +> Before the 2021 edition, during the search for visible methods, if the candidate receiver type is an [array type], methods provided by the standard library [`IntoIterator`] trait are ignored. > > The edition used for this purpose is determined by the token representing the method name. > diff --git a/src/introduction.md b/src/introduction.md index 7f9067663..88666a236 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -78,9 +78,10 @@ These conventions are documented here. An *example term* is an example of a term being defined. -* Differences in the language by which edition the crate is compiled under are in a blockquote that start with the words "Edition differences:" in **bold**. +* The main text describes the latest stable edition. Differences to previous editions are separated in edition blocks: - > **Edition differences**: In the 2015 edition, this syntax is valid that is disallowed as of the 2018 edition. + > [!EDITION-2018] + > In the 2015 edition, this syntax is valid that is disallowed as of the 2018 edition. * Notes that contain useful information about the state of the book or point out useful, but mostly out of scope, information are in note blocks. diff --git a/src/items/associated-items.md b/src/items/associated-items.md index bbecfb676..76050ab7d 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -211,8 +211,9 @@ let circle_shape = Circle::new(); let bounding_box = circle_shape.bounding_box(); ``` -r[items.associated.fn.params.edition2015] -> **Edition differences**: In the 2015 edition, it is possible to declare trait +r[items.associated.fn.params.edition2018] +> [!EDITION-2018] +> In the 2015 edition, it is possible to declare trait > methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and > an error as of the 2018 edition. All parameters must have an argument name. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 492621476..d85b14a2d 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -36,7 +36,8 @@ r[items.extern.unsafe-required] The `unsafe` keyword is semantically required to appear before the `extern` keyword on external blocks. r[items.extern.edition2024] -> **Edition differences**: Prior to the 2024 edition, the `unsafe` keyword is optional. The `safe` and `unsafe` item qualifiers are only allowed if the external block itself is marked as `unsafe`. +> [!EDITION-2024] +> Prior to the 2024 edition, the `unsafe` keyword is optional. The `safe` and `unsafe` item qualifiers are only allowed if the external block itself is marked as `unsafe`. r[items.extern.fn] ## Functions diff --git a/src/items/functions.md b/src/items/functions.md index 317a59ae3..61e7412d1 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -360,7 +360,8 @@ For more information on the effect of async, see [`async` blocks][async-blocks]. [`impl Future`]: ../types/impl-trait.md r[items.fn.async.edition2018] -> **Edition differences**: Async functions are only available beginning with +> [!EDITION-2018] +> Async functions are only available beginning with > Rust 2018. r[items.fn.async.safety] diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index cee55600b..287498b06 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -138,8 +138,9 @@ fn example() { } ``` -r[items.use.path.edition2015] -> **Edition differences**: In the 2015 edition, `use` paths are relative to the crate root. +r[items.use.path.edition2018] +> [!EDITION-2018] +> In the 2015 edition, `use` paths are relative to the crate root. > For example: > > ```rust,edition2015 @@ -196,8 +197,9 @@ r[items.use.multiple-syntax.empty] An empty brace does not import anything, though the leading path is validated that it is accessible. -r[items.use.multiple-syntax.edition2015] -> **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use {foo, bar};` will import the names `foo` and `bar` from the crate root, whereas starting in 2018, those names are relative to the current scope. +r[items.use.multiple-syntax.edition2018] +> [!EDITION-2018] +> In the 2015 edition, paths are relative to the crate root, so an import such as `use {foo, bar};` will import the names `foo` and `bar` from the crate root, whereas starting in 2018, those names are relative to the current scope. r[items.use.self] ## `self` imports @@ -307,8 +309,9 @@ r[items.use.glob.last-segment-only] r[items.use.glob.self-import] `*` cannot be used to import a module's contents into itself (such as `use self::*;`). -r[items.use.glob.edition2015] -> **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. +r[items.use.glob.edition2018] +> [!EDITION-2018] +> In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. > This cannot be used in the crate root itself. r[items.use.as-underscore] diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 19c069b6e..6acbfa208 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -160,14 +160,16 @@ The keyword metavariable `$crate` can be used to refer to the current crate; see transcribed more than once or not at all. r[macro.decl.meta.edition2021] -> **Edition differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). +> [!EDITION-2021] +> Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). > > Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]). > > The relevant edition is the one in effect for the `macro_rules!` definition. r[macro.decl.meta.edition2024] -> **Edition differences**: Before the 2024 edition, `expr` fragment specifiers do not match [_UnderscoreExpression_] or [_ConstBlockExpression_] at the top level. They are allowed within subexpressions. +> [!EDITION-2024] +> Before the 2024 edition, `expr` fragment specifiers do not match [_UnderscoreExpression_] or [_ConstBlockExpression_] at the top level. They are allowed within subexpressions. > > The `expr_2021` fragment specifier exists to maintain backwards compatibility with editions before 2024. @@ -496,7 +498,7 @@ macro_rules! call_foo { fn foo() {} ``` -> **Version & Edition differences**: Prior to Rust 1.30, `$crate` and +> **Version differences**: Prior to Rust 1.30, `$crate` and > `local_inner_macros` (below) were unsupported. They were added alongside > path-based imports of macros (described above), to ensure that helper macros > did not need to be manually imported by users of a macro-exporting crate. @@ -567,7 +569,8 @@ r[macro.decl.follow-set.token-other] * All other fragment specifiers have no restrictions. r[macro.decl.follow-set.edition2021] -> **Edition differences**: Before the 2021 edition, `pat` may also be followed by `|`. +> [!EDITION-2021] +> Before the 2021 edition, `pat` may also be followed by `|`. r[macro.decl.follow-set.repetition] When repetitions are involved, then the rules apply to every possible number of diff --git a/src/names/preludes.md b/src/names/preludes.md index 3764c1725..6701569cb 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -57,7 +57,8 @@ r[names.preludes.extern.std] The [`std`] crate is added as long as the [`no_std` attribute] is not specified in the crate root. r[names.preludes.extern.edition2018] -> **Edition differences**: In the 2015 edition, crates in the extern prelude +> [!EDITION-2018] +> In the 2015 edition, crates in the extern prelude > cannot be referenced via [use declarations], so it is generally standard > practice to include `extern crate` declarations to bring them into scope. > @@ -155,7 +156,8 @@ r[names.preludes.no_implicit_prelude.lang] This attribute does not affect the [language prelude]. r[names.preludes.no_implicit_prelude.edition2018] -> **Edition differences**: In the 2015 edition, the `no_implicit_prelude` +> [!EDITION-2018] +> In the 2015 edition, the `no_implicit_prelude` > attribute does not affect the [`macro_use` prelude], and all macros exported > from the standard library are still included in the `macro_use` prelude. > Starting in the 2018 edition, it will remove the `macro_use` prelude. diff --git a/src/paths.md b/src/paths.md index 262590344..49fabbf15 100644 --- a/src/paths.md +++ b/src/paths.md @@ -188,8 +188,9 @@ Paths starting with `::` are considered to be *global paths* where the segments start being resolved from a place which differs based on edition. Each identifier in the path must resolve to an item. -r[paths.qualifiers.global-root.edition2015] -> **Edition Differences**: In the 2015 Edition, identifiers resolve from the "crate root" +r[paths.qualifiers.global-root.edition2018] +> [!EDITION-2018] +> In the 2015 Edition, identifiers resolve from the "crate root" > (`crate::` in the 2018 edition), which contains a variety of different items, including > external crates, default crates such as `std` or `core`, and items in the top level of > the crate (including `use` imports). diff --git a/src/patterns.md b/src/patterns.md index 9723de445..515c1fd58 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -334,7 +334,8 @@ let [ref mut x] = &mut [()]; //~ ERROR ``` r[patterns.ident.binding.mode-limitations.edition2024] -> **Edition differences**: Before the 2024 edition, bindings could explicitly specify a `ref` or `ref mut` binding mode even when the default binding mode was not "move", and they could specify mutability on such bindings with `mut`. In these editions, specifying `mut` on a binding set the binding mode to "move" regardless of the current default binding mode. +> [!EDITION-2024] +> Before the 2024 edition, bindings could explicitly specify a `ref` or `ref mut` binding mode even when the default binding mode was not "move", and they could specify mutability on such bindings with `mut`. In these editions, specifying `mut` on a binding set the binding mode to "move" regardless of the current default binding mode. r[patterns.ident.binding.mode-limitations-reference] Similarly, a reference pattern may only appear when the default binding mode is "move". For example, this is not accepted: @@ -344,7 +345,8 @@ let [&x] = &[&()]; //~ ERROR ``` r[patterns.ident.binding.mode-limitations-reference.edition2024] -> **Edition differences**: Before the 2024 edition, reference patterns could appear even when the default binding mode was not "move", and had both the effect of matching against the scrutinee and of causing the default binding mode to be reset to "move". +> [!EDITION-2024] +> Before the 2024 edition, reference patterns could appear even when the default binding mode was not "move", and had both the effect of matching against the scrutinee and of causing the default binding mode to be reset to "move". r[patterns.ident.binding.mixed] Move bindings and reference bindings can be mixed together in the same pattern. @@ -669,7 +671,8 @@ _RangeFromPattern_ cannot be used as a top-level pattern for subpatterns in [sli For example, the pattern `[1.., _]` is not a valid pattern. r[patterns.range.edition2021] -> **Edition differences**: Before the 2021 edition, range patterns with both a lower and upper bound may also be written using `...` in place of `..=`, with the same meaning. +> [!EDITION-2021] +> Before the 2021 edition, range patterns with both a lower and upper bound may also be written using `...` in place of `..=`, with the same meaning. r[patterns.ref] ## Reference patterns diff --git a/src/tokens.md b/src/tokens.md index fc2205ad3..3f3879478 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -441,7 +441,8 @@ c"\xC3\xA6"; ``` r[lex.token.str-c.edition2021] -> **Edition differences**: C string literals are accepted in the 2021 edition or +> [!EDITION-2021] +> C string literals are accepted in the 2021 edition or > later. In earlier additions the token `c""` is lexed as `c ""`. r[lex.token.str-c-raw] @@ -472,7 +473,8 @@ least as many `U+0023` (`#`) characters as were used to start the raw C string literal) or `U+005C` (`\`) do not have any special meaning. r[lex.token.str-c-raw.edition2021] -> **Edition differences**: Raw C string literals are accepted in the 2021 +> [!EDITION-2021] +> Raw C string literals are accepted in the 2021 > edition or later. In earlier additions the token `cr""` is lexed as `cr ""`, > and `cr#""#` is lexed as `cr #""#` (which is non-grammatical). @@ -774,7 +776,8 @@ r[lex.token.life.raw.reserved] It is an error to use the RESERVED_RAW_LIFETIME token `'r#_` in order to avoid confusion with the [placeholder lifetime]. r[lex.token.life.raw.edition2021] -> **Edition differences**: Raw lifetimes are accepted in the 2021 +> [!EDITION-2021] +> Raw lifetimes are accepted in the 2021 > edition or later. In earlier additions the token `'r#lt` is lexed as `'r # lt`. r[lex.token.punct] @@ -874,7 +877,8 @@ r[lex.token.reserved-prefix.life] Source input which would otherwise be lexically interpreted as a non-raw lifetime (or a keyword or `_`) which is immediately followed by a `#` character (without intervening whitespace) is identified as a reserved lifetime prefix. r[lex.token.reserved-prefix.edition2021] -> **Edition differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros). +> [!EDITION-2021] +> Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros). > > Before the 2021 edition, reserved prefixes are accepted by the lexer and interpreted as multiple tokens (for example, one token for the identifier or keyword, followed by a `#` token). > @@ -915,7 +919,8 @@ r[lex.token.reserved-guards.pounds] The *reserved pounds* is a token of two or more `U+0023` (`#`). r[lex.token.reserved-guards.edition2024] -> **Edition differences**: Before the 2024 edition, reserved guards are accepted by the lexer and interpreted as multiple tokens. For example, the `#"foo"#` form is interpreted as three tokens. `##` is interpreted as two tokens. +> [!EDITION-2024] +> Before the 2024 edition, reserved guards are accepted by the lexer and interpreted as multiple tokens. For example, the `#"foo"#` form is interpreted as three tokens. `##` is interpreted as two tokens. [Inferred types]: types/inferred.md [Range patterns]: patterns.md#range-patterns diff --git a/src/types/impl-trait.md b/src/types/impl-trait.md index 3a222e6b0..635a641c1 100644 --- a/src/types/impl-trait.md +++ b/src/types/impl-trait.md @@ -115,7 +115,8 @@ r[type.impl-trait.generic-capture.auto.intro] Return-position `impl Trait` abstract types automatically capture all in-scope generic parameters, including generic type, const, and lifetime parameters (including higher-ranked ones). r[type.impl-trait.generic-capture.edition2024] -> **Edition differences**: Before the 2024 edition, on free functions and on associated functions and methods of inherent impls, generic lifetime parameters that do not appear in the bounds of the abstract return type are not automatically captured. +> [!EDITION-2024] +> Before the 2024 edition, on free functions and on associated functions and methods of inherent impls, generic lifetime parameters that do not appear in the bounds of the abstract return type are not automatically captured. r[type.impl-trait.generic-capture.precise] ## Precise capturing diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 1ca723598..90a8ff933 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -39,11 +39,13 @@ For example, given a trait `Trait`, the following are all trait objects: * `dyn (Trait)` r[type.trait-object.syntax-edition2021] -> **Edition differences**: Before the 2021 edition, the `dyn` keyword may be +> [!EDITION-2021] +> Before the 2021 edition, the `dyn` keyword may be > omitted. -r[type.trait-object.syntax-edition2015] -> **Edition differences**: In the 2015 edition, if the first bound of the +r[type.trait-object.syntax-edition2018] +> [!EDITION-2018] +> In the 2015 edition, if the first bound of the > trait object is a path that starts with `::`, then the `dyn` will be treated > as a part of the path. The first path can be put in parenthesis to get > around this. As such, if you want a trait object with the trait diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index b69e91062..00369f1e4 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -80,7 +80,8 @@ r[unsafe.extern] The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`. r[unsafe.extern.edition2024] -> **Edition differences**: Prior to edition 2024, `extern` blocks were allowed without being qualified as `unsafe`. +> [!EDITION-2024] +> Prior to edition 2024, `extern` blocks were allowed without being qualified as `unsafe`. [external block]: items/external-blocks.md diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index 6384e7a16..5aed106da 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -176,7 +176,8 @@ r[vis.scoped.self] to `pub(in self)` or not using `pub` at all. r[vis.scoped.edition2018] -> **Edition differences**: Starting with the 2018 edition, paths for +> [!EDITION-2018] +> Starting with the 2018 edition, paths for > `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition > may also use paths starting with `::` or modules from the crate root. diff --git a/theme/reference.css b/theme/reference.css index 98022ae21..fdfe918a5 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -61,19 +61,23 @@ See mdbook-spec/src/lib.rs. .light .alert { --alert-note-color: #0969da; --alert-warning-color: #9a6700; + --alert-edition-color: #1a7f37; } .ayu .alert { --alert-note-color: #74b9ff; --alert-warning-color: #f0b72f; + --alert-edition-color: #2bd853; } .rust .alert { --alert-note-color: #023b95; --alert-warning-color: #603700; + --alert-edition-color: #008200; } .coal .alert, .navy .alert { --alert-note-color: #4493f8; --alert-warning-color: #d29922; + --alert-edition-color: #3fb950; } .alert-note blockquote { border-inline-start-color: var(--alert-note-color); @@ -81,12 +85,27 @@ See mdbook-spec/src/lib.rs. .alert-warning blockquote { border-inline-start-color: var(--alert-warning-color); } +.alert-edition blockquote { + border-inline-start-color: var(--alert-edition-color); +} .alert-note .alert-title { color: var(--alert-note-color); } .alert-warning .alert-title { color: var(--alert-warning-color); } +.alert-edition .alert-title { + color: var(--alert-edition-color); +} +/* Puts a rounded rectangle around the edition date. */ +.alert-title-edition { + padding: 0px 5px; + margin-right: 1rem; + border: 2px solid var(--alert-edition-color); + border-radius: 15px; + font-weight: bold; + color: var(--alert-edition-color); +} /* tags can be used to highlight specific character elements. */ kbd { From 05e9434592d8e6b5120bee7e920781a00609f1cb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 19 Mar 2025 20:53:35 -0700 Subject: [PATCH 2/2] Unwrap edition blocks To follow the style guide. --- src/items/associated-items.md | 4 +--- src/items/functions.md | 3 +-- src/items/use-declarations.md | 6 ++---- src/names/preludes.md | 12 +++--------- src/paths.md | 8 ++------ src/tokens.md | 10 +++------- src/types/trait-object.md | 12 +++--------- src/visibility-and-privacy.md | 4 +--- 8 files changed, 16 insertions(+), 43 deletions(-) diff --git a/src/items/associated-items.md b/src/items/associated-items.md index 76050ab7d..737277948 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -213,9 +213,7 @@ let bounding_box = circle_shape.bounding_box(); r[items.associated.fn.params.edition2018] > [!EDITION-2018] -> In the 2015 edition, it is possible to declare trait -> methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and -> an error as of the 2018 edition. All parameters must have an argument name. +> In the 2015 edition, it is possible to declare trait methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and an error as of the 2018 edition. All parameters must have an argument name. r[items.associated.fn.param-attributes] #### Attributes on method parameters diff --git a/src/items/functions.md b/src/items/functions.md index 61e7412d1..f840b844f 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -361,8 +361,7 @@ For more information on the effect of async, see [`async` blocks][async-blocks]. r[items.fn.async.edition2018] > [!EDITION-2018] -> Async functions are only available beginning with -> Rust 2018. +> Async functions are only available beginning with Rust 2018. r[items.fn.async.safety] ### Combining `async` and `unsafe` diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 287498b06..db5e74a9f 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -140,8 +140,7 @@ fn example() { r[items.use.path.edition2018] > [!EDITION-2018] -> In the 2015 edition, `use` paths are relative to the crate root. -> For example: +> In the 2015 edition, `use` paths are relative to the crate root. For example: > > ```rust,edition2015 > mod foo { @@ -311,8 +310,7 @@ r[items.use.glob.self-import] r[items.use.glob.edition2018] > [!EDITION-2018] -> In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. -> This cannot be used in the crate root itself. +> In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. This cannot be used in the crate root itself. r[items.use.as-underscore] ## Underscore Imports diff --git a/src/names/preludes.md b/src/names/preludes.md index 6701569cb..c17fb9bd2 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -58,12 +58,9 @@ The [`std`] crate is added as long as the [`no_std` attribute] is not specified r[names.preludes.extern.edition2018] > [!EDITION-2018] -> In the 2015 edition, crates in the extern prelude -> cannot be referenced via [use declarations], so it is generally standard -> practice to include `extern crate` declarations to bring them into scope. +> In the 2015 edition, crates in the extern prelude cannot be referenced via [use declarations], so it is generally standard practice to include `extern crate` declarations to bring them into scope. > -> Beginning in the 2018 edition, [use declarations] can reference crates in -> the extern prelude, so it is considered unidiomatic to use `extern crate`. +> Beginning in the 2018 edition, [use declarations] can reference crates in the extern prelude, so it is considered unidiomatic to use `extern crate`. > [!NOTE] > Additional crates that ship with `rustc`, such as [`alloc`], and [`test`](mod@test), are not automatically included with the `--extern` flag when using Cargo. They must be brought into scope with an `extern crate` declaration, even in the 2018 edition. @@ -157,10 +154,7 @@ This attribute does not affect the [language prelude]. r[names.preludes.no_implicit_prelude.edition2018] > [!EDITION-2018] -> In the 2015 edition, the `no_implicit_prelude` -> attribute does not affect the [`macro_use` prelude], and all macros exported -> from the standard library are still included in the `macro_use` prelude. -> Starting in the 2018 edition, it will remove the `macro_use` prelude. +> In the 2015 edition, the `no_implicit_prelude` attribute does not affect the [`macro_use` prelude], and all macros exported from the standard library are still included in the `macro_use` prelude. Starting in the 2018 edition, it will remove the `macro_use` prelude. [`extern crate`]: ../items/extern-crates.md [`macro_use` attribute]: ../macros-by-example.md#the-macro_use-attribute diff --git a/src/paths.md b/src/paths.md index 49fabbf15..7ef97f88a 100644 --- a/src/paths.md +++ b/src/paths.md @@ -190,13 +190,9 @@ the path must resolve to an item. r[paths.qualifiers.global-root.edition2018] > [!EDITION-2018] -> In the 2015 Edition, identifiers resolve from the "crate root" -> (`crate::` in the 2018 edition), which contains a variety of different items, including -> external crates, default crates such as `std` or `core`, and items in the top level of -> the crate (including `use` imports). +> In the 2015 Edition, identifiers resolve from the "crate root" (`crate::` in the 2018 edition), which contains a variety of different items, including external crates, default crates such as `std` or `core`, and items in the top level of the crate (including `use` imports). > -> Beginning with the 2018 Edition, paths starting with `::` resolve from -> crates in the [extern prelude]. That is, they must be followed by the name of a crate. +> Beginning with the 2018 Edition, paths starting with `::` resolve from crates in the [extern prelude]. That is, they must be followed by the name of a crate. ```rust pub fn foo() { diff --git a/src/tokens.md b/src/tokens.md index 3f3879478..37ee874c7 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -442,8 +442,7 @@ c"\xC3\xA6"; r[lex.token.str-c.edition2021] > [!EDITION-2021] -> C string literals are accepted in the 2021 edition or -> later. In earlier additions the token `c""` is lexed as `c ""`. +> C string literals are accepted in the 2021 edition or later. In earlier additions the token `c""` is lexed as `c ""`. r[lex.token.str-c-raw] #### Raw C string literals @@ -474,9 +473,7 @@ literal) or `U+005C` (`\`) do not have any special meaning. r[lex.token.str-c-raw.edition2021] > [!EDITION-2021] -> Raw C string literals are accepted in the 2021 -> edition or later. In earlier additions the token `cr""` is lexed as `cr ""`, -> and `cr#""#` is lexed as `cr #""#` (which is non-grammatical). +> Raw C string literals are accepted in the 2021 edition or later. In earlier additions the token `cr""` is lexed as `cr ""`, and `cr#""#` is lexed as `cr #""#` (which is non-grammatical). #### Examples for C string and raw C string literals @@ -777,8 +774,7 @@ It is an error to use the RESERVED_RAW_LIFETIME token `'r#_` in order to avoid c r[lex.token.life.raw.edition2021] > [!EDITION-2021] -> Raw lifetimes are accepted in the 2021 -> edition or later. In earlier additions the token `'r#lt` is lexed as `'r # lt`. +> Raw lifetimes are accepted in the 2021 edition or later. In earlier additions the token `'r#lt` is lexed as `'r # lt`. r[lex.token.punct] ## Punctuation diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 90a8ff933..1e790df2d 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -40,19 +40,13 @@ For example, given a trait `Trait`, the following are all trait objects: r[type.trait-object.syntax-edition2021] > [!EDITION-2021] -> Before the 2021 edition, the `dyn` keyword may be -> omitted. +> Before the 2021 edition, the `dyn` keyword may be omitted. r[type.trait-object.syntax-edition2018] > [!EDITION-2018] -> In the 2015 edition, if the first bound of the -> trait object is a path that starts with `::`, then the `dyn` will be treated -> as a part of the path. The first path can be put in parenthesis to get -> around this. As such, if you want a trait object with the trait -> `::your_module::Trait`, you should write it as `dyn (::your_module::Trait)`. +> In the 2015 edition, if the first bound of the trait object is a path that starts with `::`, then the `dyn` will be treated as a part of the path. The first path can be put in parenthesis to get around this. As such, if you want a trait object with the trait `::your_module::Trait`, you should write it as `dyn (::your_module::Trait)`. > -> Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in -> paths, so the parentheses are not necessary. +> Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in paths, so the parentheses are not necessary. r[type.trait-object.alias] Two trait object types alias each other if the base traits alias each other and diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index 5aed106da..5e2cc0b0b 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -177,9 +177,7 @@ to `pub(in self)` or not using `pub` at all. r[vis.scoped.edition2018] > [!EDITION-2018] -> Starting with the 2018 edition, paths for -> `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition -> may also use paths starting with `::` or modules from the crate root. +> Starting with the 2018 edition, paths for `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition may also use paths starting with `::` or modules from the crate root. Here's an example: