diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 5e81ec28ee35f..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); @@ -208,7 +222,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. // @@ -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) }) @@ -584,7 +604,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/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/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/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" 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) +*/ 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() {} 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]