From 4803644df98f09d0da1022e85e4820403c785fe1 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 29 Jan 2026 17:20:32 +0800 Subject: [PATCH 1/5] Fix false positive in unused_parens caused by break --- compiler/rustc_lint/src/unused.rs | 5 +++- ...nused-parens-labeled-break-issue-143256.rs | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/unused-parens-labeled-break-issue-143256.rs diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 506a16355e226..27ddd4fb5f28c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -794,7 +794,10 @@ trait UnusedDelimLint { ExprKind::Break(_label, None) => return false, ExprKind::Break(_label, Some(break_expr)) => { - return matches!(break_expr.kind, ExprKind::Block(..)); + // `if (break 'label i) { ... }` removing parens would make `i { ... }` + // be parsed as a struct literal, so keep parentheses if the break value + // ends with a path (which could be mistaken for a struct name). + return matches!(break_expr.kind, ExprKind::Block(..) | ExprKind::Path(..)); } ExprKind::Range(_lhs, Some(rhs), _limits) => { diff --git a/tests/ui/lint/unused-parens-labeled-break-issue-143256.rs b/tests/ui/lint/unused-parens-labeled-break-issue-143256.rs new file mode 100644 index 0000000000000..8594e646f605e --- /dev/null +++ b/tests/ui/lint/unused-parens-labeled-break-issue-143256.rs @@ -0,0 +1,25 @@ +//@ check-pass +// testcase for https://github.com/rust-lang/rust/issues/143256 + +#![deny(unused_parens)] +#![allow(unreachable_code, unused_variables, dead_code)] + +fn foo() { + let _x = || 'outer: loop { + let inner = 'inner: loop { + let i = Default::default(); + // the parentheses here are necessary + if (break 'outer i) { + loop { + break 'inner 5i8; + } + } else if true { + break 'inner 6; + } + break 7; + }; + break inner < 8; + }; +} + +fn main() {} From a333f6f93c5fe34d59e24af1269b528c6b608596 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Thu, 29 Jan 2026 12:04:30 +0000 Subject: [PATCH 2/5] Fix missing syntax context in lifetime hygiene debug output `-Zunpretty=expanded,hygiene` was not printing the syntax context for lifetimes. For example, two macro-generated lifetimes `'a` with different hygiene would both print as `/* 2538 */` instead of `/* 2538#0 */` and `/* 2538#1 */`, making it impossible to distinguish them. This was fixed by changing `print_lifetime` to call `ann_post()` with the full `Ident`, matching how regular identifiers are handled in `print_ident`. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 3 +- tests/ui/hygiene/unpretty-debug-lifetimes.rs | 18 +++++++++++ .../hygiene/unpretty-debug-lifetimes.stdout | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/ui/hygiene/unpretty-debug-lifetimes.rs create mode 100644 tests/ui/hygiene/unpretty-debug-lifetimes.stdout diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index e50e31c226fdb..c8874ed99dca9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1961,7 +1961,8 @@ impl<'a> State<'a> { } fn print_lifetime(&mut self, lifetime: ast::Lifetime) { - self.print_name(lifetime.ident.name) + self.word(lifetime.ident.name.to_string()); + self.ann_post(lifetime.ident) } fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) { diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.rs b/tests/ui/hygiene/unpretty-debug-lifetimes.rs new file mode 100644 index 0000000000000..ee8be21b60d01 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, lifetimes were missing the #N syntax context suffix. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature(decl_macro)] +#![feature(no_core)] +#![no_core] + +macro lifetime_hygiene($f:ident<$a:lifetime>) { + fn $f<$a, 'a>() {} +} + +lifetime_hygiene!(f<'a>); diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout new file mode 100644 index 0000000000000..28a5c70a02d79 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout @@ -0,0 +1,31 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, lifetimes were missing the #N syntax context suffix. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature /* 0#0 */(decl_macro)] +#![feature /* 0#0 */(no_core)] +#![no_core /* 0#0 */] + +macro lifetime_hygiene + /* + 0#0 + */ { + ($f:ident<$a:lifetime>) => { fn $f<$a, 'a>() {} } +} +fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} + + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "lifetime_hygiene") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) +*/ From 21c99d3ad9ca533a2c4fe2a6bff19b7f74fd07f5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 29 Jan 2026 18:00:33 +1100 Subject: [PATCH 3/5] Fix some typos of "similarity" --- compiler/rustc_arena/src/lib.rs | 4 ++-- typos.toml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 5e81ec28ee35f..cc18cf38ef4c9 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -208,7 +208,7 @@ impl TypedArena { &self, iter: impl IntoIterator>, ) -> Result<&mut [T], E> { - // Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason + // Despite the similarity with `DroplessArena`, we cannot reuse their fast case. The reason // is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a // reference to `self` and adding elements to the arena during iteration. // @@ -584,7 +584,7 @@ impl DroplessArena { &self, iter: impl IntoIterator>, ) -> Result<&mut [T], E> { - // Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we + // Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we // cannot know the minimum length of the iterator in this case. assert!(size_of::() != 0); diff --git a/typos.toml b/typos.toml index 25083174cb8fb..e486a7c1722cd 100644 --- a/typos.toml +++ b/typos.toml @@ -46,6 +46,7 @@ unstalled = "unstalled" # short for un-stalled # # tidy-alphabetical-start definitinon = "definition" +similarlty = "similarity" # tidy-alphabetical-end [default.extend-identifiers] From 363d3ac4382e3f46a7472bed796aebc34f76deab Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 29 Jan 2026 18:05:40 +1100 Subject: [PATCH 4/5] Document a safety condition for `TypedArena::alloc_raw_slice` --- compiler/rustc_arena/src/lib.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index cc18cf38ef4c9..524baf5b07fec 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -172,8 +172,22 @@ impl TypedArena { available_bytes >= additional_bytes } + /// Allocates storage for `len >= 1` values in this arena, and returns a + /// raw pointer to the first value's storage. + /// + /// # Safety + /// + /// Caller must initialize each of the `len` slots to a droppable value + /// before the arena is dropped. + /// + /// In practice, this typically means that the caller must be able to + /// raw-copy `len` already-initialized values into the slice without any + /// possibility of panicking. + /// + /// FIXME(Zalathar): This is *very* fragile; perhaps we need a different + /// approach to arena-allocating slices of droppable values. #[inline] - fn alloc_raw_slice(&self, len: usize) -> *mut T { + unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T { assert!(size_of::() != 0); assert!(len != 0); @@ -229,9 +243,15 @@ impl TypedArena { } // Move the content to the arena by copying and then forgetting it. let len = vec.len(); - let start_ptr = self.alloc_raw_slice(len); + + // SAFETY: After allocating raw storage for exactly `len` values, we + // must fully initialize the storage without panicking, and we must + // also prevent the stale values in the vec from being dropped. Ok(unsafe { + let start_ptr = self.alloc_raw_slice(len); + // Initialize the newly-allocated storage without panicking. vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + // Prevent the stale values in the vec from being dropped. vec.set_len(0); slice::from_raw_parts_mut(start_ptr, len) }) From 69624f54051c420dbe51f17afed8799430c348c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 29 Jan 2026 17:56:04 +0100 Subject: [PATCH 5/5] Fix flakyness issue with `tests/rustdoc-gui/globals.goml` test --- tests/rustdoc-gui/globals.goml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml index 89f57add81618..b4a139537102d 100644 --- a/tests/rustdoc-gui/globals.goml +++ b/tests/rustdoc-gui/globals.goml @@ -11,7 +11,7 @@ assert-window-property-false: {"searchIndex": null} // Form input go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" call-function: ("perform-search", {"query": "Foo"}) -assert-window-property-false: {"searchIndex": null} +wait-for-window-property-false: {"searchIndex": null} // source sidebar go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"