From ca6ba4e5240bcca343ca2ce0e1aa6fa3cea8b722 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:35:45 +0200 Subject: [PATCH 01/13] feat: introduce M-MACRO-VERSION-PIN --- src/guidelines/macros/M-MACRO-VERSION-PIN | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/guidelines/macros/M-MACRO-VERSION-PIN diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN b/src/guidelines/macros/M-MACRO-VERSION-PIN new file mode 100644 index 0000000..c764ba6 --- /dev/null +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN @@ -0,0 +1,47 @@ + + +## Pin supporting proc macro crates (M-MACRO-VERSION-PIN) { #M-MACRO-VERSION-PIN } +keep minor updates semver compatible + +This guideline applies to libraries that re-export macros from supporting proc macro crates +where users depend on the main crate, not the supporting crates. Independently consumed macro +libraries are outside its scope. + +A newer macro may generate code that uses a type or helper missing from an older library. To +overcome this issue release the main crate and its supporting crates together, with the same +version number. The main crate must pin its macro dependency to that exact version. If there +is a separate macro implementation crate, pin that dependency too. Exact pins prevent Cargo +from selecting that incompatible combination. Use "=1.2.3": plain "1.2.3" allows compatible +updates. + +Update all three versions and their pins on each release, even if some crates have no code changes. +Choose the version bump based on the main crate's public API, including its macros. Users do not need +to exact-pin their dependency on the main crate. + +For example: + +```rust,ignore +# my_crate/Cargo.toml +[package] +version = "1.2.3" + +[dependencies] +my_crate_macros = "=1.2.3" + +# my_crate_macros/Cargo.toml +[package] +version = "1.2.3" + +[dependencies] +my_crate_macros_impl = "=1.2.3" + +# my_crate_macros_impl/Cargo.toml +[package] +version = "1.2.3" +``` + +The `my_macro!` implementation would then rely on its presence in its emitted code: + +```rust,ignore +impl ::foo::_private::Bar for MyType { ... } +``` From b808de1be3f3f9e5f70278d774cc47c65cf98c55 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:36:51 +0200 Subject: [PATCH 02/13] Clean up comments in M-MACRO-VERSION-PIN Removed unnecessary comments and code related to 'my_macro!' implementation. --- src/guidelines/macros/M-MACRO-VERSION-PIN | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN b/src/guidelines/macros/M-MACRO-VERSION-PIN index c764ba6..3d6e135 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN @@ -39,9 +39,3 @@ my_crate_macros_impl = "=1.2.3" [package] version = "1.2.3" ``` - -The `my_macro!` implementation would then rely on its presence in its emitted code: - -```rust,ignore -impl ::foo::_private::Bar for MyType { ... } -``` From f84eac5a0637970dad69fabca3daaa966f997f76 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:38:17 +0200 Subject: [PATCH 03/13] Rename M-MACRO-VERSION-PIN to M-MACRO-VERSION-PIN.md --- .../macros/{M-MACRO-VERSION-PIN => M-MACRO-VERSION-PIN.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/guidelines/macros/{M-MACRO-VERSION-PIN => M-MACRO-VERSION-PIN.md} (100%) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN b/src/guidelines/macros/M-MACRO-VERSION-PIN.md similarity index 100% rename from src/guidelines/macros/M-MACRO-VERSION-PIN rename to src/guidelines/macros/M-MACRO-VERSION-PIN.md From 894d2c78e25ffb403526bc6cbc69536e939c2217 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:38:27 +0200 Subject: [PATCH 04/13] Add version pinning guideline to README --- src/guidelines/macros/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guidelines/macros/README.md b/src/guidelines/macros/README.md index 54c02cf..17f7804 100644 --- a/src/guidelines/macros/README.md +++ b/src/guidelines/macros/README.md @@ -6,6 +6,7 @@ {{#include M-EXAMPLE-OVER-PROC.md}} {{#include M-MACROS-DONT-LIE.md}} {{#include M-MACRO-MAIN-CRATE.md}} +{{#include M-MACRO-VERSION-PIN.md}} {{#include M-MACRO-HELPERS.md}} {{#include M-PROC-IMPL.md}} {{#include M-PROC-IMPLIED-ITEMS.md}} From 7c56130a1af7a2562f203079ef4ffcf2f4e2d130 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:39:11 +0200 Subject: [PATCH 05/13] Add guideline for pinning proc macro crate versions Added a new section to explain the guideline for pinning supporting proc macro crates. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index 3d6e135..b3cb138 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -1,6 +1,7 @@ ## Pin supporting proc macro crates (M-MACRO-VERSION-PIN) { #M-MACRO-VERSION-PIN } + keep minor updates semver compatible This guideline applies to libraries that re-export macros from supporting proc macro crates From ab03c7a4067c7cf0cb9e13f6974f8947b555ff73 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:47:46 +0200 Subject: [PATCH 06/13] Update guidelines for pinning proc macro versions Clarify version pinning guidelines for proc macro crates and emphasize the importance of matching version numbers across main and supporting crates. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index b3cb138..9e7783d 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -2,20 +2,20 @@ ## Pin supporting proc macro crates (M-MACRO-VERSION-PIN) { #M-MACRO-VERSION-PIN } -keep minor updates semver compatible +keep generated code compatible with its library This guideline applies to libraries that re-export macros from supporting proc macro crates where users depend on the main crate, not the supporting crates. Independently consumed macro libraries are outside its scope. -A newer macro may generate code that uses a type or helper missing from an older library. To -overcome this issue release the main crate and its supporting crates together, with the same -version number. The main crate must pin its macro dependency to that exact version. If there -is a separate macro implementation crate, pin that dependency too. Exact pins prevent Cargo -from selecting that incompatible combination. Use "=1.2.3": plain "1.2.3" allows compatible -updates. +A newer macro may generate code that needs types or helpers unavailable in an older library. +Release the main crate and its supporting crates together, with matching version numbers. -Update all three versions and their pins on each release, even if some crates have no code changes. +The main crate must depend on the exact matching version of its proc macro crate. If there +is a separate macro implementation crate, pin that dependency too. Use `=1.2.3`, not `1.2.3`, +which allows compatible updates. + +Update all package versions and their pins on each release, even if some crates have no code changes. Choose the version bump based on the main crate's public API, including its macros. Users do not need to exact-pin their dependency on the main crate. From cdd0787510377e6f9efef9309fb462ccd224f2c8 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:50:14 +0200 Subject: [PATCH 07/13] Update versioning guidelines for macro crates Clarify the versioning guidelines for macro dependencies. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index 9e7783d..eb7c45e 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -9,8 +9,7 @@ where users depend on the main crate, not the supporting crates. Independently c libraries are outside its scope. A newer macro may generate code that needs types or helpers unavailable in an older library. -Release the main crate and its supporting crates together, with matching version numbers. - +Release the main crate and its supporting crates together, with matching version numbers. The main crate must depend on the exact matching version of its proc macro crate. If there is a separate macro implementation crate, pin that dependency too. Use `=1.2.3`, not `1.2.3`, which allows compatible updates. From f27d093ffffb3f72d5afa22e63d3db186298e90a Mon Sep 17 00:00:00 2001 From: Evgenii Date: Wed, 9 Sep 2026 16:53:20 +0200 Subject: [PATCH 08/13] Update M-MACRO-VERSION-PIN.md --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index eb7c45e..8f65601 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -9,10 +9,9 @@ where users depend on the main crate, not the supporting crates. Independently c libraries are outside its scope. A newer macro may generate code that needs types or helpers unavailable in an older library. -Release the main crate and its supporting crates together, with matching version numbers. -The main crate must depend on the exact matching version of its proc macro crate. If there -is a separate macro implementation crate, pin that dependency too. Use `=1.2.3`, not `1.2.3`, -which allows compatible updates. +To keep them compatible, release the main crate and its supporting crates together, with +matching version numbers and exact dependency pins. If there is a separate macro implementation +crate, pin that dependency too. Use `=1.2.3`, not `1.2.3`, which allows compatible updates. Update all package versions and their pins on each release, even if some crates have no code changes. Choose the version bump based on the main crate's public API, including its macros. Users do not need From 2ab28e278f43efccf14b4e5e223019ec15d2f27d Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 10 Sep 2026 07:30:28 +0100 Subject: [PATCH 09/13] fix(M-MACRO-VERSION-PIN): tag the example as TOML and add the checklist entry Two defects in the new guideline, both found by building the book rather than by reading the source. **The example's file headers are hidden in the rendered page.** The block is Cargo.toml content fenced as rust,ignore. mdBook treats a leading `#` in a *Rust* block as a hidden "boring" line, so all three `# my_crate/Cargo.toml`, `# my_crate_macros/Cargo.toml` and `# my_crate_macros_impl/Cargo.toml` comments are stripped of their `#`, wrapped in ``, and hidden by default (`book.js` adds `hide-boring`; `general.css` sets `.hide-boring .boring { display: none }`). Those comments are the only thing telling the reader which of the three manifests each `[package]` belongs to, and this guideline is *entirely* about three different crates' manifests. As published the reader sees three undifferentiated `[package]`/`[dependencies]` pairs. Verified by building both ways from the same tree: rust,ignore -> my_crate/Cargo.toml toml -> # my_crate/Cargo.toml Retagging as toml also gives correct highlighting and removes a Rust-doctest fence around content that is not Rust. `rust,ignore` is right for the Rust snippets elsewhere in this book; it is wrong for a manifest. The five existing manifest examples (M-TARGET-CPU, M-MIMALLOC-APPS, M-HOTPATH, M-PANIC-IS-STOP, M-CRATES-IN-WORKSPACE) already use a toml fence, so this restores the convention rather than inventing one. **The guideline is missing from the checklist.** Every other `M-` guideline appears in `src/guidelines/checklist/README.md` with a link definition; without its row the guideline is unreachable from the page teams actually review against, which is the cost that matters for a rule nobody can look up. Verified: `mdbook build` and `mdbook test` both exit 0; the rebuilt `book/guidelines/macros/index.html` contains `language-toml` and zero `boring` spans; `book/guidelines/checklist/index.html` renders the new row linking to `../macros/#M-MACRO-VERSION-PIN`, and that `id` exists on the target page; `markdownlint-cli2` reports 0 errors on both changed files with the repo's `.markdownlint.json`. Generated artifacts touched by the preprocess scripts (`src/agents/all.txt`, the `BUILD_DATE` placeholder in `src/guidelines/README.md`) were reverted rather than committed -- CI regenerates them on every run, and the base PR does not carry them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/guidelines/checklist/README.md | 2 ++ src/guidelines/macros/M-MACRO-VERSION-PIN.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/guidelines/checklist/README.md b/src/guidelines/checklist/README.md index 846042f..46a3889 100644 --- a/src/guidelines/checklist/README.md +++ b/src/guidelines/checklist/README.md @@ -56,6 +56,7 @@ - [ ] Prefer 'macros by example' over proc macros ([M-EXAMPLE-OVER-PROC]) - [ ] Macros don't lie about signatures ([M-MACROS-DONT-LIE]) - [ ] Macros assume main crate ([M-MACRO-MAIN-CRATE]) + - [ ] Pin supporting proc macro crates ([M-MACRO-VERSION-PIN]) - [ ] Third party items come from hidden `_private` module ([M-MACRO-HELPERS]) - [ ] Proc macros should have separate impl crate incl. tests ([M-PROC-IMPL]) - [ ] Proc macros don't produce implied or hidden items ([M-PROC-IMPLIED-ITEMS]) @@ -203,6 +204,7 @@ [M-EXAMPLE-OVER-PROC]: ../macros/#M-EXAMPLE-OVER-PROC [M-MACROS-DONT-LIE]: ../macros/#M-MACROS-DONT-LIE [M-MACRO-MAIN-CRATE]: ../macros/#M-MACRO-MAIN-CRATE +[M-MACRO-VERSION-PIN]: ../macros/#M-MACRO-VERSION-PIN [M-MACRO-HELPERS]: ../macros/#M-MACRO-HELPERS [M-PROC-IMPL]: ../macros/#M-PROC-IMPL [M-PROC-IMPLIED-ITEMS]: ../macros/#M-PROC-IMPLIED-ITEMS diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index 8f65601..af12517 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -19,7 +19,7 @@ to exact-pin their dependency on the main crate. For example: -```rust,ignore +```toml # my_crate/Cargo.toml [package] version = "1.2.3" From af376dbe68d80dea4ec73da10c7606a56253cf24 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Thu, 10 Sep 2026 08:49:24 +0200 Subject: [PATCH 10/13] Update M-MACRO-VERSION-PIN guidelines Clarify guidelines for pinning dependencies of proc macro crates to ensure compatibility. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index af12517..381792d 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -4,20 +4,18 @@ keep generated code compatible with its library -This guideline applies to libraries that re-export macros from supporting proc macro crates -where users depend on the main crate, not the supporting crates. Independently consumed macro -libraries are outside its scope. +A crate that re-exports macros from a companion proc macro crate must pin that dependency +to its own exact version (`=x.y.z`). This also applies to any separate macro implementation +crate. Release these crates together with the same version number, even if some crates have +no code changes. -A newer macro may generate code that needs types or helpers unavailable in an older library. -To keep them compatible, release the main crate and its supporting crates together, with -matching version numbers and exact dependency pins. If there is a separate macro implementation -crate, pin that dependency too. Use `=1.2.3`, not `1.2.3`, which allows compatible updates. +Without exact pins, Cargo may upgrade the macro crate independently of the main crate. +The newer macro may then generate code that uses types or helpers added in a newer library +release, breaking compilation even when those additions were semver compatible. -Update all package versions and their pins on each release, even if some crates have no code changes. -Choose the version bump based on the main crate's public API, including its macros. Users do not need -to exact-pin their dependency on the main crate. +M-MACRO-VERSION-PIN does not apply to independently consumed macro libraries. -For example: +Example: ```toml # my_crate/Cargo.toml From 3735fe26dadf4986f468f973fae8517b697448e4 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Thu, 10 Sep 2026 08:50:56 +0200 Subject: [PATCH 11/13] Update guidelines on macro version pinning Clarify the requirement to pin macro dependencies to exact versions and release them together. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index 381792d..e821ffc 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -5,7 +5,7 @@ keep generated code compatible with its library A crate that re-exports macros from a companion proc macro crate must pin that dependency -to its own exact version (`=x.y.z`). This also applies to any separate macro implementation +to its own exact version via `=x.y.z`. This also applies to any separate macro implementation crate. Release these crates together with the same version number, even if some crates have no code changes. From bc30d60f8b3ada5f1e972c32496879c6ea0317b2 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Thu, 10 Sep 2026 08:55:36 +0200 Subject: [PATCH 12/13] Update M-MACRO-VERSION-PIN.md for clarity Clarified the impact of not using exact version pins for macros, emphasizing potential compilation issues with older libraries. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index e821ffc..594a680 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -9,9 +9,9 @@ to its own exact version via `=x.y.z`. This also applies to any separate macro i crate. Release these crates together with the same version number, even if some crates have no code changes. -Without exact pins, Cargo may upgrade the macro crate independently of the main crate. -The newer macro may then generate code that uses types or helpers added in a newer library -release, breaking compilation even when those additions were semver compatible. +Without exact pins, a newer macro may generate code that relies on types or helpers added +in a newer library release. This can break compilation with an older library, even when +the additions were semver compatible. M-MACRO-VERSION-PIN does not apply to independently consumed macro libraries. From 0396e21ff4e9163176bfb3be51e0d315f5b00163 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Thu, 10 Sep 2026 10:35:29 +0200 Subject: [PATCH 13/13] Update version pinning guidelines for proc macro crates Clarified guidelines for pinning proc macro crate versions and publishing. --- src/guidelines/macros/M-MACRO-VERSION-PIN.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/guidelines/macros/M-MACRO-VERSION-PIN.md b/src/guidelines/macros/M-MACRO-VERSION-PIN.md index 594a680..ba1ecd7 100644 --- a/src/guidelines/macros/M-MACRO-VERSION-PIN.md +++ b/src/guidelines/macros/M-MACRO-VERSION-PIN.md @@ -4,10 +4,9 @@ keep generated code compatible with its library -A crate that re-exports macros from a companion proc macro crate must pin that dependency -to its own exact version via `=x.y.z`. This also applies to any separate macro implementation -crate. Release these crates together with the same version number, even if some crates have -no code changes. +A crate that re-exports macros from a companion proc macro crates must pin those dependencies +to its own exact version via `=x.y.z` and publish all related crates at the same time with the +same exact version. Without exact pins, a newer macro may generate code that relies on types or helpers added in a newer library release. This can break compilation with an older library, even when