From cfdd4f5036b8c360de705adf20bc502ca4301290 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Fri, 23 Oct 2026 13:05:28 -0400 Subject: [PATCH 1/6] rustfmt: prevent more comment loss in `cfg_select!` Fixes rustfmt issue 7209 Now rustfmt shouldn't loose comments between braces when formatting `cfg_select!` arms that use double brace syntax. For example, ```rust cfg_select! { _ => { // after opening brace { x } // before closing brace } } ``` --- src/macros.rs | 2 +- src/parse/macros/cfg_select.rs | 20 +++++++++++++++++-- tests/source/cfg_select_edge_cases.rs | 6 ++++++ tests/target/cfg_select_edge_cases.rs | 13 ++++++++++++- tests/target/issue_7209.rs | 28 +++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 tests/target/issue_7209.rs diff --git a/src/macros.rs b/src/macros.rs index 935459ee467..4e82f89e437 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1630,7 +1630,7 @@ fn format_cfg_select( } }; - match arm.double_block_inner() { + match arm.double_block_inner(context) { // FIXME(ytmimi) The formatting for the `$predicate => {{}}` case isn't very robust. // There's the potential that we'll lose comments in between the predicate, the `=>` // and the body. We also don't handle comments like `{/*comment*/{}/*comment*/}`. diff --git a/src/parse/macros/cfg_select.rs b/src/parse/macros/cfg_select.rs index 599eb889dab..5c5963320d6 100644 --- a/src/parse/macros/cfg_select.rs +++ b/src/parse/macros/cfg_select.rs @@ -13,9 +13,11 @@ use rustc_parse::parser::{AllowConstBlockItems, ForceCollect}; use rustc_span::Span; use tracing::debug; +use crate::comment::contains_comment; use crate::expr::is_unsafe_block; use crate::parse::macros::build_stream_parser; use crate::parse::session::ParseSess; +use crate::rewrite::RewriteContext; use crate::spanned::Spanned; // NB: parser recovery can return `Ok(expr)` (or other non-terminals) and still emit errors. We need @@ -164,7 +166,7 @@ impl CfgSelectArm { /// Is the cfg_select! arm written with two consecutive blocks. /// For example `$predicate => {{}}`. If so, extract the inner block. /// rustfmt will preserve the double block syntax. - pub(crate) fn double_block_inner(&self) -> Option<&ast::Expr> { + pub(crate) fn double_block_inner(&self, context: &RewriteContext<'_>) -> Option<&ast::Expr> { // In order to see if we can reach in and grab the inner block we'll // check the following properties of the outer block: // 1. It has a single statement that's also a block @@ -180,7 +182,21 @@ impl CfgSelectArm { { match &b.stmts[0].kind { // This is where we check that the inner block's statement is also a block - ast::StmtKind::Expr(e) if matches!(e.kind, ast::ExprKind::Block(..)) => Some(e), + ast::StmtKind::Expr(e) if matches!(e.kind, ast::ExprKind::Block(..)) => { + let pre_span = b.span.shrink_to_lo().between(e.span()); + let pre_snippet = context.snippet(pre_span).trim(); + + let post_span = e.span().shrink_to_hi().between(b.span.shrink_to_hi()); + let post_snippet = context.snippet(post_span).trim(); + + if !contains_comment(pre_snippet) && !contains_comment(post_snippet) { + // To prevent comment loss between the blocks we only want to return + // the inner block if there aren't any pre / post comments. + Some(e) + } else { + None + } + } _ => None, } } diff --git a/tests/source/cfg_select_edge_cases.rs b/tests/source/cfg_select_edge_cases.rs index 586a961864c..3c591d3afd5 100644 --- a/tests/source/cfg_select_edge_cases.rs +++ b/tests/source/cfg_select_edge_cases.rs @@ -61,6 +61,12 @@ fn cfg_select_comments_that_might_get_lost() { // before closing brace } } + cfg_select! { + _ => { /* after opening brace */ + { x } + /* before closing brace */ + } + } cfg_select! { _ => /* after => */ {{ x }} } diff --git a/tests/target/cfg_select_edge_cases.rs b/tests/target/cfg_select_edge_cases.rs index 96a3373e339..dec05d032e3 100644 --- a/tests/target/cfg_select_edge_cases.rs +++ b/tests/target/cfg_select_edge_cases.rs @@ -72,7 +72,18 @@ fn check_match_block_formatting() { fn cfg_select_comments_that_might_get_lost() { cfg_select! { - _ => {{ x }} + _ => { + // after opening brace + { x } + // before closing brace + } + } + cfg_select! { + _ => { + /* after opening brace */ + { x } + /* before closing brace */ + } } cfg_select! { _ => {{ x }} diff --git a/tests/target/issue_7209.rs b/tests/target/issue_7209.rs new file mode 100644 index 00000000000..0d7d015459a --- /dev/null +++ b/tests/target/issue_7209.rs @@ -0,0 +1,28 @@ +//@ rustfmt-unstable: true + +fn gettid() -> u64 { + cfg_select! { + any(target_os = "android", target_os = "linux") => gettid_linux_like(), + any(target_os = "nto", target_os = "qnx") => unsafe { libc::gettid() as u64 }, + target_os = "openbsd" => unsafe { libc::getthrid() as u64 }, + target_os = "freebsd" => unsafe { libc::pthread_getthreadid_np() as u64 }, + target_os = "netbsd" => unsafe { libc::_lwp_self() as u64 }, + any(target_os = "solaris", target_os = "illumos") => { + // On Solaris and Illumos, the `pthread_t` is the OS TID. + unsafe { libc::pthread_self() as u64 } + } + target_vendor = "apple" => { + let mut id = 0u64; + let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) }; + assert_eq!(status, 0); + id + } + windows => { + use windows_sys::Win32::System::Threading::GetCurrentThreadId; + unsafe { GetCurrentThreadId() as u64 } + } + _ => { + compile_error!("platform has no gettid") + } + } +} From 60837750a9da75f844fd964a44b29c47c1e49190 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Oct 2026 12:30:14 +1000 Subject: [PATCH 2/6] Remove unnecessary `Span::{data,data_untracked}` calls It's best to use `Span` methods because `SpanData` is mostly an internal detail, and to avoid unnecessary `SPAN_TRACK` calls. In the following cases, removing the `data()` gives identical behaviour: - `span.data().lo` --> `span.lo()` - `span.data().hi` --> `span.hi()` - `span.data().lo` + `span.data().hi` --> `span.lo_hi()` In the following case, removing the `data_untracked()` gives identical behaviour: - `span.data_untracked().parent` --> `span.parent()` In the following case, removing the `data` removes an unnecessary `SPAN_TRACK` call (because `SPAN_TRACK` is only needed for lo/hi accesses): - `span.data().ctxt` --> `span.ctxt()` --- src/parse/session.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index c61b43492ce..0df19406607 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -195,9 +195,7 @@ impl ParseSess { } pub(crate) fn span_to_file_contents(&self, span: Span) -> Arc { - self.raw_psess - .source_map() - .lookup_source_file(span.data().lo) + self.raw_psess.source_map().lookup_source_file(span.lo()) } pub(crate) fn span_to_first_line_string(&self, span: Span) -> String { From 589d562b04274082407d5e9f6930100a47b1a587 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 2 Nov 2026 19:09:10 +0800 Subject: [PATCH 3/6] Prepare for merging from rust-lang/rust This updates the rust-toolchain.toml file to nightly-2026-11-02 (3e92e1a2d20b991ef23a6c6064c34d57ee8c98d3). --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d621e4fb084..0a85b69efd3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-10-22" +channel = "nightly-2026-11-02" components = ["llvm-tools", "rustc-dev"] From 08996963f6bfaaefaa5c58109c90effcd664f686 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 2 Nov 2026 20:04:38 +0800 Subject: [PATCH 4/6] chore: prepare changelog for v1.12.0 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454ffc1a91c..72b916164ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,34 @@ ## [Unreleased] -### Changed -- The unstable `required_version` configuration option now defaults to a caret (`^`) semver requirement instead of an exact match when no comparator is given, matching how Cargo treats dependency version requirements. Use the explicit `=` operator (e.g. `required_version = "=1.2.3"`) to opt back into exact matching [#6729](https://github.com/rust-lang/rustfmt/issues/6729) + +## [1.12.0] 2026-12-24 +### Changed +- The unstable `required_version` configuration option now defaults to a caret (`^`) semver requirement instead of an exact match when no comparator is given, matching how Cargo treats dependency version requirements. Use the explicit `=` operator (e.g. `required_version = "=1.2.3"`) to opt back into exact matching [#6729](https://github.com/rust-lang/rustfmt/issues/6729) [#7048](https://github.com/rust-lang/rustfmt/pull/7048) +> [!IMPORTANT] +> Potential breaking changes: +> - When `--config-path` is a directory, rustfmt now also searches its parent directories for config files [#4660](https://github.com/rust-lang/rustfmt/issues/4660) [#7115](https://github.com/rust-lang/rustfmt/pull/7115) +> - Chains with comments now format under `use_try_shorthand=true` [#6121](https://github.com/rust-lang/rustfmt/issues/6121) [#7095](https://github.com/rust-lang/rustfmt/pull/7095) +> - Error on `--print-config minimal` with no output path [#7208](https://github.com/rust-lang/rustfmt/pull/7208) +> - Previously, this printed a warning and exited with `0`. + +### Fixed +- Fix ragged statement comment wrapping under unstable option `wrap_comments=true` and `comment_width` [#7167](https://github.com/rust-lang/rustfmt/issues/7167) [#7170](https://github.com/rust-lang/rustfmt/pull/7170) +- Enforce comment width in item lists [#7174](https://github.com/rust-lang/rustfmt/pull/7174) +- Fix lookup of global config files [#7178](https://github.com/rust-lang/rustfmt/issues/7178) [#7179](https://github.com/rust-lang/rustfmt/pull/7179) +- Don't remove empty generic args when formatting in a macro context [#7136](https://github.com/rust-lang/rustfmt/issues/7136) [#7181](https://github.com/rust-lang/rustfmt/pull/7181) +- Various `cfg_select!` fixes. Note that `cfg_select!` formatting is still nightly-gated. + - Fix `cfg_select!` parser recovery handling and error count leak [#7171](https://github.com/rust-lang/rustfmt/pull/7171) + - Don't remove necessary blocks when formatting `cfg_select!` arms [#7045](https://github.com/rust-lang/rustfmt/issues/7045) [#7183](https://github.com/rust-lang/rustfmt/pull/7183) + - Prevent more comment loss in `cfg_select!` [#7209](https://github.com/rust-lang/rustfmt/issues/7209) [rust-lang/rust#164815](https://github.com/rust-lang/rust/pull/164815) + - Don't lose comments and attributes between `cfg_select!` predicates, outer/inner blocks, arm body and trailing commas [#7209](https://github.com/rust-lang/rustfmt/issues/7209) [#7211](https://github.com/rust-lang/rustfmt/pull/7211) + - Have `cfg_select!` double-brace concise formatting respect `control_brace_style` unstable option [#7214](https://github.com/rust-lang/rustfmt/pull/7214) +- Prevent rustfmt from removing expression attributes when removing nested parentheses [#7190](https://github.com/rust-lang/rustfmt/issues/7190) [#7192](https://github.com/rust-lang/rustfmt/pull/7192) +- Fix `cfg_if!` error count leaks [#7195](https://github.com/rust-lang/rustfmt/pull/7195) +- Format comments after `where` clauses using `clause_shape` budget (affecting unstable options `wrap_comments=true` and `comment_width`) [#7148](https://github.com/rust-lang/rustfmt/issues/7148) [#7156](https://github.com/rust-lang/rustfmt/pull/7156) +- Fix ICE on failure to format generics in enum [#5738](https://github.com/rust-lang/rustfmt/issues/5738) [#6137](https://github.com/rust-lang/rustfmt/issues/6137) [#6318](https://github.com/rust-lang/rustfmt/issues/6318) [#6646](https://github.com/rust-lang/rustfmt/issues/6646) [#6396](https://github.com/rust-lang/rustfmt/pull/6396) +- Avoid leaking wrapper space from doc comment code block formatting (affecting unstable options `format_code_in_doc_comments=true` and `fn_single_line=true`) [#6832](https://github.com/rust-lang/rustfmt/issues/6832) [#6851](https://github.com/rust-lang/rustfmt/pull/6851) ## [1.11.0] 2026-11-12 From e4a66aa0a72be847a32a01a6a7227a29a6bcca17 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 2 Nov 2026 20:35:24 +0800 Subject: [PATCH 5/6] chore: remove changelog entry that's intended to be reverted in beta See . --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b916164ae..b28723aa08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,6 @@ - Correct visibility and defaultness order on associated impl type alias [#7064](https://github.com/rust-lang/rustfmt/pull/7064). - Correctly calculate the `shape` for inline const blocks when using `style_edition=2027` [#7065](https://github.com/rust-lang/rustfmt/pull/7065). - Prevent invalid code generation in macros that use raw identifiers [#7110](https://github.com/rust-lang/rustfmt/pull/7110). -- Prevent rustfmt from reporting on `max_width` configuration issues when formatting macros [#6651](https://github.com/rust-lang/rustfmt/pull/6651). ### Changed - No longer apply `use_field_init_shorthand` when formatting macros [#6981](https://github.com/rust-lang/rustfmt/pull/6981). From c27c61ad51fc4d312155b9848dad8e6410321e86 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 2 Nov 2026 20:05:54 +0800 Subject: [PATCH 6/6] chore: bump rustfmt version to v1.12.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b83c8ec9612..38d5f7724e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.11.0" +version = "1.12.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 9e689fc0041..78ee1fb2742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustfmt-nightly" -version = "1.11.0" +version = "1.12.0" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" license = "Apache-2.0 OR MIT"