From 3d41095af9752891b315cda30a4a91ee7db0763b Mon Sep 17 00:00:00 2001 From: Vladislav Date: Sun, 23 Feb 2025 10:51:22 +0100 Subject: [PATCH 01/20] Put shebang at the top of pretty-print --- compiler/rustc_ast_pretty/src/pprust/state.rs | 19 +++++++++++++++++++ tests/pretty/shebang-at-top.pp | 12 ++++++++++++ tests/pretty/shebang-at-top.rs | 6 ++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/pretty/shebang-at-top.pp create mode 100644 tests/pretty/shebang-at-top.rs diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0bf5de3ef8985..0d6c695108204 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -243,6 +243,11 @@ pub fn print_crate<'a>( let mut s = State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann }; + // We need to print shebang before anything else + // otherwise the resulting code will not compile + // and shebang will be useless. + s.maybe_print_shebang(); + if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. @@ -574,6 +579,20 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(st) } + fn maybe_print_shebang(&mut self) { + if let Some(cmnt) = self.peek_comment() { + // Comment is a shebang if it's: + // Isolated, starts with #! and doesn't continue with `[` + // See [rustc_lexer::strip_shebang] and [gather_comments] from pprust/state.rs for details + if cmnt.style == CommentStyle::Isolated + && cmnt.lines.first().map_or(false, |l| l.starts_with("#!")) + { + let cmnt = self.next_comment().unwrap(); + self.print_comment(cmnt); + } + } + } + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } diff --git a/tests/pretty/shebang-at-top.pp b/tests/pretty/shebang-at-top.pp new file mode 100644 index 0000000000000..a279725263640 --- /dev/null +++ b/tests/pretty/shebang-at-top.pp @@ -0,0 +1,12 @@ +#!/usr/bin/env rust +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} diff --git a/tests/pretty/shebang-at-top.rs b/tests/pretty/shebang-at-top.rs new file mode 100644 index 0000000000000..8bfa925fa1ab1 --- /dev/null +++ b/tests/pretty/shebang-at-top.rs @@ -0,0 +1,6 @@ +#!/usr/bin/env rust +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} From ff37c7d3954ce9d1c9265e7c82a0bb7b6eba6fee Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 1 Apr 2025 13:35:16 +0200 Subject: [PATCH 02/20] std: use the address of `errno` to identify threads in `unique_thread_exit` Getting the address of `errno` should be just as cheap as `pthread_self()` and avoids having to use the expensive `Mutex` logic because it always results in a pointer. --- library/std/src/sys/exit_guard.rs | 43 ++++++++++++++---------------- library/std/src/sys/pal/unix/os.rs | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index 5a090f506661d..bd70d1782440f 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -1,14 +1,5 @@ cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - /// pthread_t is a pointer on some platforms, - /// so we wrap it in this to impl Send + Sync. - #[derive(Clone, Copy)] - #[repr(transparent)] - struct PThread(libc::pthread_t); - // Safety: pthread_t is safe to send between threads - unsafe impl Send for PThread {} - // Safety: pthread_t is safe to share between threads - unsafe impl Sync for PThread {} /// Mitigation for /// /// On glibc, `libc::exit` has been observed to not always be thread-safe. @@ -30,28 +21,34 @@ cfg_if::cfg_if! { /// (waiting for the process to exit). #[cfg_attr(any(test, doctest), allow(dead_code))] pub(crate) fn unique_thread_exit() { - let this_thread_id = unsafe { libc::pthread_self() }; - use crate::sync::{Mutex, PoisonError}; - static EXITING_THREAD_ID: Mutex> = Mutex::new(None); - let mut exiting_thread_id = - EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); - match *exiting_thread_id { - None => { + use crate::ffi::c_int; + use crate::ptr; + use crate::sync::atomic::AtomicPtr; + use crate::sync::atomic::Ordering::{Acquire, Relaxed}; + + static EXITING_THREAD_ID: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + // We use the address of `errno` as a cheap and safe way to identify + // threads. As the C standard mandates that `errno` must have thread + // storage duration, we can rely on its address not changing over the + // lifetime of the thread. Additionally, accesses to `errno` are + // async-signal-safe, so this function is available in all imaginable + // circumstances. + let this_thread_id = crate::sys::os::errno_location(); + match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + Ok(_) => { // This is the first thread to call `unique_thread_exit`, - // and this is the first time it is called. - // Set EXITING_THREAD_ID to this thread's ID and return. - *exiting_thread_id = Some(PThread(this_thread_id)); - }, - Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => { + // and this is the first time it is called. Continue exiting. + } + Err(exiting_thread_id) if exiting_thread_id == this_thread_id => { // This is the first thread to call `unique_thread_exit`, // but this is the second time it is called. // Abort the process. core::panicking::panic_nounwind("std::process::exit called re-entrantly") } - Some(_) => { + Err(_) => { // This is not the first thread to call `unique_thread_exit`. // Pause until the process exits. - drop(exiting_thread_id); loop { // Safety: libc::pause is safe to call. unsafe { libc::pause(); } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f47421c67051b..3b712f316cd00 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -61,7 +61,7 @@ unsafe extern "C" { #[cfg_attr(target_os = "aix", link_name = "_Errno")] // SAFETY: this will always return the same pointer on a given thread. #[unsafe(ffi_const)] - fn errno_location() -> *mut c_int; + pub safe fn errno_location() -> *mut c_int; } /// Returns the platform-specific value of errno From a576362620a5e0691054a48fcdc7ba5038c042c5 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Thu, 10 Apr 2025 10:58:49 +1000 Subject: [PATCH 03/20] Document async block control flow in async keyword --- library/std/src/keyword_docs.rs | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c07c391892d80..93306296847cd 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2388,6 +2388,40 @@ mod while_keyword {} /// /// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. /// +/// ## Control Flow +/// [`return`] statements and [`?`][try operator] operators within `async` blocks do not cause +/// a return from the parent function; rather, they cause the `Future` returned by the block to +/// return with that value. +/// +/// For example, the following Rust function will return `5`, assigning the `!` value to `x`, which +/// goes unused: +/// ```rust +/// #[expect(unused_variables)] +/// fn example() -> i32 { +/// let x = { +/// return 5; +/// }; +/// } +/// ``` +/// In contrast, the following asynchronous function assigns a `Future` to `x`, and +/// only returns `5` when `x` is `.await`ed: +/// ```rust +/// async fn example() -> i32 { +/// let x = async { +/// return 5; +/// }; +/// +/// x.await +/// } +/// ``` +/// Code using `?` behaves similarly - it causes the `async` block to return a [`Result`] without +/// affecting the parent function. +/// +/// Note that you cannot use `break` or `continue` from within an `async` block to affect the +/// control flow of a loop in the parent function. +/// +/// Control flow in `async` blocks is documented further in the [async book][async book blocks]. +/// /// ## Editions /// /// `async` is a keyword from the 2018 edition onwards. @@ -2397,6 +2431,10 @@ mod while_keyword {} /// [`Future`]: future::Future /// [`.await`]: ../std/keyword.await.html /// [async book]: https://rust-lang.github.io/async-book/ +/// [`return`]: ../std/keyword.return.html +/// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [`Result`]: result::Result +/// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {} #[doc(keyword = "await")] From e2caab1822d858de4525ae615002094ab6e06734 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Thu, 10 Apr 2025 11:11:09 +1000 Subject: [PATCH 04/20] Doc more control flow behaviour for return keyword --- library/std/src/keyword_docs.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 93306296847cd..b8eb0fd104c3c 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1195,6 +1195,28 @@ mod ref_keyword {} /// Ok(()) /// } /// ``` +/// +/// Within [closures] and [`async`] blocks, `return` returns a value from within the closure or +/// `async` block, not from the parent function: +/// +/// ```rust +/// fn foo() -> i32 { +/// let closure = || { +/// return 5; +/// }; +/// +/// let future = async { +/// return 10; +/// }; +/// +/// return 15; +/// } +/// +/// assert_eq!(foo(), 15); +/// ``` +/// +/// [closures]: ../book/ch13-01-closures.html +/// [`async`]: ../std/keyword.async.html mod return_keyword {} #[doc(keyword = "self")] From 36ae6575fd85dd6eb9a00e097e47b38fa25235a0 Mon Sep 17 00:00:00 2001 From: Artur Roos Date: Wed, 23 Apr 2025 14:31:34 +0300 Subject: [PATCH 05/20] Document breaking out of a named code block --- library/std/src/keyword_docs.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c07c391892d80..b0e55c787250d 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -109,6 +109,33 @@ mod as_keyword {} /// println!("{result}"); /// ``` /// +/// It is also possible to exit from any *labelled* block returning the value early. +/// If no value specified `break;` returns `()`. +/// +/// ```rust +/// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; +/// +/// let mut results = vec![]; +/// for input in inputs { +/// let result = 'filter: { +/// if input.len() > 3 { +/// break 'filter Err("Too long"); +/// }; +/// +/// if !input.contains("C") { +/// break 'filter Err("No Cs"); +/// }; +/// +/// Ok(input.to_uppercase()) +/// }; +/// +/// results.push(result); +/// } +/// +/// // [Ok("COW"), Ok("CAT"), Err("No Cs"), Err("Too long"), Ok("COD")] +/// println!("{:?}", results) +/// ``` +/// /// For more details consult the [Reference on "break expression"] and the [Reference on "break and /// loop values"]. /// From e9d2fefe0cfa083965b83288f38e408df7f1cdd1 Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 30 Apr 2025 01:29:44 +0800 Subject: [PATCH 06/20] stop check paren if has different ctx --- compiler/rustc_lint/src/unused.rs | 16 +++++ ...sed-parens-for-macro-call-with-brace.fixed | 28 ++++++++ ...unused-parens-for-macro-call-with-brace.rs | 28 ++++++++ ...ed-parens-for-macro-call-with-brace.stderr | 67 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.rs create mode 100644 tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 806bca78f7875..50a27d7e84f58 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -942,6 +942,22 @@ trait UnusedDelimLint { match s.kind { StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some((init, els)) = local.kind.init_else_opt() { + if els.is_some() + && let ExprKind::Paren(paren) = &init.kind + && !init.span.eq_ctxt(paren.span) + { + // This branch prevents cases where parentheses wrap an expression + // resulting from macro expansion, such as: + // ``` + // macro_rules! x { + // () => { None:: }; + // } + // let Some(_) = (x!{}) else { return }; + // // -> let Some(_) = (None::) else { return }; + // // ~ ~ No Lint + // ``` + return; + } let ctx = match els { None => UnusedDelimsCtx::AssignedValue, Some(_) => UnusedDelimsCtx::AssignedValueLetElse, diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed b/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed new file mode 100644 index 0000000000000..4c9995fcb61a4 --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.fixed @@ -0,0 +1,28 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +fn main() { + macro_rules! x { + () => { None:: }; + } + + let Some(_) = (x!{}) else { return }; // no error + let Some(_) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around assigned value + + let Some(_) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around pattern + + let _ = x!{}; + let _ = x!{}; + //~^ ERROR: unnecessary parentheses around assigned value + + if let Some(_) = x!{} {}; + if let Some(_) = x!{} {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression + + while let Some(_) = x!{} {}; + while let Some(_) = x!{} {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression +} diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs b/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs new file mode 100644 index 0000000000000..59e215a48ccae --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.rs @@ -0,0 +1,28 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +fn main() { + macro_rules! x { + () => { None:: }; + } + + let Some(_) = (x!{}) else { return }; // no error + let Some(_) = ((x!{})) else { return }; + //~^ ERROR: unnecessary parentheses around assigned value + + let Some((_)) = (x!{}) else { return }; + //~^ ERROR: unnecessary parentheses around pattern + + let _ = x!{}; + let _ = (x!{}); + //~^ ERROR: unnecessary parentheses around assigned value + + if let Some(_) = x!{} {}; + if let Some(_) = (x!{}) {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression + + while let Some(_) = x!{} {}; + while let Some(_) = (x!{}) {}; + //~^ ERROR: unnecessary parentheses around `let` scrutinee expression +} diff --git a/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr b/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr new file mode 100644 index 0000000000000..8d3b4fe493e22 --- /dev/null +++ b/tests/ui/lint/unused-parens-for-macro-call-with-brace.stderr @@ -0,0 +1,67 @@ +error: unnecessary parentheses around assigned value + --> $DIR/unused-parens-for-macro-call-with-brace.rs:11:19 + | +LL | let Some(_) = ((x!{})) else { return }; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-for-macro-call-with-brace.rs:3:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let Some(_) = ((x!{})) else { return }; +LL + let Some(_) = (x!{}) else { return }; + | + +error: unnecessary parentheses around pattern + --> $DIR/unused-parens-for-macro-call-with-brace.rs:14:14 + | +LL | let Some((_)) = (x!{}) else { return }; + | ^ ^ + | +help: remove these parentheses + | +LL - let Some((_)) = (x!{}) else { return }; +LL + let Some(_) = (x!{}) else { return }; + | + +error: unnecessary parentheses around assigned value + --> $DIR/unused-parens-for-macro-call-with-brace.rs:18:13 + | +LL | let _ = (x!{}); + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = (x!{}); +LL + let _ = x!{}; + | + +error: unnecessary parentheses around `let` scrutinee expression + --> $DIR/unused-parens-for-macro-call-with-brace.rs:22:22 + | +LL | if let Some(_) = (x!{}) {}; + | ^ ^ + | +help: remove these parentheses + | +LL - if let Some(_) = (x!{}) {}; +LL + if let Some(_) = x!{} {}; + | + +error: unnecessary parentheses around `let` scrutinee expression + --> $DIR/unused-parens-for-macro-call-with-brace.rs:26:25 + | +LL | while let Some(_) = (x!{}) {}; + | ^ ^ + | +help: remove these parentheses + | +LL - while let Some(_) = (x!{}) {}; +LL + while let Some(_) = x!{} {}; + | + +error: aborting due to 5 previous errors + From 1157b78d62d61501e521afa0244aebab45ec6ba0 Mon Sep 17 00:00:00 2001 From: Sayantan Chakraborty <142906350+sayantn@users.noreply.github.com> Date: Fri, 18 Apr 2025 12:06:02 +0530 Subject: [PATCH 07/20] Remove `avx512dq` and `avx512vl` implication for `avx512fp16` --- compiler/rustc_target/src/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab23..e7f50c1356aad 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -398,7 +398,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), - ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]), + ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]), From adb92aeb4a1f6cd8313fa880c19a39a8caefbded Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 05:48:51 +0000 Subject: [PATCH 08/20] rustc_target: Adjust RISC-V feature implication (Za64rs and Za128rs) The Za64rs extension (reservation set -- a primitive memory unit of LR/SC atomic operations -- is naturally aligned and *at most* 64 bytes) is a superset of the Za128rs extension (*at most* 128 bytes; note that smaller the reservation set is, more fine grained control over atomics). This commit handles this as a feature implication. --- compiler/rustc_target/src/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab23..9031e0530c583 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -507,7 +507,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), ("za128rs", Unstable(sym::riscv_target_feature), &[]), - ("za64rs", Unstable(sym::riscv_target_feature), &[]), + ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs ("zaamo", Unstable(sym::riscv_target_feature), &[]), ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), From c6ed7869a13194748653f48350225bc9e0ced2ca Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 06:05:41 +0000 Subject: [PATCH 09/20] rustc_target: RISC-V: Add atomics/memory-related extensions This commit adds a part of RISC-V extensions that are mandatory part of the RVA23U64 profile (application-class processor profile) and related to memory/atomic constraints. The Zic64b extension constrains the cache line to naturally-aligned 64 bytes that would make certain memory operations (like zeroing the memory using the Zicboz extension) easier. The Zicbom and Zicbop extensions enable managing cache block-based operations (the Zicbop contains hints that will work as a NOP when this extension is absent and the Zicbom contains control instructions). Of which, the Zicbom extension is going to be discoverable from the Linux kernel (as of the version 6.15-rc4) and this commit prepares for corresponding stdarch changes. The Zicc* extensions add certain constraints to "the main memory" (usually true on the user mode application on the application-class processor but those extensions make sure such constraints exist). --- compiler/rustc_target/src/target_features.rs | 7 +++++++ tests/ui/check-cfg/target_feature.stderr | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 9031e0530c583..99f39b34b6298 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -531,7 +531,14 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zic64b", Unstable(sym::riscv_target_feature), &[]), + ("zicbom", Unstable(sym::riscv_target_feature), &[]), + ("zicbop", Unstable(sym::riscv_target_feature), &[]), ("zicboz", Unstable(sym::riscv_target_feature), &[]), + ("ziccamoa", Unstable(sym::riscv_target_feature), &[]), + ("ziccif", Unstable(sym::riscv_target_feature), &[]), + ("zicclsm", Unstable(sym::riscv_target_feature), &[]), + ("ziccrse", Unstable(sym::riscv_target_feature), &[]), ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zicond", Unstable(sym::riscv_target_feature), &[]), ("zicsr", Unstable(sym::riscv_target_feature), &[]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 4f7b8345e86ad..1740587735499 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -329,7 +329,14 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zfinx` `zhinx` `zhinxmin` +`zic64b` +`zicbom` +`zicbop` `zicboz` +`ziccamoa` +`ziccif` +`zicclsm` +`ziccrse` `zicntr` `zicond` `zicsr` From 501a539bbe74164384ebf42165b058bc01f6b5a2 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 30 Apr 2025 06:53:22 +0000 Subject: [PATCH 10/20] rustc_target: RISC-V: Add BF16 extensions This commit adds three ratified unprivileged RISC-V extensions related to BFloat16 (BF16) handling. Although that they are far from stabilization due to ABI issues, they are optional extensions of the RVA23U64 profile (application-class processor profile) and going to be discoverable from the Linux kernel (as of version 6.15-rc4). This commit mainly prepares runtime detection of those extensions. --- compiler/rustc_target/src/target_features.rs | 3 +++ tests/ui/check-cfg/target_feature.stderr | 3 +++ 2 files changed, 6 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 99f39b34b6298..009118f2d4ff4 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -526,6 +526,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), ("zfa", Unstable(sym::riscv_target_feature), &["f"]), + ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), @@ -565,6 +566,8 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), + ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 1740587735499..712ce941c54ce 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -324,6 +324,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zcmop` `zdinx` `zfa` +`zfbfmin` `zfh` `zfhmin` `zfinx` @@ -363,6 +364,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zve64d` `zve64f` `zve64x` +`zvfbfmin` +`zvfbfwma` `zvfh` `zvfhmin` `zvkb` From eec6cfb8dab2d20e58a44df0e1c52c5abf6b2d26 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Mon, 24 Mar 2025 00:23:46 +0000 Subject: [PATCH 11/20] rustc_target: RISC-V "Zfinx" is incompatible with {ILP32,LP64}[FD] ABIs Because RISC-V Calling Conventions note that: > This means code targeting the Zfinx extension always uses the ILP32, > ILP32E or LP64 integer calling-convention only ABIs as there is no > dedicated hardware floating-point register file. {ILP32,LP64}[FD] ABIs with hardware floating-point calling conventions are incompatible with the "Zfinx" extension. This commit adds "zfinx" to the incompatible feature list to those ABIs and tests whether trying to add "zdinx" (that is analogous to "zfinx" but in double-precision) on a LP64D ABI configuration results in an error (it also tests extension implication; "Zdinx" requires "Zfinx" extension). Link: RISC-V psABI specification version 1.0 --- compiler/rustc_target/src/target_features.rs | 8 ++++---- ...bidden-hardfloat-target-feature-attribute-e-d.rs} | 0 ...en-hardfloat-target-feature-attribute-e-d.stderr} | 2 +- ...den-hardfloat-target-feature-attribute-f-zfinx.rs | 12 ++++++++++++ ...hardfloat-target-feature-attribute-f-zfinx.stderr | 8 ++++++++ 5 files changed, 25 insertions(+), 5 deletions(-) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.rs => forbidden-hardfloat-target-feature-attribute-e-d.rs} (100%) rename tests/ui/target-feature/{forbidden-hardfloat-target-feature-attribute.stderr => forbidden-hardfloat-target-feature-attribute-e-d.stderr} (77%) create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs create mode 100644 tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab23..9c8c804e18cd7 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -963,12 +963,12 @@ impl Target { // about what the intended ABI is. match &*self.llvm_abiname { "ilp32d" | "lp64d" => { - // Requires d (which implies f), incompatible with e. - FeatureConstraints { required: &["d"], incompatible: &["e"] } + // Requires d (which implies f), incompatible with e and zfinx. + FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] } } "ilp32f" | "lp64f" => { - // Requires f, incompatible with e. - FeatureConstraints { required: &["f"], incompatible: &["e"] } + // Requires f, incompatible with e and zfinx. + FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] } } "ilp32" | "lp64" => { // Requires nothing, incompatible with e. diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr similarity index 77% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr index bfe767e5ffb07..84d27463b38cd 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr @@ -1,5 +1,5 @@ error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18 + --> $DIR/forbidden-hardfloat-target-feature-attribute-e-d.rs:10:18 | LL | #[target_feature(enable = "d")] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs new file mode 100644 index 0000000000000..d74f4a1d4b170 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs @@ -0,0 +1,12 @@ +//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. +//@ compile-flags: --target=riscv64gc-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +#[target_feature(enable = "zdinx")] +//~^ERROR: cannot be enabled with +pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr new file mode 100644 index 0000000000000..af0e53f34f23a --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr @@ -0,0 +1,8 @@ +error: target feature `zfinx` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs:10:18 + | +LL | #[target_feature(enable = "zdinx")] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 7cb357a36b96781f9ff85f8a4168382243352ba1 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 11 Apr 2025 02:52:17 -0700 Subject: [PATCH 12/20] Make internal `OsString::truncate` and `extend_from_slice` unsafe Communicate the safety invariants of these methods with `unsafe fn` rather than privacy. --- library/std/src/ffi/os_str.rs | 22 +++++++++++++++------ library/std/src/path.rs | 3 ++- library/std/src/sys/os_str/bytes.rs | 25 +++++++++++++++--------- library/std/src/sys/os_str/wtf8.rs | 30 ++++++++++++++++++++--------- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ce01175309a77..72bdf03ee61a4 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -582,15 +582,25 @@ impl OsString { #[unstable(feature = "os_string_truncate", issue = "133262")] pub fn truncate(&mut self, len: usize) { self.as_os_str().inner.check_public_boundary(len); - self.inner.truncate(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`OsStr::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the encoding-dependent surrogate joining, so `self` must + /// not end with a leading surrogate half and `other` must not start with + /// with a trailing surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { - self.inner.extend_from_slice(other); + pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { + // SAFETY: Guaranteed by caller. + unsafe { self.inner.extend_from_slice_unchecked(other) }; } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 50f403ba411b6..ae18891ad47d3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2759,7 +2759,8 @@ impl Path { }; let mut new_path = PathBuf::with_capacity(new_capacity); - new_path.inner.extend_from_slice(slice_to_copy); + // SAFETY: The path is empty, so cannot have surrogate halves. + unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) }; new_path.set_extension(extension); new_path } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index dfff2d3e5d31d..4a8808c923045 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -216,19 +216,26 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. - #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. + #[inline] + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// This encoding has no safety requirements. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index a32f5d40f6a9c..5174ea65d0cd9 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -195,19 +195,31 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. - #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. + #[inline] + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`Slice::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a + /// leading surrogate half and `other` must not start with with a trailing + /// surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } From 0f0c0d8b16b265ac57cac9fd50f1dcfe78719a6a Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 22 Apr 2025 03:31:45 -0700 Subject: [PATCH 13/20] Avoid redundant WTF-8 checks in `PathBuf` Eliminate checks for WTF-8 boundaries in `PathBuf::set_extension` and `add_extension`, where joining WTF-8 surrogate halves is impossible. Don't convert the `str` to `OsStr`, because `OsString::push` specializes to skip the joining when given strings. --- library/std/src/path.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index ae18891ad47d3..32a86e9f7b405 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1526,11 +1526,13 @@ impl PathBuf { self.inner.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true @@ -1587,7 +1589,7 @@ impl PathBuf { Some(f) => f.as_encoded_bytes(), }; - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { // truncate until right after the file name // this is necessary for trimming the trailing slash @@ -1597,8 +1599,10 @@ impl PathBuf { // append the new extension self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true From 7443d039a5bd9724165e616e5e545e947d85c018 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 29 Apr 2025 20:11:34 +0530 Subject: [PATCH 14/20] Update stdarch --- library/core/Cargo.toml | 1 - library/coretests/benches/ascii.rs | 2 +- library/std/Cargo.toml | 1 - library/stdarch | 2 +- library/sysroot/Cargo.toml | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index fe61f552a49de..99e52d0ada0a6 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -31,7 +31,6 @@ level = "warn" check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', - 'cfg(stdarch_intel_sde)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/coretests/benches/ascii.rs b/library/coretests/benches/ascii.rs index 3fe45aa360bf0..64bdc7fed118f 100644 --- a/library/coretests/benches/ascii.rs +++ b/library/coretests/benches/ascii.rs @@ -354,7 +354,7 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ ]; const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; -const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; #[bench] fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 940b671c51461..d7bd28b5279d3 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -121,7 +121,6 @@ debug_typeid = ["core/debug_typeid"] # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std_detect/std_detect_env_override"] # Enable using raw-dylib for Windows imports. # This will eventually be the default. diff --git a/library/stdarch b/library/stdarch index 1245618ccf5b2..f1c1839c0deb9 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 1245618ccf5b2df7ab1ebb0279b9f3f726670161 +Subproject commit f1c1839c0deb985a9f98cbd6b38a6d43f2df6157 diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index ec6ae31507e05..c149d513c32b4 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -31,5 +31,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std/std_detect_env_override"] windows_raw_dylib = ["std/windows_raw_dylib"] From 175f71750f149643cff56f88b6f7e63c88843dea Mon Sep 17 00:00:00 2001 From: Artur Roos Date: Thu, 1 May 2025 22:09:07 +0300 Subject: [PATCH 15/20] Simplify docs for breaking out of a named code block --- library/std/src/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b0e55c787250d..71b68233f7881 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -91,7 +91,7 @@ mod as_keyword {} /// /// When associated with `loop`, a break expression may be used to return a value from that loop. /// This is only valid with `loop` and not with any other type of loop. -/// If no value is specified, `break;` returns `()`. +/// If no value is specified for `break;` it returns `()`. /// Every `break` within a loop must return the same type. /// /// ```rust @@ -110,7 +110,7 @@ mod as_keyword {} /// ``` /// /// It is also possible to exit from any *labelled* block returning the value early. -/// If no value specified `break;` returns `()`. +/// If no value is specified for `break;` it returns `()`. /// /// ```rust /// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; From b2bf951dd60a57b423ab0a3f6b544ff580a08cd1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 28 Mar 2025 16:44:39 +1100 Subject: [PATCH 16/20] Augment `impl-trait-missing-lifetime-gated.rs`. We have coverage for `Foo` and `Foo` but not for `Foo<>`. This commit adds it. Note that the output has bogus syntax: `impl Foo'a, >` --- .../impl-trait-missing-lifetime-gated.rs | 11 ++++ .../impl-trait-missing-lifetime-gated.stderr | 59 +++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index 443a7e3835e3e..f5c3da847c72f 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -49,6 +49,17 @@ mod alone_in_path { //~| ERROR missing lifetime specifier } +mod alone_in_path2 { + trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; } + + fn f(_: impl Foo<>) {} + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + + fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + //~| ERROR missing lifetime specifier +} + mod in_path { trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 24013c85c8758..e7dbb06987a91 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -108,7 +108,28 @@ LL + fn g(mut x: impl Foo) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41 + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:39 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn g(mut x: impl Foo<>) -> Option<&'static ()> { x.next() } + | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo<>) -> Option<&'a ()> { x.next() } + | ++++ ++ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Foo<>) -> Option<()> { x.next() } + | + +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:41 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -129,7 +150,7 @@ LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } | warning: elided lifetime has a name - --> $DIR/impl-trait-missing-lifetime-gated.rs:64:57 + --> $DIR/impl-trait-missing-lifetime-gated.rs:75:57 | LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` @@ -217,7 +238,35 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 + --> $DIR/impl-trait-missing-lifetime-gated.rs:55:21 + | +LL | fn f(_: impl Foo<>) {} + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL - fn f(_: impl Foo<>) {} +LL + fn f<'a>(_: impl Foo'a, >) {} + | + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:25 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } +LL + fn g<'a>(mut x: impl Foo'a, >) -> Option<&()> { x.next() } + | + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:66:22 | LL | fn f(_: impl Foo<()>) {} | ^ expected named lifetime parameter @@ -230,7 +279,7 @@ LL | fn f<'a>(_: impl Foo<'a, ()>) {} | ++++ +++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:26 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -242,7 +291,7 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 17 previous errors; 1 warning emitted Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. From 28deaa6e0e7993f963b3bb44bb235c7682ce0cf3 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 12 Apr 2025 06:18:53 -0700 Subject: [PATCH 17/20] Delegate to inner `vec::IntoIter` from `env::ArgsOs` Delegate from `std::env::ArgsOs` to the methods of the inner platform-specific iterators, when it would be more efficient than just using the default methods of its own impl. Most platforms use `vec::IntoIter` as the inner type, so prioritize delegating to the methods it provides. `std::env::Args` is implemented atop `std::env::ArgsOs` and performs UTF-8 validation with a panic for invalid data. This is a visible effect which users certainly rely on, so we can't skip any arguments. Any further iterator methods would skip some elements, so no change is needed for that type. Add `#[inline]` for any methods which simply wrap the inner iterator. --- library/std/src/env.rs | 73 ++++++++++++++++++++++++- library/std/src/lib.rs | 3 + library/std/src/sys/args/common.rs | 66 ++++++++++++++++++++-- library/std/src/sys/args/sgx.rs | 68 +++++++++++++++++++---- library/std/src/sys/args/unsupported.rs | 18 ++++-- 5 files changed, 207 insertions(+), 21 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 1593969e114aa..ce2dc79522076 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -12,9 +12,11 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::ops::Try; use crate::path::{Path, PathBuf}; use crate::sys::{env as env_imp, os as os_imp}; -use crate::{fmt, io, sys}; +use crate::{array, fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. /// @@ -872,19 +874,36 @@ impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; + fn next(&mut self) -> Option { self.inner.next().map(|s| s.into_string().unwrap()) } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + // Methods which skip args cannot simply delegate to the inner iterator, + // because `env::args` states that we will "panic during iteration if any + // argument to the process is not valid Unicode". + // + // This offers two possible interpretations: + // - a skipped argument is never encountered "during iteration" + // - even a skipped argument is encountered "during iteration" + // + // As a panic can be observed, we err towards validating even skipped + // arguments for now, though this is not explicitly promised by the API. } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for Args { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -914,19 +933,65 @@ impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.inner.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn count(self) -> usize { + self.inner.len() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.inner.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for ArgsOs { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -934,9 +999,15 @@ impl ExactSizeIterator for ArgsOs { #[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for ArgsOs { + #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_back_by(n) + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ba57ad9bae329..c011f9661ae7a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -301,6 +301,8 @@ #![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(let_chains)] #![feature(link_cfg)] @@ -321,6 +323,7 @@ #![feature(strict_provenance_lints)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] // tidy-alphabetical-end // diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index 43ac5e9592348..303b373ccf900 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -1,5 +1,7 @@ use crate::ffi::OsString; -use crate::{fmt, vec}; +use crate::num::NonZero; +use crate::ops::Try; +use crate::{array, fmt, vec}; pub struct Args { iter: vec::IntoIter, @@ -9,6 +11,7 @@ impl !Send for Args {} impl !Sync for Args {} impl Args { + #[inline] pub(super) fn new(args: Vec) -> Self { Args { iter: args.into_iter() } } @@ -22,22 +25,77 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.iter.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.iter.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { + #[inline] + fn count(self) -> usize { self.iter.len() } + + #[inline] + fn last(mut self) -> Option { + self.iter.next_back() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 2a4bc76aefb9e..f800500c22a8a 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,6 +1,8 @@ #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers use crate::ffi::OsString; +use crate::num::NonZero; +use crate::ops::Try; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::os_str::Buf; use crate::sys::pal::abi::usercalls::alloc; @@ -28,35 +30,81 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; - if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) } + let slice = args.map(|args| args.as_slice()).unwrap_or(&[]); + Args { iter: slice.iter() } } -pub struct Args(slice::Iter<'static, OsString>); +pub struct Args { + iter: slice::Iter<'static, OsString>, +} impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.as_slice().fmt(f) + self.iter.as_slice().fmt(f) } } impl Iterator for Args { type Item = OsString; + fn next(&mut self) -> Option { - self.0.next().cloned() + self.iter.next().cloned() } + + #[inline] fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() + self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.0.len() + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option { + self.iter.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.by_ref().cloned().try_fold(init, f) + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.cloned().fold(init, f) } } impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option { - self.0.next_back().cloned() + self.iter.next_back().cloned() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() } } diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index a2d75a6197633..ecffc6d26414b 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -15,22 +15,28 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { None } + + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(0)) } } -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { None } } + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + 0 + } +} From d42edee451b87ce3d7b9de82f43c142592e1e661 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 28 Apr 2025 19:24:45 +1000 Subject: [PATCH 18/20] Handle `Path<>` better in error messages. `Path<>` needs to be distinguished from `Path`. This commit does that, improving some error messages. --- compiler/rustc_ast_lowering/src/lib.rs | 10 +++---- compiler/rustc_ast_lowering/src/path.rs | 30 +++++++++++-------- compiler/rustc_hir/src/hir.rs | 29 ++++++++++++------ .../impl-trait-missing-lifetime-gated.stderr | 18 +++++------ 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e14b4d6723f4..1844cb2de6c45 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, - LifetimeSyntax, ParamName, TraitCandidate, + self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, + LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1081,7 +1081,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( lt, - LifetimeSource::Path { with_angle_brackets: true }, + LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full }, lt.ident.into(), )), ast::GenericArg::Type(ty) => { @@ -1773,13 +1773,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, id: NodeId, span: Span, - with_angle_brackets: bool, + angle_brackets: AngleBrackets, ) -> &'hir hir::Lifetime { self.new_named_lifetime( id, id, Ident::new(kw::UnderscoreLifetime, span), - LifetimeSource::Path { with_angle_brackets }, + LifetimeSource::Path { angle_brackets }, LifetimeSyntax::Hidden, ) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index fabe40a9d0413..5cda64ce7b4ba 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -432,27 +432,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { - // If there are no brackets, use the identifier span. + let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() { + // No brackets, e.g. `Path`: use an empty span just past the end of the identifier. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) - } else if generic_args.is_empty() { - // If there are brackets, but not generic arguments, then use the opening bracket - (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) + ( + segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), + hir::AngleBrackets::Missing, + ) } else { - // Else use an empty span right after the opening bracket. - (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) + // Brackets, e.g. `Path<>` or `Path`: use an empty span just after the `<`. + ( + generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), + if generic_args.is_empty() { + hir::AngleBrackets::Empty + } else { + hir::AngleBrackets::Full + }, + ) }; generic_args.args.insert_many( 0, (start..end).map(|id| { - let l = self.lower_lifetime_hidden_in_path( - id, - elided_lifetime_span, - with_angle_brackets, - ); + let l = + self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af587ee5bdcdd..58b776bdc6aea 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -35,18 +35,24 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum AngleBrackets { + /// E.g. `Path`. + Missing, + /// E.g. `Path<>`. + Empty, + /// E.g. `Path`. + Full, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum LifetimeSource { /// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type` Reference, - /// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>` - Path { - /// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`, - /// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>` - /// - false for `ContainsLifetime` - with_angle_brackets: bool, - }, + /// E.g. `ContainsLifetime`, `ContainsLifetime<>`, `ContainsLifetime<'_>`, + /// `ContainsLifetime<'a>` + Path { angle_brackets: AngleBrackets }, /// E.g. `impl Trait + '_`, `impl Trait + 'a` OutlivesBound, @@ -304,12 +310,17 @@ impl Lifetime { (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), // The user wrote `Path`, and omitted the `'_,`. - (Hidden, Path { with_angle_brackets: true }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Full }) => { (self.ident.span, format!("{new_lifetime}, ")) } + // The user wrote `Path<>`, and omitted the `'_`.. + (Hidden, Path { angle_brackets: AngleBrackets::Empty }) => { + (self.ident.span, format!("{new_lifetime}")) + } + // The user wrote `Path` and omitted the `<'_>`. - (Hidden, Path { with_angle_brackets: false }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Missing }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index e7dbb06987a91..92996ca846782 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -238,32 +238,30 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } | ++++ ++++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:55:21 + --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 | LL | fn f(_: impl Foo<>) {} - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date help: consider introducing a named lifetime parameter | -LL - fn f(_: impl Foo<>) {} -LL + fn f<'a>(_: impl Foo'a, >) {} - | +LL | fn f<'a>(_: impl Foo<'a>) {} + | ++++ ++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:25 + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 | LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } - | ^ expected named lifetime parameter + | ^ expected named lifetime parameter | = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date help: consider introducing a named lifetime parameter | -LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } -LL + fn g<'a>(mut x: impl Foo'a, >) -> Option<&()> { x.next() } - | +LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } + | ++++ ++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:66:22 From 3f842e51a6e97dad23f9717ae27db2960dde1c34 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Apr 2025 15:24:54 +1000 Subject: [PATCH 19/20] Improve coverage of HIR pretty printing. By taking the existing `expanded-exhaustive.rs` test and running it with both `Zunpretty=expanded` *and* `Zunpretty=hir`. Also rename some files, and split the asm parts out so they only run on x86-64. --- .../unpretty/exhaustive-asm.expanded.stdout | 33 + tests/ui/unpretty/exhaustive-asm.hir.stdout | 31 + tests/ui/unpretty/exhaustive-asm.rs | 31 + ...tive.stdout => exhaustive.expanded.stdout} | 87 +-- tests/ui/unpretty/exhaustive.hir.stderr | 172 +++++ tests/ui/unpretty/exhaustive.hir.stdout | 700 ++++++++++++++++++ .../{expanded-exhaustive.rs => exhaustive.rs} | 64 +- ...rpolation.rs => interpolation-expanded.rs} | 0 ...n.stdout => interpolation-expanded.stdout} | 0 9 files changed, 1014 insertions(+), 104 deletions(-) create mode 100644 tests/ui/unpretty/exhaustive-asm.expanded.stdout create mode 100644 tests/ui/unpretty/exhaustive-asm.hir.stdout create mode 100644 tests/ui/unpretty/exhaustive-asm.rs rename tests/ui/unpretty/{expanded-exhaustive.stdout => exhaustive.expanded.stdout} (96%) create mode 100644 tests/ui/unpretty/exhaustive.hir.stderr create mode 100644 tests/ui/unpretty/exhaustive.hir.stdout rename tests/ui/unpretty/{expanded-exhaustive.rs => exhaustive.rs} (90%) rename tests/ui/unpretty/{expanded-interpolation.rs => interpolation-expanded.rs} (100%) rename tests/ui/unpretty/{expanded-interpolation.stdout => interpolation-expanded.stdout} (100%) diff --git a/tests/ui/unpretty/exhaustive-asm.expanded.stdout b/tests/ui/unpretty/exhaustive-asm.expanded.stdout new file mode 100644 index 0000000000000..92829b0ab15bd --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.expanded.stdout @@ -0,0 +1,33 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + global_asm! (".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout new file mode 100644 index 0000000000000..5a642dff6f2e4 --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -0,0 +1,31 @@ +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm {/// ItemKind::GlobalAsm + global_asm! (".globl my_asm_func") } + } diff --git a/tests/ui/unpretty/exhaustive-asm.rs b/tests/ui/unpretty/exhaustive-asm.rs new file mode 100644 index 0000000000000..74a45447a20f1 --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.rs @@ -0,0 +1,31 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + core::arch::asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + core::arch::global_asm!(".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout similarity index 96% rename from tests/ui/unpretty/expanded-exhaustive.stdout rename to tests/ui/unpretty/exhaustive.expanded.stdout index c6ffbb0d316bb..9712ba58e627f 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -1,7 +1,13 @@ #![feature(prelude_import)] -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -211,7 +217,10 @@ mod expressions { } /// ExprKind::Await - fn expr_await() { let fut; fut.await; } + fn expr_await() { + let fut; + fut.await; + } /// ExprKind::TryBlock fn expr_try_block() { try {} try { return; } } @@ -242,7 +251,9 @@ mod expressions { } /// ExprKind::Underscore - fn expr_underscore() { _; } + fn expr_underscore() { + _; + } /// ExprKind::Path fn expr_path() { @@ -275,16 +286,8 @@ mod expressions { /// ExprKind::Ret fn expr_ret() { return; return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", - inout(reg) - x, - out(reg) - _); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -300,65 +303,12 @@ mod expressions { - - - - - - // ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // concat_idents is deprecated @@ -450,10 +400,7 @@ mod items { unsafe extern "C++" {} unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - global_asm! (".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { pub type Type<'a> where T: 'a = T; diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr new file mode 100644 index 0000000000000..58f7ff0f59812 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -0,0 +1,172 @@ +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:211:9 + | +LL | static || value; + | ^^^^^^^^^ + +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:212:9 + | +LL | static move || value; + | ^^^^^^^^^^^^^^ + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/exhaustive.rs:241:13 + | +LL | fn expr_await() { + | --------------- this is not `async` +LL | let fut; +LL | fut.await; + | ^^^^^ only allowed inside `async` functions and blocks + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/exhaustive.rs:290:9 + | +LL | _; + | ^ `_` not allowed here + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:300:9 + | +LL | x::(); + | ^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:301:9 + | +LL | x::(T, T) -> T; + | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + | +help: use angle brackets instead + | +LL - x::(T, T) -> T; +LL + x:: -> T; + | + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:302:9 + | +LL | crate::() -> ()::expressions::() -> ()::expr_path; + | ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:302:26 + | +LL | crate::() -> ()::expressions::() -> ()::expr_path; + | ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:305:9 + | +LL | core::()::marker::()::PhantomData; + | ^^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:305:19 + | +LL | core::()::marker::()::PhantomData; + | ^^^^^^^^^^ only `Fn` traits may use parentheses + +error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks + --> $DIR/exhaustive.rs:392:9 + | +LL | yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn expr_yield() { + | ++++++++++++ + +error[E0703]: invalid ABI: found `C++` + --> $DIR/exhaustive.rs:472:23 + | +LL | unsafe extern "C++" {} + | ^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error: `..` patterns are not allowed here + --> $DIR/exhaustive.rs:679:13 + | +LL | let ..; + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:794:16 + | +LL | let _: T() -> !; + | ^^^^^^^^ only `Fn` traits may use parentheses + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:809:16 + | +LL | let _: impl Send; + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:810:16 + | +LL | let _: impl Send + 'static; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:811:16 + | +LL | let _: impl 'static + Send; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:812:16 + | +LL | let _: impl ?Sized; + | ^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:813:16 + | +LL | let _: impl ~const Clone; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:814:16 + | +LL | let _: impl for<'a> Send; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0214, E0562, E0697, E0703, E0728. +For more information about an error, try `rustc --explain E0214`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout new file mode 100644 index 0000000000000..d2c379d436624 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -0,0 +1,700 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail +//@ edition:2024 + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. + +#![feature(auto_traits)]#![feature(box_patterns)]#![feature(builtin_syntax)]#![feature(concat_idents)]#![feature(const_trait_impl)]#![feature(decl_macro)]#![feature(deref_patterns)]#![feature(dyn_star)]#![feature(explicit_tail_calls)]#![feature(gen_blocks)]#![feature(more_qualified_paths)]#![feature(never_patterns)]#![feature(never_type)]#![feature(pattern_types)]#![feature(pattern_type_macro)]#![feature(prelude_import)]#![feature(specialization)]#![feature(trace_macros)]#![feature(trait_alias)]#![feature(try_blocks)]#![feature(yeet_expr)]#![allow(incomplete_features)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; + +#[prelude_import] +use self::prelude::*; + +mod prelude { + use std::prelude::rust_2024::*; + + type T = _; + + trait Trait { + const + CONST: + (); + } +} + +//! inner single-line doc comment +/*! + * inner multi-line doc comment + */ +#[doc = "inner doc attribute"]#[allow(dead_code, unused_variables)]#[no_std] +mod attributes {//! inner single-line doc comment + /*! + * inner multi-line doc comment + */ + #![doc = + "inner doc attribute"]#![allow(dead_code, unused_variables)]#![no_std] + + /// outer single-line doc comment + /** + * outer multi-line doc comment + */ + #[doc = + "outer doc attribute"]#[doc = "macro"]#[allow()]#[attr = Repr([ReprC])] + struct Struct; +} + +mod expressions { + /// ExprKind::Array + fn expr_array() { + []; + [true]; + [true]; + [true, true]; + ["long........................................................................"]; + ["long............................................................", + true]; + } + + /// ExprKind::ConstBlock + fn expr_const_block() { + const { }; + const { 1 }; + const + { + struct S; + }; + } + + /// ExprKind::Call + fn expr_call() { + let f; + f(); + f::(); + f::<1>(); + f::<'static, u8, 1>(); + f(true); + f(true); + ()(); + } + + /// ExprKind::MethodCall + fn expr_method_call() { + let x; + x.f(); + x.f::(); + x.collect::>(); + } + + /// ExprKind::Tup + fn expr_tup() { (); (true,); (true, false); (true, false); } + + /// ExprKind::Binary + fn expr_binary() { + let (a, b, c, d, x, y); + true || false; + true || false && false; + a < 1 && 2 < b && c > 3 && 4 > d; + a & b & !c; + a + b * c - d + -1 * -2 - -3; + x = !y; + } + + /// ExprKind::Unary + fn expr_unary() { let expr; *expr; !expr; -expr; } + + /// ExprKind::Lit + fn expr_lit() { 'x'; 1000i8; 1.00000000000000000000001; } + + /// ExprKind::Cast + fn expr_cast() { let expr; expr as T; expr as T; } + + /// ExprKind::Type + fn expr_type() { let expr; type_ascribe!(expr, T); } + + /// ExprKind::Let + fn expr_let() { + let b; + if let Some(a) = b { } + if let _ = true && false { } + if let _ = (true && false) { } + } + + /// ExprKind::If + fn expr_if() { + if true { } + if !true { } + if let true = true { } else { } + if true { } else if false { } + if true { } else if false { } else { } + if true { return; } else if false { 0 } else { 0 } + } + + /// ExprKind::While + fn expr_while() { + loop { if false { } else { break; } } + 'a: loop { if false { } else { break; } } + loop { if let true = true { } else { break; } } + } + + /// ExprKind::ForLoop + fn expr_for_loop() { + let x; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + }; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + 'a: + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + } + } + + /// ExprKind::Loop + fn expr_loop() { loop { } 'a: loop { } } + + /// ExprKind::Match + fn expr_match() { + let value; + match value { } + match value { ok => 1, } + match value { ok => 1, err => 0, } + } + + /// ExprKind::Closure + fn expr_closure() { + let value; + || { }; + |x| { }; + |x: u8| { }; + || (); + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || value; + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || -> u8 { value }; + 1 + (|| { }); + } + + /// ExprKind::Block + fn expr_block() { + { } + unsafe { } + 'a: { } + #[allow()] + { } + #[allow()] + { } + } + + /// ExprKind::Gen + fn expr_gen() { + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + || { }; + move || { }; + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + } + + /// ExprKind::Await + fn expr_await() { + let fut; + { + fut; + (/*ERROR*/) + }; + } + + /// ExprKind::TryBlock + fn expr_try_block() { + { #[lang = "from_output"](()) } + { return; #[lang = "from_output"](()) } + } + + /// ExprKind::Assign + fn expr_assign() { let expr; expr = true; } + + /// ExprKind::AssignOp + fn expr_assign_op() { let expr; expr += true; } + + /// ExprKind::Field + fn expr_field() { let expr; expr.field; expr.0; } + + /// ExprKind::Index + fn expr_index() { let expr; expr[true]; } + + /// ExprKind::Range + fn expr_range() { + let (lo, hi); + #[lang = "RangeFull"] { }; + #[lang = "RangeTo"] { end: hi }; + #[lang = "RangeFrom"] { start: lo }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "RangeToInclusive"] { end: hi }; + #[lang = "range_inclusive_new"](lo, hi); + #[lang = "range_inclusive_new"](-2, -1); + } + + /// ExprKind::Underscore + fn expr_underscore() { + (/*ERROR*/); + } + + /// ExprKind::Path + fn expr_path() { + let x; + crate::expressions::expr_path; + crate::expressions::expr_path::<'static>; + ::default; + ::default; + x; + x::; + crate::expressions::expr_path; + core::marker::PhantomData; + } + + /// ExprKind::AddrOf + fn expr_addr_of() { + let expr; + &expr; + &mut expr; + &raw const expr; + &raw mut expr; + } + + /// ExprKind::Break + fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } } + + /// ExprKind::Continue + fn expr_continue() { 'a: { continue; continue 'a; } } + + /// ExprKind::Ret + fn expr_ret() { return; return true; } + + + /// ExprKind::InlineAsm: see exhaustive-asm.rs + /// ExprKind::OffsetOf + fn expr_offset_of() { + + + + + + + + + + + + + + // ... + + + + + + // concat_idents is deprecated + + + + + { offset_of!(T, field) }; + } + /// ExprKind::MacCall + fn expr_mac_call() { "..."; "..."; "..."; } + /// ExprKind::Struct + fn expr_struct() { + struct Struct { + } + let (x, base); + Struct { }; + ::Owned { }; + Struct { .. }; + Struct { ..base }; + Struct { x }; + Struct { x, ..base }; + Struct { x: true }; + Struct { x: true, .. }; + Struct { x: true, ..base }; + Struct { 0: true, ..base }; + } + /// ExprKind::Repeat + fn expr_repeat() { [(); 0]; } + /// ExprKind::Paren + fn expr_paren() { let expr; expr; } + /// ExprKind::Try + fn expr_try() { + let expr; + match #[lang = "branch"](expr) { + #[lang = "Break"] { 0: residual } => + #[allow(unreachable_code)] + return #[lang = "from_residual"](residual), + #[lang = "Continue"] { 0: val } => #[allow(unreachable_code)] + val, + }; + } + /// ExprKind::Yield + fn expr_yield() { yield (); yield true; } + /// ExprKind::Yeet + fn expr_yeet() { + return #[lang = "from_yeet"](()); + return #[lang = "from_yeet"](0); + } + /// ExprKind::Become + fn expr_become() { become true; } + /// ExprKind::IncludedBytes + fn expr_include_bytes() { + b"data for include_bytes in ../expanded-exhaustive.rs\n"; + } + /// ExprKind::FormatArgs + fn expr_format_args() { + let expr; + format_arguments::new_const(&[]); + format_arguments::new_v1(&[""], + &[format_argument::new_display(&expr)]); + } +} +mod items { + /// ItemKind::ExternCrate + mod item_extern_crate {/// ItemKind::ExternCrate + extern crate core; + extern crate self as unpretty; + extern crate core as _; + } + /// ItemKind::Use + mod item_use {/// ItemKind::Use + use ::{}; + use crate::expressions; + use crate::items::item_use; + use core::*; + } + /// ItemKind::Static + mod item_static {/// ItemKind::Static + static A: () = { }; + static mut B: () = { }; + } + /// ItemKind::Const + mod item_const {/// ItemKind::Const + const A: () = { }; + trait TraitItems { + const + B: + (); + const + C: + () + = + { }; + } + } + /// ItemKind::Fn + mod item_fn {/// ItemKind::Fn + const unsafe extern "C" fn f() { } + async unsafe extern "C" fn g() + -> + /*impl Trait*/ |mut _task_context: ResumeTy| + { { let _t = { }; _t } } + fn h<'a, T>() where T: 'a { } + trait TraitItems { + unsafe extern "C" fn f(); + } + impl TraitItems for _ { + unsafe extern "C" fn f() { } + } + } + /// ItemKind::Mod + mod item_mod {/// ItemKind::Mod + } + /// ItemKind::ForeignMod + mod item_foreign_mod {/// ItemKind::ForeignMod + extern "Rust" { } + extern "C" { } + } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + mod item_ty_alias {/// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + type Type<'a> where T: 'a = T; + } + /// ItemKind::Enum + mod item_enum {/// ItemKind::Enum + enum Void { } + enum Empty { + Unit, + Tuple(), + Struct { + }, + } + enum Generic<'a, T> where T: 'a { + Tuple(T), + Struct { + t: T, + }, + } + } + /// ItemKind::Struct + mod item_struct {/// ItemKind::Struct + struct Unit; + struct Tuple(); + struct Newtype(Unit); + struct Struct { + } + struct Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Union + mod item_union {/// ItemKind::Union + union Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Trait + mod item_trait {/// ItemKind::Trait + auto unsafe trait Send { } + trait Trait<'a>: Sized where Self: 'a { } + } + /// ItemKind::TraitAlias + mod item_trait_alias {/// ItemKind::TraitAlias + trait Trait = Sized where for<'a> T: 'a; + } + /// ItemKind::Impl + mod item_impl {/// ItemKind::Impl + impl () { } + impl () { } + impl Default for () { } + impl const Default for () { } + } + /// ItemKind::MacCall + mod item_mac_call {/// ItemKind::MacCall + } + /// ItemKind::MacroDef + mod item_macro_def {/// ItemKind::MacroDef + macro_rules! mac { () => {...}; } + macro stringify { () => {} } + } + /// ItemKind::Delegation + /*! FIXME: todo */ + mod item_delegation {/// ItemKind::Delegation + /*! FIXME: todo */ + } + /// ItemKind::DelegationMac + /*! FIXME: todo */ + mod item_delegation_mac {/// ItemKind::DelegationMac + /*! FIXME: todo */ + } +} +mod patterns { + /// PatKind::Missing + fn pat_missing() { let _: for fn(u32, T, &'_ str); } + /// PatKind::Wild + fn pat_wild() { let _; } + /// PatKind::Ident + fn pat_ident() { + let x; + let ref x; + let mut x; + let ref mut x; + let ref mut x@_; + } + /// PatKind::Struct + fn pat_struct() { + let T {}; + let T:: {}; + let T::<'static> {}; + let T { x }; + let T { x: _x }; + let T { .. }; + let T { x, .. }; + let T { x: _x, .. }; + let T { 0: _x, .. }; + let ::Owned {}; + } + /// PatKind::TupleStruct + fn pat_tuple_struct() { + struct Tuple(); + let Tuple(); + let Tuple::(); + let Tuple::<'static>(); + let Tuple(x); + let Tuple(..); + let Tuple(x, ..); + } + /// PatKind::Or + fn pat_or() { let true | false; let true; let true | false; } + /// PatKind::Path + fn pat_path() { + let core::marker::PhantomData; + let core::marker::PhantomData::; + let core::marker::PhantomData::<'static>; + let ::CONST; + } + /// PatKind::Tuple + fn pat_tuple() { let (); let (true,); let (true, false); } + /// PatKind::Box + fn pat_box() { let box pat; } + /// PatKind::Deref + fn pat_deref() { let deref!(pat); } + /// PatKind::Ref + fn pat_ref() { let &pat; let &mut pat; } + /// PatKind::Expr + fn pat_expr() { let 1000i8; let -""; } + /// PatKind::Range + fn pat_range() { let ..1; let 0...; let 0..1; let 0...1; let -2...-1; } + /// PatKind::Slice + fn pat_slice() { let []; let [true]; let [true]; let [true, false]; } + /// PatKind::Rest + fn pat_rest() { let _; } + /// PatKind::Never + fn pat_never() { let !; let Some(!); } + /// PatKind::Paren + fn pat_paren() { let pat; } + /// PatKind::MacCall + fn pat_mac_call() { let ""; let ""; let ""; } +} +mod statements { + /// StmtKind::Let + fn stmt_let() { + let _; + let _ = true; + let _: T = true; + let _ = true else { return; }; + } + /// StmtKind::Item + fn stmt_item() { + struct Struct { + } + struct Unit; + } + /// StmtKind::Expr + fn stmt_expr() { () } + /// StmtKind::Semi + fn stmt_semi() { 1 + 1; } + /// StmtKind::Empty + fn stmt_empty() { } + /// StmtKind::MacCall + fn stmt_mac_call() { "..."; "..."; "..."; } +} +mod types { + /// TyKind::Slice + fn ty_slice() { let _: [T]; } + /// TyKind::Array + fn ty_array() { let _: [T; 0]; } + /// TyKind::Ptr + fn ty_ptr() { let _: *const T; let _: *mut T; } + /// TyKind::Ref + fn ty_ref() { + let _: &T; + let _: &mut T; + let _: &'static T; + let _: &'static mut [T]; + let _: &T>>>; + let _: &T>>>; + } + /// TyKind::BareFn + fn ty_bare_fn() { + let _: fn(); + let _: fn() -> (); + let _: fn(T); + let _: fn(t: T); + let _: fn(); + let _: for<'a> fn(); + } + /// TyKind::Never + fn ty_never() { let _: !; } + /// TyKind::Tup + fn ty_tup() { let _: (); let _: (T,); let _: (T, T); } + /// TyKind::Path + fn ty_path() { + let _: T; + let _: T<'static>; + let _: T; + let _: T; + let _: T; + let _: ::Owned; + } + /// TyKind::TraitObject + fn ty_trait_object() { + let _: dyn Send; + let _: dyn Send + 'static; + let _: dyn Send + 'static; + let _: dyn for<'a> Send; + let _: dyn* Send; + } + /// TyKind::ImplTrait + const fn ty_impl_trait() { + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + } + /// TyKind::Paren + fn ty_paren() { let _: T; } + /// TyKind::Typeof + /*! unused for now */ + fn ty_typeof() { } + /// TyKind::Infer + fn ty_infer() { let _: _; } + /// TyKind::ImplicitSelf + /*! there is no syntax for this */ + fn ty_implicit_self() { } + /// TyKind::MacCall + #[expect(deprecated)] + fn ty_mac_call() { let _: T; let _: T; let _: T; } + /// TyKind::CVarArgs + /*! FIXME: todo */ + fn ty_c_var_args() { } + /// TyKind::Pat + fn ty_pat() { let _: u32 is 1..=RangeMax; } +} +mod visibilities { + /// VisibilityKind::Public + mod visibility_public {/// VisibilityKind::Public + struct Pub; + } + /// VisibilityKind::Restricted + mod visibility_restricted {/// VisibilityKind::Restricted + struct PubCrate; + struct PubSelf; + struct PubSuper; + struct PubInCrate; + struct PubInSelf; + struct PubInSuper; + struct PubInCrateVisibilities; + struct PubInSelfSuper; + struct PubInSuperMod; + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/exhaustive.rs similarity index 90% rename from tests/ui/unpretty/expanded-exhaustive.rs rename to tests/ui/unpretty/exhaustive.rs index 5697f615b9791..60ad3564689d7 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -1,6 +1,12 @@ -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -202,8 +208,8 @@ mod expressions { move || value; async || value; async move || value; - static || value; - static move || value; + static || value; //[hir]~ ERROR closures cannot be static + static move || value; //[hir]~ ERROR closures cannot be static (static async || value); (static async move || value); || -> u8 { value }; @@ -232,7 +238,7 @@ mod expressions { /// ExprKind::Await fn expr_await() { let fut; - fut.await; + fut.await; //[hir]~ ERROR `await` is only allowed } /// ExprKind::TryBlock @@ -281,7 +287,7 @@ mod expressions { /// ExprKind::Underscore fn expr_underscore() { - _; + _; //[hir]~ ERROR in expressions, `_` can only } /// ExprKind::Path @@ -291,10 +297,14 @@ mod expressions { crate::expressions::expr_path::<'static>; ::default; ::default::<>; - x::(); - x::(T, T) -> T; + x::(); //[hir]~ ERROR parenthesized type parameters + x::(T, T) -> T; //[hir]~ ERROR parenthesized type parameters crate::() -> ()::expressions::() -> ()::expr_path; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters core::()::marker::()::PhantomData; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters } /// ExprKind::AddrOf @@ -330,18 +340,7 @@ mod expressions { return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - core::arch::asm!( - "mov {tmp}, {x}", - "shl {tmp}, 1", - "shl {x}, 2", - "add {x}, {tmp}", - x = inout(reg) x, - tmp = out(reg) _, - ); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -390,7 +389,7 @@ mod expressions { /// ExprKind::Yield fn expr_yield() { - yield; + yield; //[hir]~ ERROR `yield` can only be used yield true; } @@ -470,14 +469,11 @@ mod items { /// ItemKind::ForeignMod mod item_foreign_mod { - unsafe extern "C++" {} + unsafe extern "C++" {} //[hir]~ ERROR invalid ABI unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - core::arch::global_asm!(".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { @@ -680,7 +676,7 @@ mod patterns { /// PatKind::Rest fn pat_rest() { - let ..; + let ..; //[hir]~ ERROR `..` patterns are not allowed here } /// PatKind::Never @@ -795,7 +791,7 @@ mod types { let _: T<'static>; let _: T; let _: T::; - let _: T() -> !; + let _: T() -> !; //[hir]~ ERROR parenthesized type parameters let _: ::Owned; } @@ -810,12 +806,12 @@ mod types { /// TyKind::ImplTrait const fn ty_impl_trait() { - let _: impl Send; - let _: impl Send + 'static; - let _: impl 'static + Send; - let _: impl ?Sized; - let _: impl ~const Clone; - let _: impl for<'a> Send; + let _: impl Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl Send + 'static; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl 'static + Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ?Sized; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ~const Clone; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl for<'a> Send; //[hir]~ ERROR `impl Trait` is not allowed } /// TyKind::Paren diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/interpolation-expanded.rs similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.rs rename to tests/ui/unpretty/interpolation-expanded.rs diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/interpolation-expanded.stdout similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.stdout rename to tests/ui/unpretty/interpolation-expanded.stdout From 360012f41a7521f8a1bd488f015b5342e989aab8 Mon Sep 17 00:00:00 2001 From: Lynnesbian Date: Fri, 2 May 2025 13:22:05 +1000 Subject: [PATCH 20/20] Amend language regarding the never type --- library/std/src/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b8eb0fd104c3c..b6a9ba0129029 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2415,8 +2415,7 @@ mod while_keyword {} /// a return from the parent function; rather, they cause the `Future` returned by the block to /// return with that value. /// -/// For example, the following Rust function will return `5`, assigning the `!` value to `x`, which -/// goes unused: +/// For example, the following Rust function will return `5`, causing `x` to take the [`!` type][never type]: /// ```rust /// #[expect(unused_variables)] /// fn example() -> i32 { @@ -2455,6 +2454,7 @@ mod while_keyword {} /// [async book]: https://rust-lang.github.io/async-book/ /// [`return`]: ../std/keyword.return.html /// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [never type]: ../reference/types/never.html /// [`Result`]: result::Result /// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {}