From d545e84eae2b30536a17e746137647e1de256417 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 24 Jan 2025 01:04:14 -0800 Subject: [PATCH 001/163] update llvm workaround comment to link to rust tracking issue too --- crates/core_simd/src/simd/num/float.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 79954b937b397..6371276ae262b 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -263,7 +263,8 @@ macro_rules! impl_trait { unsafe { core::intrinsics::simd::simd_as(self) } } - // https://github.com/llvm/llvm-project/issues/94694 + // workaround for https://github.com/llvm/llvm-project/issues/94694 (fixed in LLVM 20) + // tracked in: https://github.com/rust-lang/rust/issues/135982 #[cfg(target_arch = "aarch64")] #[inline] fn cast(self) -> Self::Cast From 51c5700f15a23ac55c51e8e6a3f478a7fd77fcc6 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 28 Jan 2025 09:38:54 +0100 Subject: [PATCH 002/163] clarify BufRead::{fill_buf, consume} docs Fixes #85394 --- library/std/src/io/mod.rs | 41 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index cfd03b8e3d6d0..767e6e18cca8d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2250,24 +2250,18 @@ fn skip_until(r: &mut R, delim: u8) -> Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait BufRead: Read { - /// Returns the contents of the internal buffer, filling it with more data - /// from the inner reader if it is empty. + /// Returns the contents of the internal buffer, filling it with more data, via Read methods, if empty. /// - /// This function is a lower-level call. It needs to be paired with the - /// [`consume`] method to function properly. When calling this - /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, [`consume`] must - /// be called with the number of bytes that are consumed from this buffer to - /// ensure that the bytes are never returned twice. + /// This is a lower-level method and is meant to be used together with [`consume`], + /// which can be used to mark bytes that should not be returned by subsequent calls to `read`. /// /// [`consume`]: BufRead::consume /// - /// An empty buffer returned indicates that the stream has reached EOF. + /// Returns an empty buffer to indicate that the stream has reached EOF. /// /// # Errors /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. + /// Passes on I/O errors from Read. /// /// # Examples /// @@ -2285,7 +2279,7 @@ pub trait BufRead: Read { /// // work with buffer /// println!("{buffer:?}"); /// - /// // ensure the bytes we worked with aren't returned again later + /// // mark the bytes we worked with as read /// let length = buffer.len(); /// stdin.consume(length); /// # std::io::Result::Ok(()) @@ -2293,18 +2287,13 @@ pub trait BufRead: Read { #[stable(feature = "rust1", since = "1.0.0")] fn fill_buf(&mut self) -> Result<&[u8]>; - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. + /// Marks the given `amount` of additional bytes from the internal buffer as having been read. + /// Subsequent calls to `read` return bytes that have not yet been so marked. /// - /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf`] method to function properly. This function does - /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`fill_buf`], has been consumed and should - /// no longer be returned. As such, this function may do odd things if - /// [`fill_buf`] isn't called before calling it. + /// This is a lower-level method and is meant to be used together with [`fill_buf`], + /// which can be used to fill the internal buffer via Read methods. /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`fill_buf`]. + /// It is a logic error if `amount` exceeds the number of unread bytes in the internal buffer. /// /// # Examples /// @@ -2313,9 +2302,9 @@ pub trait BufRead: Read { /// /// [`fill_buf`]: BufRead::fill_buf #[stable(feature = "rust1", since = "1.0.0")] - fn consume(&mut self, amt: usize); + fn consume(&mut self, amount: usize); - /// Checks if the underlying `Read` has any data left to be read. + /// Checks if there is any data left to be `read`. /// /// This function may fill the buffer to check for data, /// so this functions returns `Result`, not `bool`. @@ -2324,6 +2313,10 @@ pub trait BufRead: Read { /// returned slice is empty (which means that there is no data left, /// since EOF is reached). /// + /// # Errors + /// + /// Passes on I/O errors from Read. + /// /// Examples /// /// ``` From 8156e062ee12f091e128db23f09d196cd028edc1 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 31 Jan 2025 17:29:45 +0100 Subject: [PATCH 003/163] doc all differences of ptr:copy(_nonoverlapping) with memcpy and memmove --- library/core/src/intrinsics/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c0d435f99c0ca..5683377774cd8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -4250,7 +4250,8 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons /// For regions of memory which might overlap, use [`copy`] instead. /// /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but -/// with the argument order swapped. +/// with the source and destination arguments swapped, +/// and `count` counting the number of `T`s instead of bytes. /// /// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the /// requirements of `T`. The initialization state is preserved exactly. @@ -4377,8 +4378,10 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// If the source and destination will *never* overlap, /// [`copy_nonoverlapping`] can be used instead. /// -/// `copy` is semantically equivalent to C's [`memmove`], but with the argument -/// order swapped. Copying takes place as if the bytes were copied from `src` +/// `copy` is semantically equivalent to C's [`memmove`], but +/// with the source and destination arguments swapped, +/// and `count` counting the number of `T`s instead of bytes. +/// Copying takes place as if the bytes were copied from `src` /// to a temporary array and then copied from the array to `dst`. /// /// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the From 49d2d5a1161720ccd5b76ac2afbdceb6ea7e2e6e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2025 15:02:41 +0100 Subject: [PATCH 004/163] Extract `unescape` from `rustc_lexer` into its own crate --- Cargo.lock | 7 +++++++ compiler/rustc_ast/Cargo.toml | 1 + compiler/rustc_ast/src/util/literal.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 1 - compiler/rustc_parse/Cargo.toml | 1 + compiler/rustc_parse/src/lexer/mod.rs | 6 +++--- .../rustc_parse/src/lexer/unescape_error_reporting.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse_format/Cargo.toml | 1 + compiler/rustc_parse_format/src/lib.rs | 11 ++++++----- library/literal-escaper/Cargo.toml | 10 ++++++++++ library/literal-escaper/README.md | 4 ++++ .../unescape.rs => library/literal-escaper/src/lib.rs | 0 .../unescape => library/literal-escaper/src}/tests.rs | 0 14 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 library/literal-escaper/Cargo.toml create mode 100644 library/literal-escaper/README.md rename compiler/rustc_lexer/src/unescape.rs => library/literal-escaper/src/lib.rs (100%) rename {compiler/rustc_lexer/src/unescape => library/literal-escaper/src}/tests.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index fc4c7c9888fa6..63441814d4a1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2151,6 +2151,10 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "literal-escaper" +version = "0.0.1" + [[package]] name = "lld-wrapper" version = "0.1.0" @@ -3366,6 +3370,7 @@ name = "rustc_ast" version = "0.0.0" dependencies = [ "bitflags", + "literal-escaper", "memchr", "rustc_ast_ir", "rustc_data_structures", @@ -4325,6 +4330,7 @@ name = "rustc_parse" version = "0.0.0" dependencies = [ "bitflags", + "literal-escaper", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -4347,6 +4353,7 @@ dependencies = [ name = "rustc_parse_format" version = "0.0.0" dependencies = [ + "literal-escaper", "rustc_index", "rustc_lexer", ] diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 34c612dac692b..176c2d6f8a791 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +literal-escaper = { path = "../../library/literal-escaper" } memchr = "2.7.4" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 6896ac723fa58..121331ece6d64 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -2,7 +2,7 @@ use std::{ascii, fmt, str}; -use rustc_lexer::unescape::{ +use literal_escaper::{ MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, }; use rustc_span::{Span, Symbol, kw, sym}; diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c63ab77decac9..334f451a39c71 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -27,7 +27,6 @@ // tidy-alphabetical-end mod cursor; -pub mod unescape; #[cfg(test)] mod tests; diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 2360914a0aba1..109e1f5c0931e 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +literal-escaper = { path = "../../library/literal-escaper" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 792e2cc26ef1c..cefaf13e31fbe 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,12 +1,12 @@ use std::ops::Range; +use literal_escaper::{self, EscapeError, Mode}; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; -use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ @@ -970,7 +970,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_unicode(src, mode, &mut |span, result| { + literal_escaper::unescape_unicode(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) @@ -986,7 +986,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { postfix_len: u32, ) -> (token::LitKind, Symbol) { self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape::unescape_mixed(src, mode, &mut |span, result| { + literal_escaper::unescape_mixed(src, mode, &mut |span, result| { callback(span, result.map(drop)) }) }) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 2e066f0179c3f..e8aa400e73d44 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,8 +3,8 @@ use std::iter::once; use std::ops::Range; +use literal_escaper::{EscapeError, Mode}; use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed}; -use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; use tracing::debug; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0e6c2177da54..0b745217bc8be 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -6,6 +6,7 @@ use core::ops::{Bound, ControlFlow}; use ast::mut_visit::{self, MutVisitor}; use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; +use literal_escaper::unescape_char; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; @@ -21,7 +22,6 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; -use rustc_lexer::unescape::unescape_char; use rustc_macros::Subdiagnostic; use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error}; use rustc_session::lint::BuiltinLintDiag; diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 707c4e318474a..51ea46f4c9b40 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +literal-escaper = { path = "../../library/literal-escaper" } rustc_index = { path = "../rustc_index", default-features = false } rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 3b985621b5772..7e89f9b079b62 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -19,7 +19,6 @@ pub use Alignment::*; pub use Count::*; pub use Position::*; -use rustc_lexer::unescape; // Note: copied from rustc_span /// Range inside of a `Span` used for diagnostics when we only have access to relative positions. @@ -1095,12 +1094,14 @@ fn find_width_map_from_snippet( fn unescape_string(string: &str) -> Option { let mut buf = String::new(); let mut ok = true; - unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| { - match unescaped_char { + literal_escaper::unescape_unicode( + string, + literal_escaper::Mode::Str, + &mut |_, unescaped_char| match unescaped_char { Ok(c) => buf.push(c), Err(_) => ok = false, - } - }); + }, + ); ok.then_some(buf) } diff --git a/library/literal-escaper/Cargo.toml b/library/literal-escaper/Cargo.toml new file mode 100644 index 0000000000000..708fcd3cacb69 --- /dev/null +++ b/library/literal-escaper/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "literal-escaper" +version = "0.0.0" +edition = "2021" + +[dependencies] +std = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-std' } + +[features] +rustc-dep-of-std = ["dep:std"] diff --git a/library/literal-escaper/README.md b/library/literal-escaper/README.md new file mode 100644 index 0000000000000..5384ac4556a13 --- /dev/null +++ b/library/literal-escaper/README.md @@ -0,0 +1,4 @@ +# literal-escaper + +This crate provides code to unescape string literals. It is used by `rustc_lexer` +and `proc-macro`. diff --git a/compiler/rustc_lexer/src/unescape.rs b/library/literal-escaper/src/lib.rs similarity index 100% rename from compiler/rustc_lexer/src/unescape.rs rename to library/literal-escaper/src/lib.rs diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/library/literal-escaper/src/tests.rs similarity index 100% rename from compiler/rustc_lexer/src/unescape/tests.rs rename to library/literal-escaper/src/tests.rs From b993f9c835a3ed2119d45597f74e3eaedbf806e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2025 15:45:18 +0100 Subject: [PATCH 005/163] Add `_value` methods to proc_macro lib --- Cargo.lock | 11 +++- library/Cargo.lock | 8 +++ library/proc_macro/Cargo.toml | 1 + library/proc_macro/src/lib.rs | 114 ++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 63441814d4a1f..06c1394295769 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2153,7 +2153,10 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "literal-escaper" -version = "0.0.1" +version = "0.0.0" +dependencies = [ + "rustc-std-workspace-std 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "lld-wrapper" @@ -3332,6 +3335,12 @@ version = "1.0.1" name = "rustc-std-workspace-std" version = "1.0.1" +[[package]] +name = "rustc-std-workspace-std" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba676a20abe46e5b0f1b0deae474aaaf31407e6c71147159890574599da04ef" + [[package]] name = "rustc_abi" version = "0.0.0" diff --git a/library/Cargo.lock b/library/Cargo.lock index 8b78908e6d730..f769fb2e1e1d3 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -158,6 +158,13 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "literal-escaper" +version = "0.0.0" +dependencies = [ + "rustc-std-workspace-std", +] + [[package]] name = "memchr" version = "2.7.4" @@ -220,6 +227,7 @@ name = "proc_macro" version = "0.0.0" dependencies = [ "core", + "literal-escaper", "std", ] diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index e54a50aa15c61..e5c90309f16d0 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] +literal-escaper = { path = "../literal-escaper", features = ["rustc-dep-of-std"] } std = { path = "../std" } # Workaround: when documenting this crate rustdoc will try to load crate named # `core` when resolving doc links. Without this line a different `core` will be diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 6611ce30a1b01..57dd47f106089 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -28,6 +28,7 @@ #![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(extend_one)] +#![feature(stmt_expr_attributes)] #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] @@ -50,11 +51,23 @@ use std::{error, fmt}; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +#[unstable(feature = "proc_macro_value", issue = "136652")] +pub use literal_escaper::EscapeError; +use literal_escaper::{MixedUnit, Mode, byte_from_char, unescape_mixed, unescape_unicode}; #[unstable(feature = "proc_macro_totokens", issue = "130977")] pub use to_tokens::ToTokens; use crate::escape::{EscapeOptions, escape_bytes}; +/// Errors returned when trying to retrieve a literal unescaped value. +#[unstable(feature = "proc_macro_value", issue = "136652")] +pub enum ConversionErrorKind { + /// The literal failed to be escaped, take a look at [`EscapeError`] for more information. + FailedToUnescape(EscapeError), + /// Trying to convert a literal with the wrong type. + InvalidLiteralKind, +} + /// Determines whether proc_macro has been made accessible to the currently /// running program. /// @@ -1450,6 +1463,107 @@ impl Literal { } }) } + + /// Returns the unescaped string value if the current literal is a string or a string literal. + #[unstable(feature = "proc_macro_value", issue = "136652")] + pub fn str_value(&self) -> Result { + self.0.symbol.with(|symbol| match self.0.kind { + bridge::LitKind::Str => { + if symbol.contains('\\') { + let mut buf = String::with_capacity(symbol.len()); + let mut error = None; + // Force-inlining here is aggressive but the closure is + // called on every char in the string, so it can be hot in + // programs with many long strings containing escapes. + unescape_unicode( + symbol, + Mode::Str, + &mut #[inline(always)] + |_, c| match c { + Ok(c) => buf.push(c), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }, + ); + if let Some(error) = error { Err(error) } else { Ok(buf) } + } else { + Ok(symbol.to_string()) + } + } + bridge::LitKind::StrRaw(_) => Ok(symbol.to_string()), + _ => Err(ConversionErrorKind::InvalidLiteralKind), + }) + } + + /// Returns the unescaped string value if the current literal is a c-string or a c-string + /// literal. + #[unstable(feature = "proc_macro_value", issue = "136652")] + pub fn cstr_value(&self) -> Result, ConversionErrorKind> { + self.0.symbol.with(|symbol| match self.0.kind { + bridge::LitKind::CStr => { + let mut error = None; + let mut buf = Vec::with_capacity(symbol.len()); + + unescape_mixed(symbol, Mode::CStr, &mut |_span, c| match c { + Ok(MixedUnit::Char(c)) => { + buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + } + Ok(MixedUnit::HighByte(b)) => buf.push(b), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }); + if let Some(error) = error { + Err(error) + } else { + buf.push(0); + Ok(buf) + } + } + bridge::LitKind::CStrRaw(_) => { + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc` after appending the terminating NUL + // char. + let mut buf = symbol.to_owned().into_bytes(); + buf.push(0); + Ok(buf) + } + _ => Err(ConversionErrorKind::InvalidLiteralKind), + }) + } + + /// Returns the unescaped string value if the current literal is a byte string or a byte string + /// literal. + #[unstable(feature = "proc_macro_value", issue = "136652")] + pub fn byte_str_value(&self) -> Result, ConversionErrorKind> { + self.0.symbol.with(|symbol| match self.0.kind { + bridge::LitKind::ByteStr => { + let mut buf = Vec::with_capacity(symbol.len()); + let mut error = None; + + unescape_unicode(symbol, Mode::ByteStr, &mut |_, c| match c { + Ok(c) => buf.push(byte_from_char(c)), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }); + if let Some(error) = error { Err(error) } else { Ok(buf) } + } + bridge::LitKind::ByteStrRaw(_) => { + // Raw strings have no escapes so we can convert the symbol + // directly to a `Lrc`. + Ok(symbol.to_owned().into_bytes()) + } + _ => Err(ConversionErrorKind::InvalidLiteralKind), + }) + } } /// Parse a single literal from its stringified representation. From 615a9cd10a0d99f12c8b07a9e9fbff52b08e2139 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2025 23:12:15 +0100 Subject: [PATCH 006/163] Ignore duplicated dep for `literal-escaper` --- src/bootstrap/src/core/metadata.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 983674d2c6835..e6b01b2e2d95a 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -63,6 +63,11 @@ pub fn build(build: &mut Build) { let relative_path = krate.local_path(build); build.crates.insert(name.clone(), krate); let existing_path = build.crate_paths.insert(relative_path, name); + // `literal-escaper` is both a dependency of `compiler/rustc_lexer` and of + // `library/proc-macro`, making it appear multiple times in the workspace. + if existing_path.as_deref() == Some("literal-escaper") { + continue; + } assert!( existing_path.is_none(), "multiple crates with the same path: {}", From 94f0f2b603bdd10fabc7e06e29d25f230d22a93f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Jan 2025 23:42:09 +0100 Subject: [PATCH 007/163] Reexport `literal-escaper` from `rustc_lexer` to allow rust-analyzer to compile --- Cargo.lock | 1 + compiler/rustc_lexer/Cargo.toml | 1 + compiler/rustc_lexer/src/lib.rs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 06c1394295769..e0bf24f1eda71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4074,6 +4074,7 @@ name = "rustc_lexer" version = "0.0.0" dependencies = [ "expect-test", + "literal-escaper", "memchr", "unicode-properties", "unicode-xid", diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 4b3492fdeda25..5789cd0195883 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -16,6 +16,7 @@ Rust lexer used by rustc. No stability guarantees are provided. [dependencies] memchr = "2.7.4" unicode-xid = "0.2.0" +literal-escaper = { path = "../../library/literal-escaper" } [dependencies.unicode-properties] version = "0.1.0" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 334f451a39c71..587ef89566a7e 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -31,6 +31,9 @@ mod cursor; #[cfg(test)] mod tests; +// FIXME: This is needed for rust-analyzer. Remove this dependency once rust-analyzer uses +// `literal-escaper`. +pub use literal_escaper as unescape; use unicode_properties::UnicodeEmoji; pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; From e256a21734dbd88bed0ec6934e5d6b2ab2754927 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 1 Feb 2025 00:07:21 +0100 Subject: [PATCH 008/163] Add `literal-escaper` and `rustc-std-workspace-std` to the allowed rustc deps list --- src/tools/tidy/src/deps.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index faa0db27b2b05..5d871f0ab26f1 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -320,6 +320,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "libloading", "linux-raw-sys", "litemap", + "literal-escaper", "lock_api", "log", "matchers", @@ -366,6 +367,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-rayon", "rustc-rayon-core", "rustc-stable-hash", + "rustc-std-workspace-std", "rustc_apfloat", "rustc_version", "rustix", From d40ed632b6909f4ebf0b3cbda98615b9c2acd65b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Feb 2025 23:09:24 +0100 Subject: [PATCH 009/163] Fix bootstrap `build_all` test --- src/bootstrap/src/core/builder/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 74e1ed5c63763..d72e185f51a74 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -647,7 +647,7 @@ mod dist { let mut builder = Builder::new(&build); builder.run_step_descriptions( &Builder::get_step_descriptions(Kind::Build), - &["compiler/rustc".into(), "library".into()], + &["compiler/rustc".into(), "std".into()], ); assert_eq!( From 3c33cbe7789bf25611842b261f7fa07d592a672e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Feb 2025 20:55:54 +0100 Subject: [PATCH 010/163] Add ui test for ensuring that users cannot use `literal-escaper` crate for the time being --- tests/ui/feature-gates/literal-escaper.rs | 3 +++ tests/ui/feature-gates/literal-escaper.stderr | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/feature-gates/literal-escaper.rs create mode 100644 tests/ui/feature-gates/literal-escaper.stderr diff --git a/tests/ui/feature-gates/literal-escaper.rs b/tests/ui/feature-gates/literal-escaper.rs new file mode 100644 index 0000000000000..7c145fca7dec2 --- /dev/null +++ b/tests/ui/feature-gates/literal-escaper.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +extern crate literal_escaper; //~ ERROR diff --git a/tests/ui/feature-gates/literal-escaper.stderr b/tests/ui/feature-gates/literal-escaper.stderr new file mode 100644 index 0000000000000..edddb6504f575 --- /dev/null +++ b/tests/ui/feature-gates/literal-escaper.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? + --> $DIR/literal-escaper.rs:3:1 + | +LL | extern crate literal_escaper; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #27812 for more information + = help: add `#![feature(rustc_private)]` 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 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 2b5f6f05b552026673c272411ed5db3f1cccd479 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Feb 2025 15:17:46 -0800 Subject: [PATCH 011/163] Migrate core_simd to Rust 2024 --- crates/core_simd/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core_simd/Cargo.toml b/crates/core_simd/Cargo.toml index a7a6d43b11d3c..537ce459c07cd 100644 --- a/crates/core_simd/Cargo.toml +++ b/crates/core_simd/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "core_simd" version = "0.1.0" -edition = "2021" +edition = "2024" homepage = "https://github.com/rust-lang/portable-simd" repository = "https://github.com/rust-lang/portable-simd" keywords = ["core", "simd", "intrinsics"] From 007e0f18982519e0e7a521240c7e67e7b9e3e7a0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Feb 2025 16:49:46 -0800 Subject: [PATCH 012/163] Apply style_edition 2024 --- crates/core_simd/src/ops.rs | 2 +- crates/core_simd/src/simd/cmp/eq.rs | 2 +- crates/core_simd/src/simd/cmp/ord.rs | 2 +- crates/core_simd/src/simd/num/float.rs | 2 +- crates/core_simd/src/simd/num/int.rs | 4 ++-- crates/core_simd/src/simd/num/uint.rs | 2 +- crates/core_simd/src/simd/prelude.rs | 3 ++- crates/core_simd/src/simd/ptr/const_ptr.rs | 2 +- crates/core_simd/src/simd/ptr/mut_ptr.rs | 2 +- crates/core_simd/src/to_bytes.rs | 2 +- crates/core_simd/src/vector.rs | 2 +- crates/core_simd/tests/pointers.rs | 2 +- 12 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/core_simd/src/ops.rs b/crates/core_simd/src/ops.rs index d3bd14a340278..be3bacb76d57a 100644 --- a/crates/core_simd/src/ops.rs +++ b/crates/core_simd/src/ops.rs @@ -1,4 +1,4 @@ -use crate::simd::{cmp::SimdPartialEq, LaneCount, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount, cmp::SimdPartialEq}; use core::ops::{Add, Mul}; use core::ops::{BitAnd, BitOr, BitXor}; use core::ops::{Div, Rem, Sub}; diff --git a/crates/core_simd/src/simd/cmp/eq.rs b/crates/core_simd/src/simd/cmp/eq.rs index 93989ce91b89d..2312ba401fa78 100644 --- a/crates/core_simd/src/simd/cmp/eq.rs +++ b/crates/core_simd/src/simd/cmp/eq.rs @@ -1,6 +1,6 @@ use crate::simd::{ - ptr::{SimdConstPtr, SimdMutPtr}, LaneCount, Mask, Simd, SimdElement, SupportedLaneCount, + ptr::{SimdConstPtr, SimdMutPtr}, }; /// Parallel `PartialEq`. diff --git a/crates/core_simd/src/simd/cmp/ord.rs b/crates/core_simd/src/simd/cmp/ord.rs index 899f00a831641..e813e7613032c 100644 --- a/crates/core_simd/src/simd/cmp/ord.rs +++ b/crates/core_simd/src/simd/cmp/ord.rs @@ -1,7 +1,7 @@ use crate::simd::{ + LaneCount, Mask, Simd, SupportedLaneCount, cmp::SimdPartialEq, ptr::{SimdConstPtr, SimdMutPtr}, - LaneCount, Mask, Simd, SupportedLaneCount, }; /// Parallel `PartialOrd`. diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 79954b937b397..46b94ad9f1caa 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -1,7 +1,7 @@ use super::sealed::Sealed; use crate::simd::{ - cmp::{SimdPartialEq, SimdPartialOrd}, LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount, + cmp::{SimdPartialEq, SimdPartialOrd}, }; /// Operations on SIMD vectors of floats. diff --git a/crates/core_simd/src/simd/num/int.rs b/crates/core_simd/src/simd/num/int.rs index 3a51235ff954e..d25050c3e4b47 100644 --- a/crates/core_simd/src/simd/num/int.rs +++ b/crates/core_simd/src/simd/num/int.rs @@ -1,7 +1,7 @@ use super::sealed::Sealed; use crate::simd::{ - cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement, - SupportedLaneCount, + LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd, + cmp::SimdPartialOrd, num::SimdUint, }; /// Operations on SIMD vectors of signed integers. diff --git a/crates/core_simd/src/simd/num/uint.rs b/crates/core_simd/src/simd/num/uint.rs index 1ab2d8c7b7316..45d978068b664 100644 --- a/crates/core_simd/src/simd/num/uint.rs +++ b/crates/core_simd/src/simd/num/uint.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount}; +use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd}; /// Operations on SIMD vectors of unsigned integers. pub trait SimdUint: Copy + Sealed { diff --git a/crates/core_simd/src/simd/prelude.rs b/crates/core_simd/src/simd/prelude.rs index 4b7c744c01326..e5d7a2aeb73df 100644 --- a/crates/core_simd/src/simd/prelude.rs +++ b/crates/core_simd/src/simd/prelude.rs @@ -7,10 +7,11 @@ #[doc(no_inline)] pub use super::{ + Mask, Simd, cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd}, num::{SimdFloat, SimdInt, SimdUint}, ptr::{SimdConstPtr, SimdMutPtr}, - simd_swizzle, Mask, Simd, + simd_swizzle, }; #[rustfmt::skip] diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index 3f5fb1f2c1bcf..34d46216710ca 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount}; +use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index c909cca1fb208..bf5d160c09ea0 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,5 +1,5 @@ use super::sealed::Sealed; -use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount}; +use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount, cmp::SimdPartialEq, num::SimdUint}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { diff --git a/crates/core_simd/src/to_bytes.rs b/crates/core_simd/src/to_bytes.rs index 4833ea9e11362..fee2cc06c5b09 100644 --- a/crates/core_simd/src/to_bytes.rs +++ b/crates/core_simd/src/to_bytes.rs @@ -1,6 +1,6 @@ use crate::simd::{ - num::{SimdFloat, SimdInt, SimdUint}, LaneCount, Simd, SimdElement, SupportedLaneCount, + num::{SimdFloat, SimdInt, SimdUint}, }; mod sealed { diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 9c4dd36c24fe8..498715887e1d6 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -1,8 +1,8 @@ use crate::simd::{ + LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle, cmp::SimdPartialOrd, num::SimdUint, ptr::{SimdConstPtr, SimdMutPtr}, - LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle, }; /// A SIMD vector with the shape of `[T; N]` but the operations of `T`. diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs index d7db4e82b3ca2..6e74c2d18b1ed 100644 --- a/crates/core_simd/tests/pointers.rs +++ b/crates/core_simd/tests/pointers.rs @@ -1,8 +1,8 @@ #![feature(portable_simd)] use core_simd::simd::{ - ptr::{SimdConstPtr, SimdMutPtr}, Simd, + ptr::{SimdConstPtr, SimdMutPtr}, }; macro_rules! common_tests { From 7b5e847ae5b8d2da27455ffd3fe55cc2e2dccf6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2025 22:15:26 +0100 Subject: [PATCH 013/163] exit: document interaction with C --- library/std/src/env.rs | 2 +- library/std/src/process.rs | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 4a071b4e1faec..c0415eafb0510 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -330,7 +330,7 @@ impl Error for VarError { /// /// Discussion of this unsafety on Unix may be found in: /// -/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) +/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// /// To pass an environment variable to a child process, you can instead use [`Command::env`]. diff --git a/library/std/src/process.rs b/library/std/src/process.rs index bdd4844b6511a..2ae93d84ba4b6 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2003,9 +2003,9 @@ impl ExitCode { /// /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function /// terminates the process immediately, so no destructors on the current stack or any other - /// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply - /// return this ExitCode from the `main` function, as demonstrated in the [type - /// documentation](#examples). + /// thread's stack will be run. Also see those docs for some important notes on interop with C + /// code. If a clean shutdown is needed, it is recommended to simply return this ExitCode from + /// the `main` function, as demonstrated in the [type documentation](#examples). /// /// # Differences from `process::exit()` /// @@ -2297,6 +2297,34 @@ impl Child { /// considered undesirable. Note that returning from `main` also calls `exit`, so making `exit` an /// unsafe operation is not an option.) /// +/// ## Safe interop with C code +/// +/// This function is safe to call as long as `exit` is only ever invoked from Rust. However, on some +/// platforms this function is implemented by calling the C function [`exit`][C-exit]. As of C23, +/// the C standard does not permit multiple threads to call `exit` concurrently. Rust mitigates this +/// with a lock, but if C code calls `exit`, that can still cause undefined behavior. Note that +/// returning from `main` is equivalent to calling `exit`. +/// +/// Therefore, it is undefined behavior to have two concurrent threads perform the following +/// without synchronization: +/// - One thread calls Rust's `exit` function or returns from Rust's `main` function +/// - Another thread calls the C function `exit` or `quick_exit`, or returns from C's `main` function +/// +/// Note that if a binary contains multiple copies of the Rust runtime (e.g., when combining +/// multiple `cdylib` or `staticlib`), they each have their own separate lock, so from the +/// perspective of code running in one of the Rust runtimes, the "outside" Rust code is basically C +/// code, and concurrent `exit` again causes undefined behavior. +/// +/// Individual C implementations might provide more guarantees than the standard and permit concurrent +/// calls to `exit`; consult the documentation of your C implementation for details. +/// +/// For some of the on-going discussion to make `exit` thread-safe in C, see: +/// - [Rust issue #126600](https://github.com/rust-lang/rust/issues/126600) +/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=1845) +/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=31997) +/// +/// [C-exit]: https://en.cppreference.com/w/c/program/exit +/// /// ## Platform-specific behavior /// /// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit` From 6324b398735961c4636fd41d5044a196063d5efa Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Wed, 12 Feb 2025 10:24:57 +0800 Subject: [PATCH 014/163] promote ohos targets to tier to with host tools --- Cargo.lock | 21 +++++++++++++++---- compiler/rustc_codegen_llvm/Cargo.toml | 3 ++- compiler/rustc_data_structures/Cargo.toml | 3 ++- compiler/rustc_llvm/build.rs | 3 ++- compiler/rustc_query_impl/Cargo.toml | 4 ++-- src/bootstrap/src/core/build_steps/llvm.rs | 4 ++++ .../docker/host-x86_64/dist-ohos/Dockerfile | 13 +++++++++++- src/ci/docker/scripts/ohos-openssl.sh | 7 +++++++ src/ci/docker/scripts/ohos-sdk.sh | 6 +++--- src/doc/rustc/src/platform-support.md | 6 +++--- 10 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 src/ci/docker/scripts/ohos-openssl.sh diff --git a/Cargo.lock b/Cargo.lock index 72f2d4f6cd390..ea5d9bffefbfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2178,6 +2178,20 @@ dependencies = [ "smallvec", ] +[[package]] +name = "measureme-mirror" +version = "12.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe110855993552cfa51a5018e8cdf2acf7f948c46136322017a9a8484ffc5ea8" +dependencies = [ + "log", + "memmap2", + "parking_lot", + "perf-event-open-sys", + "rustc-hash 1.1.0", + "smallvec", +] + [[package]] name = "memchr" version = "2.7.4" @@ -3365,7 +3379,7 @@ dependencies = [ "gimli 0.30.0", "itertools", "libc", - "measureme", + "measureme-mirror", "object 0.36.7", "rustc-demangle", "rustc_abi", @@ -3483,7 +3497,7 @@ dependencies = [ "indexmap", "jobserver", "libc", - "measureme", + "measureme-mirror", "memmap2", "parking_lot", "portable-atomic", @@ -4249,8 +4263,7 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ - "measureme", - "rustc_attr_data_structures", + "measureme-mirror", "rustc_data_structures", "rustc_errors", "rustc_hashes", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index d3ce7c5a1130f..1122883914d83 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,7 +14,8 @@ bitflags = "2.4.1" gimli = "0.30" itertools = "0.12" libc = "0.2" -measureme = "11" +# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) +measureme = { package = "measureme-mirror", version = "12.0.1" } object = { version = "0.36.3", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index bdf5494f2107b..6629f2a751653 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -12,7 +12,8 @@ elsa = "1.11.0" ena = "0.14.3" indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } -measureme = "11" +# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) +measureme = { package = "measureme-mirror", version = "12.0.1" } rustc-hash = "2.0.0" rustc-rayon = { version = "0.5.1", features = ["indexmap"] } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 3d1f3b2cd4dd4..6692ea735401a 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -241,7 +241,7 @@ fn main() { println!("cargo:rustc-link-lib=kstat"); } - if (target.starts_with("arm") && !target.contains("freebsd")) + if (target.starts_with("arm") && !target.contains("freebsd")) && !target.contains("ohos") || target.starts_with("mips-") || target.starts_with("mipsel-") || target.starts_with("powerpc-") @@ -371,6 +371,7 @@ fn main() { || target.contains("freebsd") || target.contains("windows-gnullvm") || target.contains("aix") + || target.contains("ohos") { "c++" } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index c85156e059e5a..14a7391f10890 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -measureme = "11" -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) +measureme = { package = "measureme-mirror", version = "12.0.1" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 40d701f22c137..5919e989b3413 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -471,6 +471,10 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if target.starts_with("x86_64") && target.contains("ohos") { + cfg.define("LLVM_TOOL_LLVM_RTDYLD_BUILD", "OFF"); + } + let mut enabled_llvm_projects = Vec::new(); if helpers::forcing_clang_based_tests() { diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile index bbbf0b3adf2a2..23c0c8b49d2b3 100644 --- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile @@ -22,6 +22,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/ohos-sdk.sh /scripts/ RUN sh /scripts/ohos-sdk.sh +COPY scripts/ohos-openssl.sh /scripts/ +RUN sh /scripts/ohos-openssl.sh + COPY scripts/ohos/aarch64-unknown-linux-ohos-clang.sh /usr/local/bin/ COPY scripts/ohos/aarch64-unknown-linux-ohos-clang++.sh /usr/local/bin/ COPY scripts/ohos/armv7-unknown-linux-ohos-clang.sh /usr/local/bin/ @@ -30,6 +33,14 @@ COPY scripts/ohos/x86_64-unknown-linux-ohos-clang.sh /usr/local/bin/ COPY scripts/ohos/x86_64-unknown-linux-ohos-clang++.sh /usr/local/bin/ # env +ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/arm64-v8a +ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/armeabi-v7a +ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/x86_64 + +ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 +ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 +ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 + ENV TARGETS=aarch64-unknown-linux-ohos ENV TARGETS=$TARGETS,armv7-unknown-linux-ohos ENV TARGETS=$TARGETS,x86_64-unknown-linux-ohos @@ -51,7 +62,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ --disable-docs -ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS +ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/scripts/ohos-openssl.sh b/src/ci/docker/scripts/ohos-openssl.sh new file mode 100644 index 0000000000000..713ab6131e31a --- /dev/null +++ b/src/ci/docker/scripts/ohos-openssl.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -ex + +URL=https://github.com/ohos-rs/ohos-openssl/archive/refs/tags/0.1.0.tar.gz + +mkdir -p /opt/ohos-openssl +curl -fL $URL | tar xz -C /opt/ohos-openssl --strip-components=1 diff --git a/src/ci/docker/scripts/ohos-sdk.sh b/src/ci/docker/scripts/ohos-sdk.sh index 321be2b8697b0..0b62e49f7ca20 100755 --- a/src/ci/docker/scripts/ohos-sdk.sh +++ b/src/ci/docker/scripts/ohos-sdk.sh @@ -1,9 +1,9 @@ #!/bin/sh set -ex -URL=https://repo.huaweicloud.com/openharmony/os/4.0-Release/ohos-sdk-windows_linux-public.tar.gz +URL=https://repo.huaweicloud.com/openharmony/os/5.0.0-Release/ohos-sdk-windows_linux-public.tar.gz -curl $URL | tar xz -C /tmp ohos-sdk/linux/native-linux-x64-4.0.10.13-Release.zip +curl $URL | tar xz -C /tmp linux/native-linux-x64-5.0.0.71-Release.zip mkdir /opt/ohos-sdk cd /opt/ohos-sdk -unzip -qq /tmp/ohos-sdk/linux/native-linux-x64-4.0.10.13-Release.zip +unzip -qq /tmp/linux/native-linux-x64-5.0.0.71-Release.zip diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c4e5c1aac2f5d..a98c6f8d86111 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -89,9 +89,11 @@ target | notes -------|------- `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 +[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) `armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) +[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) @@ -104,6 +106,7 @@ target | notes [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 +[`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 ## Tier 2 without Host Tools @@ -142,7 +145,6 @@ target | std | notes [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ARM64 MinGW (Windows 10+), LLVM ABI [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia -[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | ARM64 OpenHarmony `aarch64-unknown-none` | * | Bare ARM64, hardfloat `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI @@ -158,7 +160,6 @@ target | std | notes `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat -[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat @@ -205,7 +206,6 @@ target | std | notes [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) -[`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat [`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI From 7279acf2025a5affd51862d126624ed0f49f701b Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Sat, 15 Feb 2025 09:19:02 +0800 Subject: [PATCH 015/163] use measureme-12.0.1 --- Cargo.lock | 12 ++++++------ compiler/rustc_codegen_llvm/Cargo.toml | 3 +-- compiler/rustc_data_structures/Cargo.toml | 3 +-- compiler/rustc_query_impl/Cargo.toml | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea5d9bffefbfb..d4ca5ce5d59dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2179,10 +2179,10 @@ dependencies = [ ] [[package]] -name = "measureme-mirror" +name = "measureme" version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe110855993552cfa51a5018e8cdf2acf7f948c46136322017a9a8484ffc5ea8" +checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395" dependencies = [ "log", "memmap2", @@ -2275,7 +2275,7 @@ dependencies = [ "libc", "libffi", "libloading", - "measureme", + "measureme 11.0.1", "rand 0.9.0", "regex", "rustc_version", @@ -3379,7 +3379,7 @@ dependencies = [ "gimli 0.30.0", "itertools", "libc", - "measureme-mirror", + "measureme 12.0.1", "object 0.36.7", "rustc-demangle", "rustc_abi", @@ -3497,7 +3497,7 @@ dependencies = [ "indexmap", "jobserver", "libc", - "measureme-mirror", + "measureme 12.0.1", "memmap2", "parking_lot", "portable-atomic", @@ -4263,7 +4263,7 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ - "measureme-mirror", + "measureme 12.0.1", "rustc_data_structures", "rustc_errors", "rustc_hashes", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 1122883914d83..ec1fd4b641a27 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,8 +14,7 @@ bitflags = "2.4.1" gimli = "0.30" itertools = "0.12" libc = "0.2" -# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) -measureme = { package = "measureme-mirror", version = "12.0.1" } +measureme = "12.0.1" object = { version = "0.36.3", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 6629f2a751653..df3bee6ee9cc8 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -12,8 +12,7 @@ elsa = "1.11.0" ena = "0.14.3" indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } -# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) -measureme = { package = "measureme-mirror", version = "12.0.1" } +measureme = "12.0.1" rustc-hash = "2.0.0" rustc-rayon = { version = "0.5.1", features = ["indexmap"] } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 14a7391f10890..b6773fb460fd4 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -5,8 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -# FIXME: waiting for the new version of measureme. (https://github.com/rust-lang/measureme/pull/240) -measureme = { package = "measureme-mirror", version = "12.0.1" } +measureme = "12.0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } From 6efacfb7a59ebde2620398861713fae136060a04 Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Mon, 24 Feb 2025 11:42:07 +0800 Subject: [PATCH 016/163] add fix for full tools and sanitizer --- Cargo.lock | 20 +++++++++---------- src/bootstrap/src/core/build_steps/llvm.rs | 13 ++++++++++++ .../docker/host-x86_64/dist-ohos/Dockerfile | 5 ++++- .../rustc/src/platform-support/openharmony.md | 13 +++++++++++- src/gcc | 2 +- src/llvm-project | 2 +- src/tools/cargo | 2 +- src/tools/enzyme | 2 +- 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4ca5ce5d59dc..05a2534c85737 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,22 +1997,22 @@ dependencies = [ ] [[package]] -name = "libffi" -version = "3.2.0" +name = "libffi-sys2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +checksum = "47aedd9774ffb3dcab5c96f593cb5a0caf421a5e38b16bab3b8cdef5facb6ea2" dependencies = [ - "libc", - "libffi-sys", + "cc", ] [[package]] -name = "libffi-sys" -version = "2.3.0" +name = "libffi2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +checksum = "c88a3402cad8ff58216ec6d07e5ecfa9e15fc36613c0a832db541e4e1a718a7b" dependencies = [ - "cc", + "libc", + "libffi-sys2", ] [[package]] @@ -2273,7 +2273,7 @@ dependencies = [ "directories", "getrandom 0.3.1", "libc", - "libffi", + "libffi2", "libloading", "measureme 11.0.1", "rand 0.9.0", diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 5919e989b3413..6a392b6bd7c1e 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -814,6 +814,10 @@ fn configure_cmake( cflags.push(s); } + if target.contains("ohos") { + cflags.push(" -D_LINUX_SYSINFO_H"); + } + if builder.config.llvm_clang_cl.is_some() { cflags.push(format!(" --target={target}")); } @@ -834,6 +838,11 @@ fn configure_cmake( cxxflags.push(" "); cxxflags.push(s); } + + if target.contains("ohos") { + cxxflags.push(" -D_LINUX_SYSINFO_H"); + } + if builder.config.llvm_clang_cl.is_some() { cxxflags.push(format!(" --target={target}")); } @@ -1220,6 +1229,10 @@ impl Step for Sanitizers { cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); cfg.define("LLVM_CONFIG_PATH", &llvm_config); + if self.target.contains("ohos") { + cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"); + } + // On Darwin targets the sanitizer runtimes are build as universal binaries. // Unfortunately sccache currently lacks support to build them successfully. // Disable compiler launcher on Darwin targets to avoid potential issues. diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile index 23c0c8b49d2b3..2c514fa0d4ddd 100644 --- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile @@ -60,7 +60,10 @@ ENV \ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ - --disable-docs + --disable-docs \ + --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ + --enable-extended \ + --enable-sanitizers ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md index 1632f44aeecc0..5988c468a8ba8 100644 --- a/src/doc/rustc/src/platform-support/openharmony.md +++ b/src/doc/rustc/src/platform-support/openharmony.md @@ -1,6 +1,6 @@ # `*-unknown-linux-ohos` -**Tier: 2** +**Tier: 2(with Host Tools)** * aarch64-unknown-linux-ohos * armv7-unknown-linux-ohos @@ -18,6 +18,17 @@ system. - Amanieu d'Antras ([@Amanieu](https://github.com/Amanieu)) - Lu Binglun ([@lubinglun](https://github.com/lubinglun)) +## Requirements + +All the ohos targets of Tier 2 with host tools support all extended rust tools. +(exclude `miri`, the support of `miri` will be added soon) + +### Host toolchain + +The targets require a reasonably up-to-date OpenHarmony SDK on the host. + +The targets support `cargo`, which require [ohos-openssl](https://github.com/ohos-rs/ohos-openssl). + ## Setup The OpenHarmony SDK doesn't currently support Rust compilation directly, so diff --git a/src/gcc b/src/gcc index 48664a6cab29d..fd3498bff0b93 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac +Subproject commit fd3498bff0b939dda91d56960acc33d55f2f9cdf diff --git a/src/llvm-project b/src/llvm-project index 1c3bb96fdb6db..92e80685d0d5d 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 1c3bb96fdb6db7b8e8f24edb016099c223fdd27e +Subproject commit 92e80685d0d5dcea3ccf321995c43b72338639c6 diff --git a/src/tools/cargo b/src/tools/cargo index 2622e844bc1e2..ce948f4616e3d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2622e844bc1e2e6123e54e94e4706f7b6195ce3d +Subproject commit ce948f4616e3d4277e30c75c8bb01e094910df39 diff --git a/src/tools/enzyme b/src/tools/enzyme index a35f4f773118c..5004a8f6f5d84 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit a35f4f773118ccfbd8d05102eb12a34097b1ee55 +Subproject commit 5004a8f6f5d8468b64fae457afb7d96e1784c783 From 4dab55bcaa3f1a60f11b3ff36159c199bc210616 Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Tue, 4 Mar 2025 17:38:06 +0800 Subject: [PATCH 017/163] Revert "add fix for full tools and sanitizer" This reverts commit 6efacfb7a59ebde2620398861713fae136060a04. --- Cargo.lock | 20 +++++++++---------- src/bootstrap/src/core/build_steps/llvm.rs | 13 ------------ .../docker/host-x86_64/dist-ohos/Dockerfile | 5 +---- .../rustc/src/platform-support/openharmony.md | 13 +----------- src/gcc | 2 +- src/llvm-project | 2 +- src/tools/cargo | 2 +- src/tools/enzyme | 2 +- 8 files changed, 16 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05a2534c85737..d4ca5ce5d59dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,22 +1997,22 @@ dependencies = [ ] [[package]] -name = "libffi-sys2" -version = "2.4.0" +name = "libffi" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aedd9774ffb3dcab5c96f593cb5a0caf421a5e38b16bab3b8cdef5facb6ea2" +checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" dependencies = [ - "cc", + "libc", + "libffi-sys", ] [[package]] -name = "libffi2" -version = "3.3.0" +name = "libffi-sys" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c88a3402cad8ff58216ec6d07e5ecfa9e15fc36613c0a832db541e4e1a718a7b" +checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" dependencies = [ - "libc", - "libffi-sys2", + "cc", ] [[package]] @@ -2273,7 +2273,7 @@ dependencies = [ "directories", "getrandom 0.3.1", "libc", - "libffi2", + "libffi", "libloading", "measureme 11.0.1", "rand 0.9.0", diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 6a392b6bd7c1e..5919e989b3413 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -814,10 +814,6 @@ fn configure_cmake( cflags.push(s); } - if target.contains("ohos") { - cflags.push(" -D_LINUX_SYSINFO_H"); - } - if builder.config.llvm_clang_cl.is_some() { cflags.push(format!(" --target={target}")); } @@ -838,11 +834,6 @@ fn configure_cmake( cxxflags.push(" "); cxxflags.push(s); } - - if target.contains("ohos") { - cxxflags.push(" -D_LINUX_SYSINFO_H"); - } - if builder.config.llvm_clang_cl.is_some() { cxxflags.push(format!(" --target={target}")); } @@ -1229,10 +1220,6 @@ impl Step for Sanitizers { cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); cfg.define("LLVM_CONFIG_PATH", &llvm_config); - if self.target.contains("ohos") { - cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"); - } - // On Darwin targets the sanitizer runtimes are build as universal binaries. // Unfortunately sccache currently lacks support to build them successfully. // Disable compiler launcher on Darwin targets to avoid potential issues. diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile index 2c514fa0d4ddd..23c0c8b49d2b3 100644 --- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile @@ -60,10 +60,7 @@ ENV \ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ - --disable-docs \ - --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ - --enable-extended \ - --enable-sanitizers + --disable-docs ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md index 5988c468a8ba8..1632f44aeecc0 100644 --- a/src/doc/rustc/src/platform-support/openharmony.md +++ b/src/doc/rustc/src/platform-support/openharmony.md @@ -1,6 +1,6 @@ # `*-unknown-linux-ohos` -**Tier: 2(with Host Tools)** +**Tier: 2** * aarch64-unknown-linux-ohos * armv7-unknown-linux-ohos @@ -18,17 +18,6 @@ system. - Amanieu d'Antras ([@Amanieu](https://github.com/Amanieu)) - Lu Binglun ([@lubinglun](https://github.com/lubinglun)) -## Requirements - -All the ohos targets of Tier 2 with host tools support all extended rust tools. -(exclude `miri`, the support of `miri` will be added soon) - -### Host toolchain - -The targets require a reasonably up-to-date OpenHarmony SDK on the host. - -The targets support `cargo`, which require [ohos-openssl](https://github.com/ohos-rs/ohos-openssl). - ## Setup The OpenHarmony SDK doesn't currently support Rust compilation directly, so diff --git a/src/gcc b/src/gcc index fd3498bff0b93..48664a6cab29d 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit fd3498bff0b939dda91d56960acc33d55f2f9cdf +Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac diff --git a/src/llvm-project b/src/llvm-project index 92e80685d0d5d..1c3bb96fdb6db 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 92e80685d0d5dcea3ccf321995c43b72338639c6 +Subproject commit 1c3bb96fdb6db7b8e8f24edb016099c223fdd27e diff --git a/src/tools/cargo b/src/tools/cargo index ce948f4616e3d..2622e844bc1e2 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ce948f4616e3d4277e30c75c8bb01e094910df39 +Subproject commit 2622e844bc1e2e6123e54e94e4706f7b6195ce3d diff --git a/src/tools/enzyme b/src/tools/enzyme index 5004a8f6f5d84..a35f4f773118c 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit 5004a8f6f5d8468b64fae457afb7d96e1784c783 +Subproject commit a35f4f773118ccfbd8d05102eb12a34097b1ee55 From 3eb04fd590527a103a70027a9da5ed9b20b76238 Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Tue, 4 Mar 2025 17:55:06 +0800 Subject: [PATCH 018/163] add support for extend rust tools and sanitizer --- src/bootstrap/src/core/build_steps/llvm.rs | 11 ++++++++++- src/ci/docker/host-x86_64/dist-ohos/Dockerfile | 5 ++++- src/doc/rustc/src/platform-support/openharmony.md | 13 ++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 5919e989b3413..3a32487a17cf4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -813,7 +813,9 @@ fn configure_cmake( cflags.push(" "); cflags.push(s); } - + if target.contains("ohos") { + cflags.push(" -D_LINUX_SYSINFO_H"); + } if builder.config.llvm_clang_cl.is_some() { cflags.push(format!(" --target={target}")); } @@ -834,6 +836,9 @@ fn configure_cmake( cxxflags.push(" "); cxxflags.push(s); } + if target.contains("ohos") { + cxxflags.push(" -D_LINUX_SYSINFO_H"); + } if builder.config.llvm_clang_cl.is_some() { cxxflags.push(format!(" --target={target}")); } @@ -1220,6 +1225,10 @@ impl Step for Sanitizers { cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); cfg.define("LLVM_CONFIG_PATH", &llvm_config); + if self.target.contains("ohos") { + cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"); + } + // On Darwin targets the sanitizer runtimes are build as universal binaries. // Unfortunately sccache currently lacks support to build them successfully. // Disable compiler launcher on Darwin targets to avoid potential issues. diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile index 23c0c8b49d2b3..2c514fa0d4ddd 100644 --- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos/Dockerfile @@ -60,7 +60,10 @@ ENV \ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ - --disable-docs + --disable-docs \ + --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ + --enable-extended \ + --enable-sanitizers ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md index 1632f44aeecc0..a2107b48a8671 100644 --- a/src/doc/rustc/src/platform-support/openharmony.md +++ b/src/doc/rustc/src/platform-support/openharmony.md @@ -1,6 +1,6 @@ # `*-unknown-linux-ohos` -**Tier: 2** +**Tier: 2 (with Host Tools)** * aarch64-unknown-linux-ohos * armv7-unknown-linux-ohos @@ -18,6 +18,17 @@ system. - Amanieu d'Antras ([@Amanieu](https://github.com/Amanieu)) - Lu Binglun ([@lubinglun](https://github.com/lubinglun)) +## Requirements + +All the ohos targets of Tier 2 with host tools support all extended rust tools. +(exclude `miri`, the support of `miri` will be added soon) + +### Host toolchain + +The targets require a reasonably up-to-date OpenHarmony SDK on the host. + +The targets support `cargo`, which require [ohos-openssl](https://github.com/ohos-rs/ohos-openssl). + ## Setup The OpenHarmony SDK doesn't currently support Rust compilation directly, so From f3312609f7a9db95047196387fdd8c69edaa898e Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Tue, 4 Mar 2025 20:30:57 +0800 Subject: [PATCH 019/163] add note for miri --- src/doc/rustc/src/platform-support/openharmony.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md index a2107b48a8671..e772a3d09f3d3 100644 --- a/src/doc/rustc/src/platform-support/openharmony.md +++ b/src/doc/rustc/src/platform-support/openharmony.md @@ -29,6 +29,9 @@ The targets require a reasonably up-to-date OpenHarmony SDK on the host. The targets support `cargo`, which require [ohos-openssl](https://github.com/ohos-rs/ohos-openssl). +`miri` isn't supported yet, since its dependencies (`libffi` and `tikv-jemalloc-sys`) don't support +compiling for the OHOS targets. + ## Setup The OpenHarmony SDK doesn't currently support Rust compilation directly, so From 23adb46b4733a5e5962419dbd5876b7d06d51f7a Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Wed, 5 Mar 2025 18:23:34 +0800 Subject: [PATCH 020/163] disable link libstdc++ statically --- src/ci/run.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index b874f71832d73..205eb2438430c 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -113,7 +113,11 @@ export RUST_RELEASE_CHANNEL=$(releaseChannel) RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" + if [[ "$CI_JOB_NAME" == *ohos* ]]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-static-stdcpp" + else + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" + fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" if [ "$DEPLOY_ALT" != "" ] && isLinux; then From 1be80d48fa0f3fdea8dec7f05426dd619dfdf411 Mon Sep 17 00:00:00 2001 From: moxian Date: Wed, 5 Mar 2025 17:43:24 -0800 Subject: [PATCH 021/163] Leave a breadcrumb towards bootstrap config documentation --- src/bootstrap/src/core/build_steps/setup.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f25dfaab0f115..ae6544227a621 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -216,8 +216,9 @@ fn setup_config_toml(path: &Path, profile: Profile, config: &Config) { let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id; let settings = format!( - "# Includes one of the default files in {PROFILE_DIR}\n\ - profile = \"{profile}\"\n\ + "# See bootstrap.example.toml for documentation of available options\n\ + #\n\ + profile = \"{profile}\" # Includes one of the default files in {PROFILE_DIR}\n\ change-id = {latest_change_id}\n" ); From 4cd350f61639d66095a9c5c87e6ff574ad1f7a00 Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Thu, 6 Mar 2025 16:03:35 +0800 Subject: [PATCH 022/163] remove zip file in /tmp to save some space and use large runner --- src/ci/docker/scripts/ohos-sdk.sh | 1 + src/ci/github-actions/jobs.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/ohos-sdk.sh b/src/ci/docker/scripts/ohos-sdk.sh index 0b62e49f7ca20..47d630ca76bc9 100755 --- a/src/ci/docker/scripts/ohos-sdk.sh +++ b/src/ci/docker/scripts/ohos-sdk.sh @@ -7,3 +7,4 @@ curl $URL | tar xz -C /tmp linux/native-linux-x64-5.0.0.71-Release.zip mkdir /opt/ohos-sdk cd /opt/ohos-sdk unzip -qq /tmp/linux/native-linux-x64-5.0.0.71-Release.zip +rm /tmp/linux/native-linux-x64-5.0.0.71-Release.zip diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1504e5c60ce7e..45ec4433c42e7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -176,7 +176,7 @@ auto: <<: *job-linux-4c - name: dist-ohos - <<: *job-linux-4c + <<: *job-linux-4c-largedisk - name: dist-powerpc-linux <<: *job-linux-4c From c86f0a134cf975f354e0fe14f868ccb58276bdbf Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Tue, 4 Mar 2025 20:28:38 -0800 Subject: [PATCH 023/163] Use size_of from the prelude instead of imported Use `std::mem::{size_of, size_of_val, align_of, align_of_val}` from the prelude instead of importing or qualifying them. These functions were added to all preludes in Rust 1.80. --- beginners-guide.md | 4 ++-- crates/core_simd/src/masks/full_masks.rs | 2 +- crates/core_simd/src/simd/num/float.rs | 4 ++-- crates/core_simd/src/simd/ptr/const_ptr.rs | 2 +- crates/core_simd/src/simd/ptr/mut_ptr.rs | 2 +- crates/core_simd/src/vector.rs | 2 +- crates/core_simd/tests/layout.rs | 4 ++-- crates/core_simd/tests/round.rs | 2 +- crates/test_helpers/src/subnormals.rs | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/beginners-guide.md b/beginners-guide.md index 17ade06ae80f9..dc08d847ced50 100644 --- a/beginners-guide.md +++ b/beginners-guide.md @@ -80,12 +80,12 @@ Most of the portable SIMD API is designed to allow the user to gloss over the de Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equivalent to `[i32; 4]` and so can be bitcast to it, e.g. using [`mem::transmute`], though the API usually offers a safe cast you can use instead. -However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`]. +However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`align_of`]. When working with slices, data correctly aligned for SIMD can be acquired using the [`as_simd`] and [`as_simd_mut`] methods of the slice primitive. [`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html -[`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html +[`align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html [`as_simd`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd [`as_simd_mut`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd_mut diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs index 2d01946b5747c..ae55cf1f8fa87 100644 --- a/crates/core_simd/src/masks/full_masks.rs +++ b/crates/core_simd/src/masks/full_masks.rs @@ -81,7 +81,7 @@ macro_rules! impl_reverse_bits { #[inline(always)] fn reverse_bits(self, n: usize) -> Self { let rev = <$int>::reverse_bits(self); - let bitsize = core::mem::size_of::<$int>() * 8; + let bitsize = size_of::<$int>() * 8; if n < bitsize { // Shift things back to the right rev >> (bitsize - n) diff --git a/crates/core_simd/src/simd/num/float.rs b/crates/core_simd/src/simd/num/float.rs index 46b94ad9f1caa..6d36b9ac68cc6 100644 --- a/crates/core_simd/src/simd/num/float.rs +++ b/crates/core_simd/src/simd/num/float.rs @@ -302,14 +302,14 @@ macro_rules! impl_trait { #[inline] fn to_bits(self) -> Simd<$bits_ty, N> { - assert_eq!(core::mem::size_of::(), core::mem::size_of::()); + assert_eq!(size_of::(), size_of::()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&self) } } #[inline] fn from_bits(bits: Simd<$bits_ty, N>) -> Self { - assert_eq!(core::mem::size_of::(), core::mem::size_of::()); + assert_eq!(size_of::(), size_of::()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&bits) } } diff --git a/crates/core_simd/src/simd/ptr/const_ptr.rs b/crates/core_simd/src/simd/ptr/const_ptr.rs index 34d46216710ca..36452e7ae920d 100644 --- a/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -109,7 +109,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/crates/core_simd/src/simd/ptr/mut_ptr.rs b/crates/core_simd/src/simd/ptr/mut_ptr.rs index bf5d160c09ea0..c644f390c20a5 100644 --- a/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -106,7 +106,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 498715887e1d6..d76a6cd52bfc5 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -83,7 +83,7 @@ use crate::simd::{ /// converting `[T]` to `[Simd]`, and allows soundly operating on an aligned SIMD body, /// but it may cost more time when handling the scalar head and tail. /// If these are not enough, it is most ideal to design data structures to be already aligned -/// to `mem::align_of::>()` before using `unsafe` Rust to read or write. +/// to `align_of::>()` before using `unsafe` Rust to read or write. /// Other ways to compensate for these facts, like materializing `Simd` to or from an array first, /// are handled by safe methods like [`Simd::from_array`] and [`Simd::from_slice`]. /// diff --git a/crates/core_simd/tests/layout.rs b/crates/core_simd/tests/layout.rs index 24114c2d261e7..3b4666249b0d7 100644 --- a/crates/core_simd/tests/layout.rs +++ b/crates/core_simd/tests/layout.rs @@ -7,8 +7,8 @@ macro_rules! layout_tests { test_helpers::test_lanes! { fn no_padding() { assert_eq!( - core::mem::size_of::>(), - core::mem::size_of::<[$ty; LANES]>(), + size_of::>(), + size_of::<[$ty; LANES]>(), ); } } diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 847766ec41ed2..4c1ac3c36f894 100644 --- a/crates/core_simd/tests/round.rs +++ b/crates/core_simd/tests/round.rs @@ -58,7 +58,7 @@ macro_rules! float_rounding_test { // all of the mantissa digits set to 1, pushed up to the MSB. const ALL_MANTISSA_BITS: IntScalar = ((1 << ::MANTISSA_DIGITS) - 1); const MAX_REPRESENTABLE_VALUE: Scalar = - (ALL_MANTISSA_BITS << (core::mem::size_of::() * 8 - ::MANTISSA_DIGITS as usize - 1)) as Scalar; + (ALL_MANTISSA_BITS << (size_of::() * 8 - ::MANTISSA_DIGITS as usize - 1)) as Scalar; let mut runner = test_helpers::make_runner(); runner.run( diff --git a/crates/test_helpers/src/subnormals.rs b/crates/test_helpers/src/subnormals.rs index ec0f1fb24b936..b5f19ba47b819 100644 --- a/crates/test_helpers/src/subnormals.rs +++ b/crates/test_helpers/src/subnormals.rs @@ -12,7 +12,7 @@ macro_rules! impl_float { $( impl FlushSubnormals for $ty { fn flush(self) -> Self { - let is_f32 = core::mem::size_of::() == 4; + let is_f32 = size_of::() == 4; let ppc_flush = is_f32 && cfg!(all( any(target_arch = "powerpc", all(target_arch = "powerpc64", target_endian = "big")), target_feature = "altivec", From 61f70003c2122313faf77185b6e5ec4bc2ba3bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Mon, 3 Mar 2025 12:54:26 +0100 Subject: [PATCH 024/163] Add helper methods checking for "#[non_exhaustive] that's active" A check for `#[non_exhaustive]` is often done in combination with checking whether the type is local to the crate, in a variety of ways. Create a helper method and standardize on it as the way to check for this. --- compiler/rustc_hir_typeck/src/cast.rs | 3 +-- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 11 ++--------- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_lint/src/types.rs | 12 ++++-------- compiler/rustc_lint/src/types/improper_ctypes.rs | 14 +++----------- compiler/rustc_middle/src/ty/adt.rs | 11 +++++++++++ compiler/rustc_middle/src/ty/inhabitedness/mod.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 13 ++++++++++++- .../src/builder/matches/match_pair.rs | 3 +-- compiler/rustc_mir_build/src/errors.rs | 6 +++--- compiler/rustc_pattern_analysis/src/rustc.rs | 4 +--- src/tools/clippy/clippy_lints/src/default.rs | 2 +- .../clippy/clippy_lints/src/needless_update.rs | 5 +++-- .../clippy_lints/src/unneeded_struct_pattern.rs | 2 +- 15 files changed, 46 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 70b49fea34f1c..e2e366c82c0ae 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -42,7 +42,6 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_type_ir::elaborate; @@ -789,7 +788,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { _ => return Err(CastError::NonScalar), }; if let ty::Adt(adt_def, _) = *self.expr_ty.kind() - && adt_def.did().krate != LOCAL_CRATE + && !adt_def.did().is_local() && adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { return Err(CastError::ForeignNonExhaustiveAdt); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2a89a03e0aa49..f771c938f5ddd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1966,7 +1966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prohibit struct expressions when non-exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); - if !adt.did().is_local() && variant.is_field_list_non_exhaustive() { + if variant.field_list_has_applicable_non_exhaustive() { self.dcx() .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c0617119d67c7..f16d258e982f6 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -20,7 +20,7 @@ use rustc_middle::hir::place::ProjectionKind; pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{ - self, AdtKind, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, + self, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Span}; @@ -1834,14 +1834,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // to assume that more cases will be added to the variant in the future. This mean // that we should handle non-exhaustive SingleVariant the same way we would handle // a MultiVariant. - // If the variant is not local it must be defined in another crate. - let is_non_exhaustive = match def.adt_kind() { - AdtKind::Struct | AdtKind::Union => { - def.non_enum_variant().is_field_list_non_exhaustive() - } - AdtKind::Enum => def.is_variant_list_non_exhaustive(), - }; - def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive) + def.variants().len() > 1 || def.variant_list_has_applicable_non_exhaustive() } else { false } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 19ae3e3899c93..f493ae6a8f82e 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Require `..` if struct has non_exhaustive attribute. - let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local(); + let non_exhaustive = variant.field_list_has_applicable_non_exhaustive(); if non_exhaustive && !has_rest_pat { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fcadbfc3c4a7e..31098bf443ac9 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1193,9 +1193,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - let is_non_exhaustive = - def.non_enum_variant().is_field_list_non_exhaustive(); - if is_non_exhaustive && !def.did().is_local() { + if def.non_enum_variant().field_list_has_applicable_non_exhaustive() { return FfiUnsafe { ty, reason: if def.is_struct() { @@ -1248,14 +1246,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - use improper_ctypes::{ - check_non_exhaustive_variant, non_local_and_non_exhaustive, - }; + use improper_ctypes::check_non_exhaustive_variant; - let non_local_def = non_local_and_non_exhaustive(def); + let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); // Check the contained variants. let ret = def.variants().iter().try_for_each(|variant| { - check_non_exhaustive_variant(non_local_def, variant) + check_non_exhaustive_variant(non_exhaustive, variant) .map_break(|reason| FfiUnsafe { ty, reason, help: None })?; match self.check_variant_for_ffi(acc, ty, def, variant, args) { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 1030101c545da..13afa540afcf6 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -15,13 +15,13 @@ use crate::fluent_generated as fluent; /// so we don't need the lint to account for it. /// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }. pub(crate) fn check_non_exhaustive_variant( - non_local_def: bool, + non_exhaustive_variant_list: bool, variant: &ty::VariantDef, ) -> ControlFlow { // non_exhaustive suggests it is possible that someone might break ABI // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 // so warn on complex enums being used outside their crate - if non_local_def { + if non_exhaustive_variant_list { // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195 // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }` // but exempt enums with unit ctors like C's (e.g. from rust-bindgen) @@ -30,8 +30,7 @@ pub(crate) fn check_non_exhaustive_variant( } } - let non_exhaustive_variant_fields = variant.is_field_list_non_exhaustive(); - if non_exhaustive_variant_fields && !variant.def_id.is_local() { + if variant.field_list_has_applicable_non_exhaustive() { return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant); } @@ -42,10 +41,3 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool { // CtorKind::Const means a "unit" ctor !matches!(variant.ctor_kind(), Some(CtorKind::Const)) } - -// non_exhaustive suggests it is possible that someone might break ABI -// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344 -// so warn on complex enums being used outside their crate -pub(crate) fn non_local_and_non_exhaustive(def: ty::AdtDef<'_>) -> bool { - def.is_variant_list_non_exhaustive() && !def.did().is_local() -} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 3585f28b4a550..fc48f68804988 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -329,11 +329,22 @@ impl<'tcx> AdtDef<'tcx> { } /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`. + /// + /// Note that this function will return `true` even if the ADT has been + /// defined in the crate currently being compiled. If that's not what you + /// want, see [`Self::variant_list_has_applicable_non_exhaustive`]. #[inline] pub fn is_variant_list_non_exhaustive(self) -> bool { self.flags().contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) } + /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]` + /// and has been defined in another crate. + #[inline] + pub fn variant_list_has_applicable_non_exhaustive(self) -> bool { + self.is_variant_list_non_exhaustive() && !self.did().is_local() + } + /// Returns the kind of the ADT. #[inline] pub fn adt_kind(self) -> AdtKind { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 4a5f6d80f24c4..855e5043e84a2 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -107,7 +107,7 @@ impl<'tcx> Ty<'tcx> { // For now, unions are always considered inhabited Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, // Non-exhaustive ADTs from other crates are always considered inhabited - Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { + Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => { InhabitedPredicate::True } Never => InhabitedPredicate::False, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 527509af05fc7..7b8f74e8a397f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1206,12 +1206,23 @@ impl VariantDef { } } - /// Is this field list non-exhaustive? + /// Returns `true` if the field list of this variant is `#[non_exhaustive]`. + /// + /// Note that this function will return `true` even if the type has been + /// defined in the crate currently being compiled. If that's not what you + /// want, see [`Self::field_list_has_applicable_non_exhaustive`]. #[inline] pub fn is_field_list_non_exhaustive(&self) -> bool { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } + /// Returns `true` if the field list of this variant is `#[non_exhaustive]` + /// and the type has been defined in another crate. + #[inline] + pub fn field_list_has_applicable_non_exhaustive(&self) -> bool { + self.is_field_list_non_exhaustive() && !self.def_id.is_local() + } + /// Computes the `Ident` of this variant by looking up the `Span` pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index c6f3e22e95f6f..c41538a2817dc 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -277,8 +277,7 @@ impl<'tcx> MatchPairTree<'tcx> { .inhabited_predicate(cx.tcx, adt_def) .instantiate(cx.tcx, args) .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); + }) && !adt_def.variant_list_has_applicable_non_exhaustive(); if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 17b22f25dbb0a..0e16f871b16f9 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -613,9 +613,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo diag.span_note(span, fluent::mir_build_def_note); } - let is_variant_list_non_exhaustive = matches!(self.ty.kind(), - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); - if is_variant_list_non_exhaustive { + let is_non_exhaustive = matches!(self.ty.kind(), + ty::Adt(def, _) if def.variant_list_has_applicable_non_exhaustive()); + if is_non_exhaustive { diag.note(fluent::mir_build_non_exhaustive_type_note); } else { diag.note(fluent::mir_build_type_note); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 88194c737a6cc..fec525c9e8cd2 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -150,9 +150,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool { match ty.kind() { - ty::Adt(def, ..) => { - def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local() - } + ty::Adt(def, ..) => def.variant_list_has_applicable_non_exhaustive(), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index ffdd946aadb8b..886c325b355fe 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { && let ty::Adt(adt, args) = *binding_type.kind() && adt.is_struct() && let variant = adt.non_enum_variant() - && (adt.did().is_local() || !variant.is_field_list_non_exhaustive()) + && !variant.field_list_has_applicable_non_exhaustive() && let module_did = cx.tcx.parent_module(stmt.hir_id) && variant .fields diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 0cba72bd2c6a9..cce0617ba3925 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -54,8 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { if let ExprKind::Struct(_, fields, StructTailExpr::Base(base)) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, _) = ty.kind() { - if fields.len() == def.non_enum_variant().fields.len() - && !def.variant(0_usize.into()).is_field_list_non_exhaustive() + let variant = def.non_enum_variant(); + if fields.len() == variant.fields.len() + && !variant.is_field_list_non_exhaustive() { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs index a74eab8b6ae50..3326dea8c5dfa 100644 --- a/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs @@ -51,7 +51,7 @@ impl LateLintPass<'_> for UnneededStructPattern { let variant = cx.tcx.adt_def(enum_did).variant_with_id(did); let has_only_fields_brackets = variant.ctor.is_some() && variant.fields.is_empty(); - let non_exhaustive_activated = !variant.def_id.is_local() && variant.is_field_list_non_exhaustive(); + let non_exhaustive_activated = variant.field_list_has_applicable_non_exhaustive(); if !has_only_fields_brackets || non_exhaustive_activated { return; } From 044deec6824a834ac870e6d081807d432a999807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Tue, 4 Mar 2025 15:18:01 +0100 Subject: [PATCH 025/163] mir_build: consider privacy when checking for irrefutable patterns --- .../src/builder/matches/match_pair.rs | 9 ++-- .../privately-uninhabited-issue-137999.rs | 44 +++++++++++++++++++ .../privately-uninhabited-issue-137999.stderr | 26 +++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 tests/ui/match/privately-uninhabited-issue-137999.rs create mode 100644 tests/ui/match/privately-uninhabited-issue-137999.stderr diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index c41538a2817dc..f2ce0c46dd33d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -273,10 +273,11 @@ impl<'tcx> MatchPairTree<'tcx> { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index - || !v - .inhabited_predicate(cx.tcx, adt_def) - .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) + || !v.inhabited_predicate(cx.tcx, adt_def).instantiate(cx.tcx, args).apply( + cx.tcx, + cx.infcx.typing_env(cx.param_env), + cx.def_id.into(), + ) }) && !adt_def.variant_list_has_applicable_non_exhaustive(); if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) } } diff --git a/tests/ui/match/privately-uninhabited-issue-137999.rs b/tests/ui/match/privately-uninhabited-issue-137999.rs new file mode 100644 index 0000000000000..918393a0c6acf --- /dev/null +++ b/tests/ui/match/privately-uninhabited-issue-137999.rs @@ -0,0 +1,44 @@ +//@ edition:2024 +//@ check-fail + +mod m { + enum Void {} + + pub struct Internal { + _v: Void, + } + + pub enum Test { + A(u32, u32), + B(Internal), + } +} + +use m::Test; + +pub fn f1(x: &mut Test) { + let r1: &mut u32 = match x { + Test::A(a, _) => a, + _ => todo!(), + }; + + let r2: &mut u32 = match x { //~ ERROR cannot use `*x` because it was mutably borrowed + Test::A(_, b) => b, + _ => todo!(), + }; + + let _ = *r1; + let _ = *r2; +} + +pub fn f2(x: &mut Test) { + let r = &mut *x; + match x { //~ ERROR cannot use `*x` because it was mutably borrowed + Test::A(_, _) => {} + _ => {} + } + + let _ = r; +} + +fn main() {} diff --git a/tests/ui/match/privately-uninhabited-issue-137999.stderr b/tests/ui/match/privately-uninhabited-issue-137999.stderr new file mode 100644 index 0000000000000..6f74a75375e32 --- /dev/null +++ b/tests/ui/match/privately-uninhabited-issue-137999.stderr @@ -0,0 +1,26 @@ +error[E0503]: cannot use `*x` because it was mutably borrowed + --> $DIR/privately-uninhabited-issue-137999.rs:25:30 + | +LL | Test::A(a, _) => a, + | - `x.0` is borrowed here +... +LL | let r2: &mut u32 = match x { + | ^ use of borrowed `x.0` +... +LL | let _ = *r1; + | --- borrow later used here + +error[E0503]: cannot use `*x` because it was mutably borrowed + --> $DIR/privately-uninhabited-issue-137999.rs:36:11 + | +LL | let r = &mut *x; + | ------- `*x` is borrowed here +LL | match x { + | ^ use of borrowed `*x` +... +LL | let _ = r; + | - borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0503`. From 8269132210360e201ff9969b956c660602104cf8 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 18 Aug 2024 19:50:41 -0400 Subject: [PATCH 026/163] Add inherent versions of MaybeUninit::fill methods for slices --- library/core/src/mem/maybe_uninit.rs | 320 +++++++++++++++------------ library/coretests/tests/mem.rs | 54 ++--- library/std/src/io/util.rs | 3 +- 3 files changed, 209 insertions(+), 168 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ce84f105e5c50..d0be82adb6b16 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1065,161 +1065,46 @@ impl MaybeUninit { this.write_clone_of_slice(src) } - /// Fills a slice with elements by cloning `value`, returning a mutable reference to the now - /// initialized contents of the slice. - /// Any previously initialized elements will not be dropped. - /// - /// This is similar to [`slice::fill`]. - /// - /// # Panics - /// - /// This function will panic if any call to `Clone` panics. - /// - /// If such a panic occurs, any elements previously initialized during this operation will be - /// dropped. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_fill)] - /// use std::mem::MaybeUninit; - /// - /// let mut buf = [const { MaybeUninit::uninit() }; 10]; - /// let initialized = MaybeUninit::fill(&mut buf, 1); - /// assert_eq!(initialized, &mut [1; 10]); - /// ``` - #[doc(alias = "memset")] + /// Deprecated version of [`slice::write_filled`]. #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill(this: &mut [MaybeUninit], value: T) -> &mut [T] + #[deprecated( + note = "replaced by inherent write_filled method; will eventually be removed", + since = "1.83.0" + )] + pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] where T: Clone, { - SpecFill::spec_fill(this, value); - // SAFETY: Valid elements have just been filled into `this` so it is initialized - unsafe { this.assume_init_mut() } + this.write_filled(value) } - /// Fills a slice with elements returned by calling a closure repeatedly. - /// - /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use - /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can - /// pass [`Default::default`] as the argument. - /// - /// # Panics - /// - /// This function will panic if any call to the provided closure panics. - /// - /// If such a panic occurs, any elements previously initialized during this operation will be - /// dropped. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_fill)] - /// use std::mem::MaybeUninit; - /// - /// let mut buf = [const { MaybeUninit::::uninit() }; 10]; - /// let initialized = MaybeUninit::fill_with(&mut buf, Default::default); - /// assert_eq!(initialized, &mut [0; 10]); - /// ``` + /// Deprecated version of [`slice::write_with`]. #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill_with(this: &mut [MaybeUninit], mut f: F) -> &mut [T] + #[deprecated( + note = "replaced by inherent write_with method; will eventually be removed", + since = "1.83.0" + )] + pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] where F: FnMut() -> T, { - let mut guard = Guard { slice: this, initialized: 0 }; - - for element in guard.slice.iter_mut() { - element.write(f()); - guard.initialized += 1; - } - - super::forget(guard); - - // SAFETY: Valid elements have just been written into `this` so it is initialized - unsafe { this.assume_init_mut() } + this.write_with(|_| f()) } - /// Fills a slice with elements yielded by an iterator until either all elements have been - /// initialized or the iterator is empty. - /// - /// Returns two slices. The first slice contains the initialized portion of the original slice. - /// The second slice is the still-uninitialized remainder of the original slice. - /// - /// # Panics - /// - /// This function panics if the iterator's `next` function panics. - /// - /// If such a panic occurs, any elements previously initialized during this operation will be - /// dropped. - /// - /// # Examples - /// - /// Completely filling the slice: - /// - /// ``` - /// #![feature(maybe_uninit_fill)] - /// use std::mem::MaybeUninit; - /// - /// let mut buf = [const { MaybeUninit::uninit() }; 5]; - /// - /// let iter = [1, 2, 3].into_iter().cycle(); - /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); - /// - /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]); - /// assert_eq!(remainder.len(), 0); - /// ``` - /// - /// Partially filling the slice: - /// - /// ``` - /// #![feature(maybe_uninit_fill)] - /// use std::mem::MaybeUninit; - /// - /// let mut buf = [const { MaybeUninit::uninit() }; 5]; - /// let iter = [1, 2]; - /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); - /// - /// assert_eq!(initialized, &mut [1, 2]); - /// assert_eq!(remainder.len(), 3); - /// ``` - /// - /// Checking an iterator after filling a slice: - /// - /// ``` - /// #![feature(maybe_uninit_fill)] - /// use std::mem::MaybeUninit; - /// - /// let mut buf = [const { MaybeUninit::uninit() }; 3]; - /// let mut iter = [1, 2, 3, 4, 5].into_iter(); - /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter.by_ref()); - /// - /// assert_eq!(initialized, &mut [1, 2, 3]); - /// assert_eq!(remainder.len(), 0); - /// assert_eq!(iter.as_slice(), &[4, 5]); - /// ``` + /// Deprecated version of [`slice::write_iter`]. #[unstable(feature = "maybe_uninit_fill", issue = "117428")] - pub fn fill_from(this: &mut [MaybeUninit], it: I) -> (&mut [T], &mut [MaybeUninit]) + #[deprecated( + note = "replaced by inherent write_iter method; will eventually be removed", + since = "1.83.0" + )] + pub fn fill_from<'a, I>( + this: &'a mut [MaybeUninit], + it: I, + ) -> (&'a mut [T], &'a mut [MaybeUninit]) where I: IntoIterator, { - let iter = it.into_iter(); - let mut guard = Guard { slice: this, initialized: 0 }; - - for (element, val) in guard.slice.iter_mut().zip(iter) { - element.write(val); - guard.initialized += 1; - } - - let initialized_len = guard.initialized; - super::forget(guard); - - // SAFETY: guard.initialized <= this.len() - let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) }; - - // SAFETY: Valid elements have just been written into `init`, so that portion - // of `this` is initialized. - (unsafe { initted.assume_init_mut() }, remainder) + this.write_iter(it) } /// Deprecated version of [`slice::as_bytes`]. @@ -1380,6 +1265,163 @@ impl [MaybeUninit] { unsafe { self.assume_init_mut() } } + /// Fills a slice with elements by cloning `value`, returning a mutable reference to the now + /// initialized contents of the slice. + /// Any previously initialized elements will not be dropped. + /// + /// This is similar to [`slice::fill`]. + /// + /// # Panics + /// + /// This function will panic if any call to `Clone` panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::uninit() }; 10]; + /// let initialized = buf.write_filled(1); + /// assert_eq!(initialized, &mut [1; 10]); + /// ``` + #[doc(alias = "memset")] + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn write_filled(&mut self, value: T) -> &mut [T] + where + T: Clone, + { + SpecFill::spec_fill(self, value); + // SAFETY: Valid elements have just been filled into `self` so it is initialized + unsafe { self.assume_init_mut() } + } + + /// Fills a slice with elements returned by calling a closure for each index. + /// + /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use + /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// pass [`|_| Default::default()`][Default::default] as the argument. + /// + /// # Panics + /// + /// This function will panic if any call to the provided closure panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::::uninit() }; 5]; + /// let initialized = buf.write_with(|idx| idx + 1); + /// assert_eq!(initialized, &mut [1, 2, 3, 4, 5]); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn write_with(&mut self, mut f: F) -> &mut [T] + where + F: FnMut(usize) -> T, + { + let mut guard = Guard { slice: self, initialized: 0 }; + + for (idx, element) in guard.slice.iter_mut().enumerate() { + element.write(f(idx)); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `this` so it is initialized + unsafe { self.assume_init_mut() } + } + + /// Fills a slice with elements yielded by an iterator until either all elements have been + /// initialized or the iterator is empty. + /// + /// Returns two slices. The first slice contains the initialized portion of the original slice. + /// The second slice is the still-uninitialized remainder of the original slice. + /// + /// # Panics + /// + /// This function panics if the iterator's `next` function panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Completely filling the slice: + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::uninit() }; 5]; + /// + /// let iter = [1, 2, 3].into_iter().cycle(); + /// let (initialized, remainder) = buf.write_iter(iter); + /// + /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]); + /// assert_eq!(remainder.len(), 0); + /// ``` + /// + /// Partially filling the slice: + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::uninit() }; 5]; + /// let iter = [1, 2]; + /// let (initialized, remainder) = buf.write_iter(iter); + /// + /// assert_eq!(initialized, &mut [1, 2]); + /// assert_eq!(remainder.len(), 3); + /// ``` + /// + /// Checking an iterator after filling a slice: + /// + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = [const { MaybeUninit::uninit() }; 3]; + /// let mut iter = [1, 2, 3, 4, 5].into_iter(); + /// let (initialized, remainder) = buf.write_iter(iter.by_ref()); + /// + /// assert_eq!(initialized, &mut [1, 2, 3]); + /// assert_eq!(remainder.len(), 0); + /// assert_eq!(iter.as_slice(), &[4, 5]); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn write_iter(&mut self, it: I) -> (&mut [T], &mut [MaybeUninit]) + where + I: IntoIterator, + { + let iter = it.into_iter(); + let mut guard = Guard { slice: self, initialized: 0 }; + + for (element, val) in guard.slice.iter_mut().zip(iter) { + element.write(val); + guard.initialized += 1; + } + + let initialized_len = guard.initialized; + super::forget(guard); + + // SAFETY: guard.initialized <= self.len() + let (initted, remainder) = unsafe { self.split_at_mut_unchecked(initialized_len) }; + + // SAFETY: Valid elements have just been written into `init`, so that portion + // of `this` is initialized. + (unsafe { initted.assume_init_mut() }, remainder) + } + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. /// /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 9cb94ca3b0ff0..9c15be4a8c4bd 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,5 +1,5 @@ use core::mem::*; -use core::ptr; +use core::{array, ptr}; #[cfg(panic = "unwind")] use std::rc::Rc; @@ -327,11 +327,11 @@ fn uninit_write_clone_of_slice_no_drop() { } #[test] -fn uninit_fill() { +fn uninit_write_filled() { let mut dst = [MaybeUninit::new(255); 64]; let expect = [0; 64]; - assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect); + assert_eq!(dst.write_filled(0), &expect); } #[cfg(panic = "unwind")] @@ -352,7 +352,7 @@ impl Clone for CloneUntilPanic { #[test] #[cfg(panic = "unwind")] -fn uninit_fill_clone_panic_drop() { +fn uninit_write_filled_panic_drop() { use std::panic; let rc = Rc::new(()); @@ -361,7 +361,7 @@ fn uninit_fill_clone_panic_drop() { let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill(&mut dst, src); + dst.write_filled(src); })); match err { @@ -378,23 +378,23 @@ fn uninit_fill_clone_panic_drop() { #[test] #[cfg(panic = "unwind")] -fn uninit_fill_clone_no_drop_clones() { +fn uninit_write_filled_no_drop_clones() { let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - MaybeUninit::fill(&mut dst, Bomb); + dst.write_filled(Bomb); } #[test] -fn uninit_fill_with() { - let mut dst = [MaybeUninit::new(255); 64]; - let expect = [0; 64]; +fn uninit_write_with() { + let mut dst = [MaybeUninit::new(255usize); 64]; + let expect = array::from_fn::(|idx| idx); - assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect); + assert_eq!(dst.write_with(|idx| idx), &expect); } #[test] #[cfg(panic = "unwind")] -fn uninit_fill_with_mid_panic() { +fn uninit_write_with_mid_panic() { use std::panic; let rc = Rc::new(()); @@ -403,7 +403,7 @@ fn uninit_fill_with_mid_panic() { let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill_with(&mut dst, || src.clone()); + dst.write_with(|_| src.clone()); })); drop(src); @@ -423,58 +423,58 @@ fn uninit_fill_with_mid_panic() { #[test] #[cfg(panic = "unwind")] -fn uninit_fill_with_no_drop() { +fn uninit_write_with_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = Bomb; - MaybeUninit::fill_with(&mut dst, || src.clone()); + dst.write_with(|_| src.clone()); forget(src); } #[test] -fn uninit_fill_from() { +fn uninit_write_iter() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 64]; - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + let (initted, remainder) = dst.write_iter(src.into_iter()); assert_eq!(initted, &src); assert_eq!(remainder.len(), 0); } #[test] -fn uninit_fill_from_partial() { +fn uninit_write_iter_partial() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 48]; - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + let (initted, remainder) = dst.write_iter(src.into_iter()); assert_eq!(initted, &src); assert_eq!(remainder.len(), 16); } #[test] -fn uninit_over_fill() { +fn uninit_write_iter_overfill() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 72]; - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + let (initted, remainder) = dst.write_iter(src.into_iter()); assert_eq!(initted, &src[0..64]); assert_eq!(remainder.len(), 0); } #[test] -fn uninit_empty_fill() { +fn uninit_write_iter_empty() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 0]; - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + let (initted, remainder) = dst.write_iter(src.into_iter()); assert_eq!(initted, &src[0..0]); assert_eq!(remainder.len(), 64); } #[test] #[cfg(panic = "unwind")] -fn uninit_fill_from_mid_panic() { +fn uninit_write_iter_mid_panic() { use std::panic; struct IterUntilPanic { @@ -504,7 +504,7 @@ fn uninit_fill_from_mid_panic() { let src = IterUntilPanic { limit: 3, rc: rc.clone() }; let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill_from(&mut dst, src); + dst.write_iter(src); })); match err { @@ -522,11 +522,11 @@ fn uninit_fill_from_mid_panic() { #[test] #[cfg(panic = "unwind")] -fn uninit_fill_from_no_drop() { +fn uninit_write_iter_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = [Bomb]; - MaybeUninit::fill_from(&mut dst, src.iter()); + dst.write_iter(src.iter()); forget(src); } diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index cb3f864fd4e1e..3b66dbf40b6b5 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -7,7 +7,6 @@ use crate::fmt; use crate::io::{ self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, }; -use crate::mem::MaybeUninit; /// `Empty` ignores any data written via [`Write`], and will always be empty /// (returning zero bytes) when read via [`Read`]. @@ -196,7 +195,7 @@ impl Read for Repeat { #[inline] fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { // SAFETY: No uninit bytes are being written. - MaybeUninit::fill(unsafe { buf.as_mut() }, self.byte); + unsafe { buf.as_mut() }.write_filled(self.byte); // SAFETY: the entire unfilled portion of buf has been initialized. unsafe { buf.advance_unchecked(buf.capacity()) }; Ok(()) From db7e61cfa53f72f1be9179180272b836bf781a40 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 30 Jan 2025 12:51:22 +0100 Subject: [PATCH 027/163] document capacity for ZST as example and prose --- library/alloc/src/vec/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 48afcf6e0645b..0aacdd2fc5bec 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1240,6 +1240,19 @@ impl Vec { /// vec.push(42); /// assert!(vec.capacity() >= 10); /// ``` + /// + /// A vector with zero-sized elements will always have a capacity of usize::MAX: + /// + /// ``` + /// #[derive(Clone)] + /// struct ZeroSized; + /// + /// fn main() { + /// assert_eq!(std::mem::size_of::(), 0); + /// let v = vec![ZeroSized; 0]; + /// assert_eq!(v.capacity(), usize::MAX); + /// } + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] From 523b9d942890f331fcee5d2d26e7cecfb59c6ec8 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 14 Feb 2025 13:40:24 -0800 Subject: [PATCH 028/163] Implement default methods for io::Empty and io::Sink Eliminate any redundant, unobservable logic from the their default method implementations. The observable changes are that `Write::write_fmt` for both types now ignores the formatting arguments, so a user fmt impl which has side effects is not invoked, and `Write::write_all_vectored` for both types does not advance the borrowed buffers. Neither behavior is guaranteed by the docs and the latter is documented as unspecified. `Empty` is not marked as vectored, so that `Chain` and `Chain<_, Empty>` are not forced to be vectored. --- library/std/src/io/util.rs | 116 +++++++++++++++++++++++++++++++ library/std/src/io/util/tests.rs | 111 ++++++++++++++++++++++++++--- tests/ui/write-fmt-errors.rs | 4 +- 3 files changed, 218 insertions(+), 13 deletions(-) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index cb3f864fd4e1e..17178b4a64147 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -68,6 +68,38 @@ impl Read for Empty { fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { Ok(()) } + + #[inline] + fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + Ok(0) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + // Do not force `Chain` or `Chain` to use vectored + // reads, unless the other reader is vectored. + false + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } + } + + #[inline] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } + } + + #[inline] + fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { + Ok(0) + } + + #[inline] + fn read_to_string(&mut self, _buf: &mut String) -> io::Result { + Ok(0) + } } #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Empty { @@ -75,20 +107,44 @@ impl BufRead for Empty { fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) } + #[inline] fn consume(&mut self, _n: usize) {} + + #[inline] + fn has_data_left(&mut self) -> io::Result { + Ok(false) + } + + #[inline] + fn read_until(&mut self, _byte: u8, _buf: &mut Vec) -> io::Result { + Ok(0) + } + + #[inline] + fn skip_until(&mut self, _byte: u8) -> io::Result { + Ok(0) + } + + #[inline] + fn read_line(&mut self, _buf: &mut String) -> io::Result { + Ok(0) + } } #[stable(feature = "empty_seek", since = "1.51.0")] impl Seek for Empty { + #[inline] fn seek(&mut self, _pos: SeekFrom) -> io::Result { Ok(0) } + #[inline] fn stream_len(&mut self) -> io::Result { Ok(0) } + #[inline] fn stream_position(&mut self) -> io::Result { Ok(0) } @@ -119,6 +175,21 @@ impl Write for Empty { true } + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -143,6 +214,21 @@ impl Write for &Empty { true } + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -302,6 +388,21 @@ impl Write for Sink { true } + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -326,6 +427,21 @@ impl Write for &Sink { true } + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index 0599a881af179..d0f106d7af416 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -1,14 +1,51 @@ +use crate::fmt; use crate::io::prelude::*; -use crate::io::{BorrowedBuf, Empty, Repeat, SeekFrom, Sink, empty, repeat, sink}; +use crate::io::{ + BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink, +}; use crate::mem::MaybeUninit; +struct ErrorDisplay; + +impl fmt::Display for ErrorDisplay { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Err(fmt::Error) + } +} + +struct PanicDisplay; + +impl fmt::Display for PanicDisplay { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + panic!() + } +} + +#[track_caller] +fn test_sinking(mut w: W) { + assert_eq!(w.write(&[]).unwrap(), 0); + assert_eq!(w.write(&[0]).unwrap(), 1); + assert_eq!(w.write(&[0; 1024]).unwrap(), 1024); + w.write_all(&[]).unwrap(); + w.write_all(&[0]).unwrap(); + w.write_all(&[0; 1024]).unwrap(); + let mut bufs = + [IoSlice::new(&[]), IoSlice::new(&[0]), IoSlice::new(&[0; 1024]), IoSlice::new(&[])]; + assert!(w.is_write_vectored()); + assert_eq!(w.write_vectored(&[]).unwrap(), 0); + assert_eq!(w.write_vectored(&bufs).unwrap(), 1025); + w.write_all_vectored(&mut []).unwrap(); + w.write_all_vectored(&mut bufs).unwrap(); + assert!(w.flush().is_ok()); + assert_eq!(w.by_ref().write(&[0; 1024]).unwrap(), 1024); + // Ignores fmt arguments + w.write_fmt(format_args!("{}", ErrorDisplay)).unwrap(); + w.write_fmt(format_args!("{}", PanicDisplay)).unwrap(); +} + #[test] fn sink_sinks() { - let mut s = sink(); - assert_eq!(s.write(&[]).unwrap(), 0); - assert_eq!(s.write(&[0]).unwrap(), 1); - assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); + test_sinking(sink()); } #[test] @@ -19,6 +56,21 @@ fn empty_reads() { assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0); + e.read_exact(&mut []).unwrap(); + assert_eq!(e.read_exact(&mut [0]).unwrap_err().kind(), ErrorKind::UnexpectedEof); + assert_eq!(e.read_exact(&mut [0; 1024]).unwrap_err().kind(), ErrorKind::UnexpectedEof); + + assert!(!e.is_read_vectored()); + assert_eq!(e.read_vectored(&mut []).unwrap(), 0); + let (mut buf1, mut buf1024) = ([0], [0; 1024]); + let bufs = &mut [ + IoSliceMut::new(&mut []), + IoSliceMut::new(&mut buf1), + IoSliceMut::new(&mut buf1024), + IoSliceMut::new(&mut []), + ]; + assert_eq!(e.read_vectored(bufs).unwrap(), 0); + let buf: &mut [MaybeUninit<_>] = &mut []; let mut buf: BorrowedBuf<'_> = buf.into(); e.read_buf(buf.unfilled()).unwrap(); @@ -42,6 +94,47 @@ fn empty_reads() { Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.len(), 0); assert_eq!(buf.init_len(), 0); + + let buf: &mut [MaybeUninit<_>] = &mut []; + let mut buf: BorrowedBuf<'_> = buf.into(); + e.read_buf_exact(buf.unfilled()).unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit()]; + let mut buf: BorrowedBuf<'_> = buf.into(); + assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; + let mut buf: BorrowedBuf<'_> = buf.into(); + assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024]; + let mut buf: BorrowedBuf<'_> = buf.into(); + assert_eq!( + Read::by_ref(&mut e).read_buf_exact(buf.unfilled()).unwrap_err().kind(), + ErrorKind::UnexpectedEof, + ); + assert_eq!(buf.len(), 0); + assert_eq!(buf.init_len(), 0); + + let mut buf = Vec::new(); + assert_eq!(e.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf, vec![]); + let mut buf = vec![1, 2, 3]; + assert_eq!(e.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf, vec![1, 2, 3]); + + let mut buf = String::new(); + assert_eq!(e.read_to_string(&mut buf).unwrap(), 0); + assert_eq!(buf, ""); + let mut buf = "hello".to_owned(); + assert_eq!(e.read_to_string(&mut buf).unwrap(), 0); + assert_eq!(buf, "hello"); } #[test] @@ -66,11 +159,7 @@ fn empty_seeks() { #[test] fn empty_sinks() { - let mut e = empty(); - assert_eq!(e.write(&[]).unwrap(), 0); - assert_eq!(e.write(&[0]).unwrap(), 1); - assert_eq!(e.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(Write::by_ref(&mut e).write(&[0; 1024]).unwrap(), 1024); + test_sinking(empty()); } #[test] diff --git a/tests/ui/write-fmt-errors.rs b/tests/ui/write-fmt-errors.rs index 1dafb9a784b3a..b48fa3f11ccb1 100644 --- a/tests/ui/write-fmt-errors.rs +++ b/tests/ui/write-fmt-errors.rs @@ -4,7 +4,7 @@ #![feature(io_error_uncategorized)] use std::fmt; -use std::io::{self, Error, Write, sink}; +use std::io::{self, Error, Write}; use std::panic::catch_unwind; struct ErrorDisplay; @@ -33,7 +33,7 @@ fn main() { assert!(res.is_err(), "writer error did not propagate"); // Test that the error from the formatter is detected. - let res = catch_unwind(|| write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar")); + let res = catch_unwind(|| write!(vec![], "{} {} {}", 1, ErrorDisplay, "bar")); let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap(); assert!( err.contains("formatting trait implementation returned an error"), From c9ccec93fa5e87f1363f0ce6edc897340e8c3884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Thu, 26 Dec 2024 16:52:54 +0900 Subject: [PATCH 029/163] Initial STD support for Cygwin Signed-off-by: Ookiineko --- library/rtstartup/rsbegin.rs | 2 +- library/rtstartup/rsend.rs | 2 +- library/std/build.rs | 1 + library/std/src/os/cygwin/fs.rs | 122 ++++++++++++++++++ library/std/src/os/cygwin/mod.rs | 4 + library/std/src/os/cygwin/raw.rs | 70 ++++++++++ library/std/src/os/mod.rs | 2 + library/std/src/os/unix/mod.rs | 2 + library/std/src/os/unix/net/datagram.rs | 2 + library/std/src/os/unix/net/mod.rs | 1 + library/std/src/os/unix/net/stream.rs | 2 + library/std/src/os/unix/net/ucred.rs | 4 +- library/std/src/sys/fs/unix.rs | 6 +- library/std/src/sys/net/connection/socket.rs | 3 +- .../std/src/sys/net/connection/socket/unix.rs | 3 + library/std/src/sys/pal/unix/args.rs | 1 + library/std/src/sys/pal/unix/env.rs | 11 ++ library/std/src/sys/pal/unix/fd.rs | 3 + library/std/src/sys/pal/unix/mod.rs | 2 +- library/std/src/sys/pal/unix/os.rs | 2 + library/std/src/sys/pal/unix/pipe.rs | 1 + .../src/sys/pal/unix/process/process_unix.rs | 3 +- .../std/src/sys/pal/unix/stack_overflow.rs | 2 + library/std/src/sys/pal/unix/thread.rs | 5 +- 24 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 library/std/src/os/cygwin/fs.rs create mode 100644 library/std/src/os/cygwin/mod.rs create mode 100644 library/std/src/os/cygwin/raw.rs diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 67b09599d9d2b..4ae218c2f9f3f 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -49,7 +49,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { // enumerating currently loaded modules via the dl_iterate_phdr() API and // finding their ".eh_frame" sections); Others, like Windows, require modules // to actively register their unwind info sections via unwinder API. -#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] +#[cfg(all(any(target_os = "cygwin", all(target_os = "windows", target_env = "gnu")), target_arch = "x86"))] pub mod eh_frames { #[no_mangle] #[unsafe(link_section = ".eh_frame")] diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index a6f7d103356bf..9809f4b0878e1 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -27,7 +27,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } -#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] +#[cfg(all(any(target_os = "cygwin", all(target_os = "windows", target_env = "gnu")), target_arch = "x86"))] pub mod eh_frames { // Terminate the frame unwind info section with a 0 as a sentinel; // this would be the 'length' field in a real FDE. diff --git a/library/std/build.rs b/library/std/build.rs index cedfd7406a1aa..e4295eb2f682a 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -61,6 +61,7 @@ fn main() { || target_os == "zkvm" || target_os == "rtems" || target_os == "nuttx" + || target_os == "cygwin" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/os/cygwin/fs.rs b/library/std/src/os/cygwin/fs.rs new file mode 100644 index 0000000000000..a0667935ac1f6 --- /dev/null +++ b/library/std/src/os/cygwin/fs.rs @@ -0,0 +1,122 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] +use crate::fs::Metadata; +#[allow(deprecated)] +use crate::os::cygwin::raw; +use crate::sys_common::AsInner; +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned `stat` are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[deprecated( + since = "1.8.0", + note = "deprecated in favor of the accessor \ + methods of this trait" + )] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_birthtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_birthtime_nsec(&self) -> i64; +} +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } + fn st_birthtime(&self) -> i64 { + self.as_inner().as_inner().st_birthtime as i64 + } + fn st_birthtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_birthtime_nsec as i64 + } +} diff --git a/library/std/src/os/cygwin/mod.rs b/library/std/src/os/cygwin/mod.rs new file mode 100644 index 0000000000000..638f738dac806 --- /dev/null +++ b/library/std/src/os/cygwin/mod.rs @@ -0,0 +1,4 @@ +//! Cygwin-specific definitions +#![stable(feature = "raw_ext", since = "1.1.0")] +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/cygwin/raw.rs b/library/std/src/os/cygwin/raw.rs new file mode 100644 index 0000000000000..7177b2f699c7e --- /dev/null +++ b/library/std/src/os/cygwin/raw.rs @@ -0,0 +1,70 @@ +//! Cygwin-specific raw type definitions +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] +use crate::os::raw::{c_long, c_void}; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = u16; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = i64; +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = *mut c_void; +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: blksize_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: blkcnt_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime_nsec: c_long, +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index e28a1c3e6d5f4..229c645b2d0c8 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -125,6 +125,8 @@ pub mod windows; pub mod aix; #[cfg(target_os = "android")] pub mod android; +#[cfg(target_os = "cygwin")] +pub mod cygwin; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "emscripten")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 2f9dffe8c6561..5802b6539651c 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -41,6 +41,8 @@ mod platform { pub use crate::os::aix::*; #[cfg(target_os = "android")] pub use crate::os::android::*; + #[cfg(target_os = "cygwin")] + pub use crate::os::cygwin::*; #[cfg(target_vendor = "apple")] pub use crate::os::darwin::*; #[cfg(target_os = "dragonfly")] diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 82446ea107fe5..7735637c84059 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -9,6 +9,7 @@ target_os = "illumos", target_os = "haiku", target_os = "nto", + target_os = "cygwin" ))] use libc::MSG_NOSIGNAL; @@ -37,6 +38,7 @@ use crate::{fmt, io}; target_os = "illumos", target_os = "haiku", target_os = "nto", + target_os = "cygwin" )))] const MSG_NOSIGNAL: core::ffi::c_int = 0x0; diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 3e45e3533ed28..b07ba110c41c2 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -21,6 +21,7 @@ mod tests; target_os = "openbsd", target_os = "nto", target_vendor = "apple", + target_os = "cygwin" ))] mod ucred; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index cb210b41eae19..1cab04a454dc0 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -10,6 +10,7 @@ use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_wi target_os = "openbsd", target_os = "nto", target_vendor = "apple", + target_os = "cygwin" ))] use super::{UCred, peer_cred}; use crate::fmt; @@ -231,6 +232,7 @@ impl UnixStream { target_os = "openbsd", target_os = "nto", target_vendor = "apple", + target_os = "cygwin" ))] pub fn peer_cred(&self) -> io::Result { peer_cred(self) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index 2dd7d409e48c2..36fb9c46b4aba 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -33,10 +33,10 @@ pub(super) use self::impl_apple::peer_cred; target_os = "nto" ))] pub(super) use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub(super) use self::impl_linux::peer_cred; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))] mod impl_linux { use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred}; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 914971934bfb0..e99d6a07731e7 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -543,7 +543,7 @@ impl FileAttr { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } - #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_vendor = "apple"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_vendor = "apple", target_os = "cygwin"))] pub fn created(&self) -> io::Result { SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64) } @@ -553,6 +553,7 @@ impl FileAttr { target_os = "openbsd", target_os = "vita", target_vendor = "apple", + target_os = "cygwin", )))] pub fn created(&self) -> io::Result { cfg_has_statx! { @@ -960,6 +961,7 @@ impl DirEntry { #[cfg(any( target_os = "linux", + target_os = "cygwin", target_os = "emscripten", target_os = "android", target_os = "solaris", @@ -1220,6 +1222,7 @@ impl File { target_os = "freebsd", target_os = "fuchsia", target_os = "linux", + target_os = "cygwin", target_os = "android", target_os = "netbsd", target_os = "openbsd", @@ -1234,6 +1237,7 @@ impl File { target_os = "fuchsia", target_os = "freebsd", target_os = "linux", + target_os = "cygwin", target_os = "netbsd", target_os = "openbsd", target_os = "nto", diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs index e154cf039cad1..7301bde6881a3 100644 --- a/library/std/src/sys/net/connection/socket.rs +++ b/library/std/src/sys/net/connection/socket.rs @@ -59,7 +59,8 @@ cfg_if::cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "solaris", target_os = "illumos", - target_os = "haiku", target_os = "nto"))] { + target_os = "haiku", target_os = "nto", + target_os = "cygwin"))] { use libc::MSG_NOSIGNAL; } else { const MSG_NOSIGNAL: c_int = 0x0; diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index e633cf772c528..647058385a247 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -81,6 +81,7 @@ impl Socket { target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "nto", target_os = "solaris", ))] { @@ -128,6 +129,7 @@ impl Socket { target_os = "hurd", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "nto", ))] { // Like above, set cloexec atomically @@ -257,6 +259,7 @@ impl Socket { target_os = "hurd", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", ))] { unsafe { let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?; diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index 1c87a79803c0d..0bb7b64007aba 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -100,6 +100,7 @@ impl DoubleEndedIterator for Args { target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "solaris", target_os = "illumos", target_os = "emscripten", diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs index 2aee0b5d46056..c6609298f4b23 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/pal/unix/env.rs @@ -108,6 +108,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "cygwin")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "cygwin"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".dll"; + pub const DLL_EXTENSION: &str = "dll"; + pub const EXE_SUFFIX: &str = ".exe"; + pub const EXE_EXTENSION: &str = "exe"; +} + #[cfg(target_os = "android")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 2fc33bdfefbf5..8ec2a08966eee 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -47,6 +47,7 @@ const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { target_os = "netbsd", target_os = "openbsd", target_vendor = "apple", + target_os = "cygwin", ))] const fn max_iov() -> usize { libc::IOV_MAX as usize @@ -500,6 +501,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "l4re", target_os = "linux", + target_os = "cygwin", target_os = "haiku", target_os = "redox", target_os = "vxworks", @@ -522,6 +524,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "l4re", target_os = "linux", + target_os = "cygwin", target_os = "haiku", target_os = "redox", target_os = "vxworks", diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 419abe732ac3f..e2e537b7bd365 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -380,7 +380,7 @@ cfg_if::cfg_if! { #[link(name = "pthread")] #[link(name = "rt")] unsafe extern "C" {} - } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] { + } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin"))] { #[link(name = "pthread")] unsafe extern "C" {} } else if #[cfg(target_os = "solaris")] { diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 3a238d160cb57..418211d24bb3b 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -46,6 +46,7 @@ unsafe extern "C" { any( target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "android", target_os = "redox", target_os = "nuttx", @@ -395,6 +396,7 @@ pub fn current_exe() -> io::Result { #[cfg(any( target_os = "linux", + target_os = "cygwin", target_os = "hurd", target_os = "android", target_os = "nuttx", diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs index 4a992e32a9184..55510153dc847 100644 --- a/library/std/src/sys/pal/unix/pipe.rs +++ b/library/std/src/sys/pal/unix/pipe.rs @@ -27,6 +27,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "redox" ))] { unsafe { diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 25d9e9353320f..257732aaedc06 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -1154,7 +1154,7 @@ fn signal_string(signal: i32) -> &'static str { ) ))] libc::SIGSTKFLT => " (SIGSTKFLT)", - #[cfg(any(target_os = "linux", target_os = "nto"))] + #[cfg(any(target_os = "linux", target_os = "nto", target_os = "cygwin"))] libc::SIGPWR => " (SIGPWR)", #[cfg(any( target_os = "freebsd", @@ -1163,6 +1163,7 @@ fn signal_string(signal: i32) -> &'static str { target_os = "dragonfly", target_os = "nto", target_vendor = "apple", + target_os = "cygwin", ))] libc::SIGEMT => " (SIGEMT)", #[cfg(any( diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0ecccdc8812dd..5a639d0545bfe 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -32,6 +32,7 @@ impl Drop for Handler { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "solaris", target_os = "illumos", ))] @@ -583,6 +584,7 @@ mod imp { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "cygwin", target_os = "solaris", target_os = "illumos", )))] diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 11f6998cac118..4397cb69a09e6 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -137,7 +137,8 @@ impl Thread { target_os = "linux", target_os = "freebsd", target_os = "dragonfly", - target_os = "nuttx" + target_os = "nuttx", + target_os = "cygwin" ))] pub fn set_name(name: &CStr) { unsafe { @@ -343,6 +344,7 @@ impl Drop for Thread { target_os = "illumos", target_os = "vxworks", target_vendor = "apple", + target_os = "cygwin", ))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; @@ -362,6 +364,7 @@ pub fn available_parallelism() -> io::Result> { target_os = "linux", target_os = "aix", target_vendor = "apple", + target_os = "cygwin", ))] { #[allow(unused_assignments)] #[allow(unused_mut)] From e3e98c84d3eb64181c25ff88f31aee432363ca12 Mon Sep 17 00:00:00 2001 From: Ookiineko Date: Mon, 4 Mar 2024 18:34:47 +0800 Subject: [PATCH 030/163] Fix `std::sys::unix::set_linger` for Cygwin Signed-off-by: Ookiineko --- library/std/src/sys/net/connection/socket/unix.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 647058385a247..bbe1e038dccf5 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -424,6 +424,7 @@ impl Socket { Ok(()) } + #[cfg(not(target_os = "cygwin"))] pub fn set_linger(&self, linger: Option) -> io::Result<()> { let linger = libc::linger { l_onoff: linger.is_some() as libc::c_int, @@ -433,6 +434,16 @@ impl Socket { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } + #[cfg(target_os = "cygwin")] + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = libc::linger { + l_onoff: linger.is_some() as libc::c_ushort, + l_linger: linger.unwrap_or_default().as_secs() as libc::c_ushort, + }; + + setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + } + pub fn linger(&self) -> io::Result> { let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?; From 1aad114afda473ccda8b0eb5e0d5a3dcfc35c40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Mon, 30 Dec 2024 05:00:20 +0900 Subject: [PATCH 031/163] Fix building for cygwin --- library/std/src/os/unix/net/mod.rs | 1 + library/std/src/sys/pal/unix/fd.rs | 1 + library/std/src/sys/pal/unix/stack_overflow.rs | 8 +++++--- library/std/src/sys/random/linux.rs | 6 +++++- library/std/src/sys/random/mod.rs | 3 ++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index b07ba110c41c2..6cd62303a5325 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -45,6 +45,7 @@ pub use self::stream::*; target_os = "openbsd", target_os = "nto", target_vendor = "apple", + target_os = "cygwin", ))] #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] pub use self::ucred::*; diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 8ec2a08966eee..eb873759ecbb4 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -75,6 +75,7 @@ const fn max_iov() -> usize { target_os = "horizon", target_os = "vita", target_vendor = "apple", + target_os = "cygwin", )))] const fn max_iov() -> usize { 16 // The minimum value required by POSIX. diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 5a639d0545bfe..463f18800a6c8 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -316,7 +316,8 @@ mod imp { target_os = "netbsd", target_os = "hurd", target_os = "linux", - target_os = "l4re" + target_os = "l4re", + target_os = "cygwin" ))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; @@ -371,7 +372,7 @@ mod imp { // this way someone on any unix-y OS can check that all these compile if cfg!(all(target_os = "linux", not(target_env = "musl"))) { install_main_guard_linux(page_size) - } else if cfg!(all(target_os = "linux", target_env = "musl")) { + } else if cfg!(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin")) { install_main_guard_linux_musl(page_size) } else if cfg!(target_os = "freebsd") { install_main_guard_freebsd(page_size) @@ -511,7 +512,8 @@ mod imp { target_os = "hurd", target_os = "linux", target_os = "netbsd", - target_os = "l4re" + target_os = "l4re", + target_os = "cygwin" ))] // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option> { diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index e3cb79285cd15..266c71abf3d66 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -94,7 +94,10 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { let flags = if insecure { if GRND_INSECURE_AVAILABLE.load(Relaxed) { - libc::GRND_INSECURE + #[cfg(target_os = "cygwin")] + { libc::GRND_NONBLOCK } + #[cfg(not(target_os = "cygwin"))] + { libc::GRND_INSECURE } } else { libc::GRND_NONBLOCK } @@ -110,6 +113,7 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { libc::EINTR => continue, // `GRND_INSECURE` is not available, try // `GRND_NONBLOCK`. + #[cfg(not(target_os = "cygwin"))] libc::EINVAL if flags == libc::GRND_INSECURE => { GRND_INSECURE_AVAILABLE.store(false, Relaxed); continue; diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index f42351deb92c0..b6a357e5b07f9 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -1,6 +1,6 @@ cfg_if::cfg_if! { // Tier 1 - if #[cfg(any(target_os = "linux", target_os = "android"))] { + if #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))] { mod linux; pub use linux::{fill_bytes, hashmap_random_keys}; } else if #[cfg(target_os = "windows")] { @@ -88,6 +88,7 @@ cfg_if::cfg_if! { target_os = "android", all(target_family = "wasm", target_os = "unknown"), target_os = "xous", + target_os = "cygwin", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; From 886fb15c0fb1125624a3d8e5f82f147431e8f708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 25 Feb 2025 23:33:53 +0800 Subject: [PATCH 032/163] Update metadata for cygwin target --- compiler/rustc_target/src/spec/targets/x86_64_pc_cygwin.rs | 2 +- src/doc/rustc/src/platform-support.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_cygwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_cygwin.rs index 8da4fe6b8b152..eac4caf41c8bc 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_cygwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_cygwin.rs @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { description: Some("64-bit x86 Cygwin".into()), tier: Some(3), host_tools: Some(false), - std: None, + std: Some(true), }, } } diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f78ab151b9c24..9048eb274b7f9 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -406,7 +406,7 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator -[`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ? | | 64-bit x86 Cygwin | +[`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin | [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | [`x86_64-pc-nto-qnx800`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 8.0 RTOS | From abcbd881754651af73f7454cbcbdab953d2e4e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 26 Feb 2025 00:05:40 +0800 Subject: [PATCH 033/163] Revert changes for rtstartup --- library/rtstartup/rsbegin.rs | 2 +- library/rtstartup/rsend.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 4ae218c2f9f3f..67b09599d9d2b 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -49,7 +49,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { // enumerating currently loaded modules via the dl_iterate_phdr() API and // finding their ".eh_frame" sections); Others, like Windows, require modules // to actively register their unwind info sections via unwinder API. -#[cfg(all(any(target_os = "cygwin", all(target_os = "windows", target_env = "gnu")), target_arch = "x86"))] +#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] pub mod eh_frames { #[no_mangle] #[unsafe(link_section = ".eh_frame")] diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index 9809f4b0878e1..a6f7d103356bf 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -27,7 +27,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } -#[cfg(all(any(target_os = "cygwin", all(target_os = "windows", target_env = "gnu")), target_arch = "x86"))] +#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] pub mod eh_frames { // Terminate the frame unwind info section with a 0 as a sentinel; // this would be the 'length' field in a real FDE. From d24c6a29f5dca8c52ecf1ff88e4786e537078fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 26 Feb 2025 00:05:55 +0800 Subject: [PATCH 034/163] Fix code style --- library/std/src/sys/fs/unix.rs | 7 ++++++- library/std/src/sys/pal/unix/stack_overflow.rs | 3 ++- library/std/src/sys/random/linux.rs | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index e99d6a07731e7..7774461a493bb 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -543,7 +543,12 @@ impl FileAttr { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } - #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_vendor = "apple", target_os = "cygwin"))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_vendor = "apple", + target_os = "cygwin", + ))] pub fn created(&self) -> io::Result { SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64) } diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 463f18800a6c8..344f9c63257e8 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -372,7 +372,8 @@ mod imp { // this way someone on any unix-y OS can check that all these compile if cfg!(all(target_os = "linux", not(target_env = "musl"))) { install_main_guard_linux(page_size) - } else if cfg!(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin")) { + } else if cfg!(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin")) + { install_main_guard_linux_musl(page_size) } else if cfg!(target_os = "freebsd") { install_main_guard_freebsd(page_size) diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 266c71abf3d66..fb4274281d63f 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -95,9 +95,13 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { let flags = if insecure { if GRND_INSECURE_AVAILABLE.load(Relaxed) { #[cfg(target_os = "cygwin")] - { libc::GRND_NONBLOCK } + { + libc::GRND_NONBLOCK + } #[cfg(not(target_os = "cygwin"))] - { libc::GRND_INSECURE } + { + libc::GRND_INSECURE + } } else { libc::GRND_NONBLOCK } From 7d80aaaca8f5828fe6ce265e1dc6cb2267e618a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 15:26:23 +0800 Subject: [PATCH 035/163] Remove std::os::cygwin::raw --- library/std/src/os/cygwin/fs.rs | 20 --------- library/std/src/os/cygwin/mod.rs | 1 - library/std/src/os/cygwin/raw.rs | 70 -------------------------------- 3 files changed, 91 deletions(-) delete mode 100644 library/std/src/os/cygwin/raw.rs diff --git a/library/std/src/os/cygwin/fs.rs b/library/std/src/os/cygwin/fs.rs index a0667935ac1f6..5533264fd515b 100644 --- a/library/std/src/os/cygwin/fs.rs +++ b/library/std/src/os/cygwin/fs.rs @@ -1,27 +1,11 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; -#[allow(deprecated)] -use crate::os::cygwin::raw; use crate::sys_common::AsInner; /// OS-specific extensions to [`fs::Metadata`]. /// /// [`fs::Metadata`]: crate::fs::Metadata #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { - /// Gain a reference to the underlying `stat` structure which contains - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[deprecated( - since = "1.8.0", - note = "deprecated in favor of the accessor \ - methods of this trait" - )] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; #[stable(feature = "metadata_ext2", since = "1.8.0")] @@ -61,10 +45,6 @@ pub trait MetadataExt { } #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } - } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 } diff --git a/library/std/src/os/cygwin/mod.rs b/library/std/src/os/cygwin/mod.rs index 638f738dac806..f6385653d774d 100644 --- a/library/std/src/os/cygwin/mod.rs +++ b/library/std/src/os/cygwin/mod.rs @@ -1,4 +1,3 @@ //! Cygwin-specific definitions #![stable(feature = "raw_ext", since = "1.1.0")] pub mod fs; -pub mod raw; diff --git a/library/std/src/os/cygwin/raw.rs b/library/std/src/os/cygwin/raw.rs deleted file mode 100644 index 7177b2f699c7e..0000000000000 --- a/library/std/src/os/cygwin/raw.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Cygwin-specific raw type definitions -#![stable(feature = "raw_ext", since = "1.1.0")] -#![deprecated( - since = "1.8.0", - note = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions" -)] -#![allow(deprecated)] -use crate::os::raw::{c_long, c_void}; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blkcnt_t = i64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type blksize_t = i32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type dev_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type nlink_t = u16; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type off_t = i64; -#[stable(feature = "raw_ext", since = "1.1.0")] -pub type time_t = i64; -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = *mut c_void; -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ino_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: mode_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: nlink_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: dev_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: off_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: c_long, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: blksize_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: blkcnt_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: time_t, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: c_long, -} From 268e73499652a27eeedd1d3e43430ebcdf1160f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 15:53:00 +0800 Subject: [PATCH 036/163] Impl cygwin rand with getrandom --- library/std/src/sys/random/cygwin.rs | 8 ++++++++ library/std/src/sys/random/linux.rs | 10 +--------- library/std/src/sys/random/mod.rs | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 library/std/src/sys/random/cygwin.rs diff --git a/library/std/src/sys/random/cygwin.rs b/library/std/src/sys/random/cygwin.rs new file mode 100644 index 0000000000000..e6759c8a3ed99 --- /dev/null +++ b/library/std/src/sys/random/cygwin.rs @@ -0,0 +1,8 @@ +pub fn fill_bytes(mut bytes: &mut [u8]) { + while !bytes.is_empty() { + let ret = + unsafe { libc::getrandom(bytes.as_mut_ptr().cast(), bytes.len(), libc::GRND_NONBLOCK) }; + assert!(ret != -1, "failed to generate random data"); + bytes = &mut bytes[ret as usize..]; + } +} diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index fb4274281d63f..e3cb79285cd15 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -94,14 +94,7 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { let flags = if insecure { if GRND_INSECURE_AVAILABLE.load(Relaxed) { - #[cfg(target_os = "cygwin")] - { - libc::GRND_NONBLOCK - } - #[cfg(not(target_os = "cygwin"))] - { - libc::GRND_INSECURE - } + libc::GRND_INSECURE } else { libc::GRND_NONBLOCK } @@ -117,7 +110,6 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { libc::EINTR => continue, // `GRND_INSECURE` is not available, try // `GRND_NONBLOCK`. - #[cfg(not(target_os = "cygwin"))] libc::EINVAL if flags == libc::GRND_INSECURE => { GRND_INSECURE_AVAILABLE.store(false, Relaxed); continue; diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index b6a357e5b07f9..2e5765b8a429c 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -1,11 +1,14 @@ cfg_if::cfg_if! { // Tier 1 - if #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))] { + if #[cfg(any(target_os = "linux", target_os = "android"))] { mod linux; pub use linux::{fill_bytes, hashmap_random_keys}; } else if #[cfg(target_os = "windows")] { mod windows; pub use windows::fill_bytes; + } else if #[cfg(target_os = "cygwin")] { + mod cygwin; + pub use cygwin::fill_bytes; } else if #[cfg(target_vendor = "apple")] { mod apple; pub use apple::fill_bytes; @@ -88,7 +91,6 @@ cfg_if::cfg_if! { target_os = "android", all(target_family = "wasm", target_os = "unknown"), target_os = "xous", - target_os = "cygwin", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; From c3051b1f5a6fa308cab85f37be446e7946e1f22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 15:59:49 +0800 Subject: [PATCH 037/163] Unify cygwin & horizon random impl --- library/std/src/random.rs | 2 +- library/std/src/sys/random/cygwin.rs | 8 -------- .../std/src/sys/random/{horizon.rs => getrandom.rs} | 0 library/std/src/sys/random/mod.rs | 11 ++++------- 4 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 library/std/src/sys/random/cygwin.rs rename library/std/src/sys/random/{horizon.rs => getrandom.rs} (100%) diff --git a/library/std/src/random.rs b/library/std/src/random.rs index 45f51dd37b041..e7d4ab81df0ac 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -37,7 +37,7 @@ use crate::sys::random as sys; /// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html) /// Vita | `arc4random_buf` /// Hermit | `read_entropy` -/// Horizon | `getrandom` shim +/// Horizon, Cygwin | `getrandom` /// AIX, Hurd, L4Re, QNX | `/dev/urandom` /// Redox | `/scheme/rand` /// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html) diff --git a/library/std/src/sys/random/cygwin.rs b/library/std/src/sys/random/cygwin.rs deleted file mode 100644 index e6759c8a3ed99..0000000000000 --- a/library/std/src/sys/random/cygwin.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub fn fill_bytes(mut bytes: &mut [u8]) { - while !bytes.is_empty() { - let ret = - unsafe { libc::getrandom(bytes.as_mut_ptr().cast(), bytes.len(), libc::GRND_NONBLOCK) }; - assert!(ret != -1, "failed to generate random data"); - bytes = &mut bytes[ret as usize..]; - } -} diff --git a/library/std/src/sys/random/horizon.rs b/library/std/src/sys/random/getrandom.rs similarity index 100% rename from library/std/src/sys/random/horizon.rs rename to library/std/src/sys/random/getrandom.rs diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 2e5765b8a429c..7f598c9e5cc3b 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -6,9 +6,6 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "windows")] { mod windows; pub use windows::fill_bytes; - } else if #[cfg(target_os = "cygwin")] { - mod cygwin; - pub use cygwin::fill_bytes; } else if #[cfg(target_vendor = "apple")] { mod apple; pub use apple::fill_bytes; @@ -38,10 +35,10 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "hermit")] { mod hermit; pub use hermit::fill_bytes; - } else if #[cfg(target_os = "horizon")] { - // FIXME: add arc4random_buf to shim-3ds - mod horizon; - pub use horizon::fill_bytes; + } else if #[cfg(any(target_os = "horizon", target_os = "cygwin"))] { + // FIXME(horizon): add arc4random_buf to shim-3ds + mod getrandom; + pub use getrandom::fill_bytes; } else if #[cfg(any( target_os = "aix", target_os = "hurd", From b9fe8def52c996dcb7dd2d7ab3c362854caee8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 21:45:41 +0800 Subject: [PATCH 038/163] Readd os::cygwin::raw as pub(crate) --- library/std/src/os/cygwin/mod.rs | 1 + library/std/src/os/cygwin/raw.rs | 4 ++++ library/std/src/sys/pal/unix/thread.rs | 1 - 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 library/std/src/os/cygwin/raw.rs diff --git a/library/std/src/os/cygwin/mod.rs b/library/std/src/os/cygwin/mod.rs index f6385653d774d..7f6d6a645c855 100644 --- a/library/std/src/os/cygwin/mod.rs +++ b/library/std/src/os/cygwin/mod.rs @@ -1,3 +1,4 @@ //! Cygwin-specific definitions #![stable(feature = "raw_ext", since = "1.1.0")] pub mod fs; +pub(crate) mod raw; diff --git a/library/std/src/os/cygwin/raw.rs b/library/std/src/os/cygwin/raw.rs new file mode 100644 index 0000000000000..2bae1477fcfe1 --- /dev/null +++ b/library/std/src/os/cygwin/raw.rs @@ -0,0 +1,4 @@ +//! Cygwin-specific raw type definitions. + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, pthread_t, time_t}; diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 4397cb69a09e6..8aac58d65a26f 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -344,7 +344,6 @@ impl Drop for Thread { target_os = "illumos", target_os = "vxworks", target_vendor = "apple", - target_os = "cygwin", ))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; From c3c02a517ca1ce8526abf0d1ed4201a888265b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 22:23:39 +0800 Subject: [PATCH 039/163] Use __xpg_strerror_r on cygwin --- library/std/src/sys/pal/unix/os.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 418211d24bb3b..b9a1e60b3dc9b 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -119,7 +119,12 @@ pub fn error_string(errno: i32) -> String { unsafe extern "C" { #[cfg_attr( all( - any(target_os = "linux", target_os = "hurd", target_env = "newlib"), + any( + target_os = "linux", + target_os = "hurd", + target_env = "newlib", + target_os = "cygwin" + ), not(target_env = "ohos") ), link_name = "__xpg_strerror_r" From 9cab8c25dc3c7c1cac7475568161b3b4fc34a88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 7 Mar 2025 22:30:35 +0800 Subject: [PATCH 040/163] Remove stack overflow handler for cygwin --- library/std/src/sys/pal/unix/stack_overflow.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 344f9c63257e8..0ecccdc8812dd 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -32,7 +32,6 @@ impl Drop for Handler { target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "cygwin", target_os = "solaris", target_os = "illumos", ))] @@ -316,8 +315,7 @@ mod imp { target_os = "netbsd", target_os = "hurd", target_os = "linux", - target_os = "l4re", - target_os = "cygwin" + target_os = "l4re" ))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; @@ -372,8 +370,7 @@ mod imp { // this way someone on any unix-y OS can check that all these compile if cfg!(all(target_os = "linux", not(target_env = "musl"))) { install_main_guard_linux(page_size) - } else if cfg!(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin")) - { + } else if cfg!(all(target_os = "linux", target_env = "musl")) { install_main_guard_linux_musl(page_size) } else if cfg!(target_os = "freebsd") { install_main_guard_freebsd(page_size) @@ -513,8 +510,7 @@ mod imp { target_os = "hurd", target_os = "linux", target_os = "netbsd", - target_os = "l4re", - target_os = "cygwin" + target_os = "l4re" ))] // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option> { @@ -587,7 +583,6 @@ mod imp { target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "cygwin", target_os = "solaris", target_os = "illumos", )))] From a9b536f8a41e731b64b98e6c3085f2a7e4614504 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 11 Mar 2025 14:43:21 +0800 Subject: [PATCH 041/163] std: Mention clone-on-write mutation in Arc Signed-off-by: xizheyin --- library/alloc/src/sync.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4999319f618e4..a521c53b6906b 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -84,9 +84,29 @@ macro_rules! acquire { /// /// Shared references in Rust disallow mutation by default, and `Arc` is no /// exception: you cannot generally obtain a mutable reference to something -/// inside an `Arc`. If you need to mutate through an `Arc`, use -/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] -/// types. +/// inside an `Arc`. If you do need to mutate through an `Arc`, you have several options: +/// +/// 1. Use interior mutability with synchronization primitives like [`Mutex`][mutex], +/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types. +/// +/// 2. Use clone-on-write semantics with [`Arc::make_mut`] which provides efficient mutation +/// without requiring interior mutability. This approach clones the data only when +/// needed (when there are multiple references) and can be more efficient when mutations +/// are infrequent. +/// +/// 3. Use [`Arc::get_mut`] when you know your `Arc` is not shared (has a reference count of 1), +/// which provides direct mutable access to the inner value without any cloning. +/// +/// ``` +/// use std::sync::Arc; +/// +/// let mut data = Arc::new(vec![1, 2, 3]); +/// +/// // This will clone the vector only if there are other references to it +/// Arc::make_mut(&mut data).push(4); +/// +/// assert_eq!(*data, vec![1, 2, 3, 4]); +/// ``` /// /// **Note**: This type is only available on platforms that support atomic /// loads and stores of pointers, which includes all platforms that support From 7c0726521f61649d3c2192dd36180b2ac489100b Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 11 Mar 2025 17:16:22 +0000 Subject: [PATCH 042/163] Add `From<{integer}>` for `f16`/`f128` impls --- library/core/src/convert/num.rs | 50 ++++++++++++++++++++++++++++++-- library/std/tests/floats/f128.rs | 31 ++++++++++++++++++++ library/std/tests/floats/f16.rs | 12 ++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 0246d0627cafe..d5cb10a5d1c8b 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -147,22 +147,42 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf // Note: integers can only be represented with full precision in a float if -// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. +// they fit in the significand, which is: +// * 11 bits in f16 +// * 24 bits in f32 +// * 53 bits in f64 +// * 113 bits in f128 // Lossy float conversions are not implemented at this time. +// FIXME(f16_f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference +// `f16`/`f128` when they are stabilised (trait impls have to have a `#[stable]` attribute, but none +// of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). // signed integer -> float +impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. +// impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // unsigned integer -> float +impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. +// impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // float -> float // FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See @@ -174,7 +194,12 @@ impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0 impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); macro_rules! impl_float_from_bool { - ($float:ty) => { + ( + $float:ty $(; + doctest_prefix: $(#[doc = $doctest_prefix:literal])* + doctest_suffix: $(#[doc = $doctest_suffix:literal])* + )? + ) => { #[stable(feature = "float_from_bool", since = "1.68.0")] impl From for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] @@ -182,12 +207,14 @@ macro_rules! impl_float_from_bool { /// /// # Examples /// ``` + $($(#[doc = $doctest_prefix])*)? #[doc = concat!("let x: ", stringify!($float)," = false.into();")] /// assert_eq!(x, 0.0); /// assert!(x.is_sign_positive()); /// #[doc = concat!("let y: ", stringify!($float)," = true.into();")] /// assert_eq!(y, 1.0); + $($(#[doc = $doctest_suffix])*)? /// ``` #[inline] fn from(small: bool) -> Self { @@ -198,8 +225,27 @@ macro_rules! impl_float_from_bool { } // boolean -> float +impl_float_from_bool!( + f16; + doctest_prefix: + // rustdoc doesn't remove the conventional space after the `///` + ///#![feature(f16)] + ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + doctest_suffix: + ///# } +); impl_float_from_bool!(f32); impl_float_from_bool!(f64); +impl_float_from_bool!( + f128; + doctest_prefix: + ///#![feature(f128)] + ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + doctest_suffix: + ///# } +); // no possible bounds violation macro_rules! impl_try_from_unbounded { diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs index d0e8b157e6b6f..b4a6c672bf05f 100644 --- a/library/std/tests/floats/f128.rs +++ b/library/std/tests/floats/f128.rs @@ -983,3 +983,34 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_from() { + assert_eq!(f128::from(false), 0.0); + assert_eq!(f128::from(true), 1.0); + assert_eq!(f128::from(u8::MIN), 0.0); + assert_eq!(f128::from(42_u8), 42.0); + assert_eq!(f128::from(u8::MAX), 255.0); + assert_eq!(f128::from(i8::MIN), -128.0); + assert_eq!(f128::from(42_i8), 42.0); + assert_eq!(f128::from(i8::MAX), 127.0); + assert_eq!(f128::from(u16::MIN), 0.0); + assert_eq!(f128::from(42_u16), 42.0); + assert_eq!(f128::from(u16::MAX), 65535.0); + assert_eq!(f128::from(i16::MIN), -32768.0); + assert_eq!(f128::from(42_i16), 42.0); + assert_eq!(f128::from(i16::MAX), 32767.0); + assert_eq!(f128::from(u32::MIN), 0.0); + assert_eq!(f128::from(42_u32), 42.0); + assert_eq!(f128::from(u32::MAX), 4294967295.0); + assert_eq!(f128::from(i32::MIN), -2147483648.0); + assert_eq!(f128::from(42_i32), 42.0); + assert_eq!(f128::from(i32::MAX), 2147483647.0); + // FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added. + // assert_eq!(f128::from(u64::MIN), 0.0); + // assert_eq!(f128::from(42_u64), 42.0); + // assert_eq!(f128::from(u64::MAX), 18446744073709551615.0); + // assert_eq!(f128::from(i64::MIN), -9223372036854775808.0); + // assert_eq!(f128::from(42_i64), 42.0); + // assert_eq!(f128::from(i64::MAX), 9223372036854775807.0); +} diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 5180f3d40f3a7..727f29e375ba5 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -955,3 +955,15 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_from() { + assert_eq!(f16::from(false), 0.0); + assert_eq!(f16::from(true), 1.0); + assert_eq!(f16::from(u8::MIN), 0.0); + assert_eq!(f16::from(42_u8), 42.0); + assert_eq!(f16::from(u8::MAX), 255.0); + assert_eq!(f16::from(i8::MIN), -128.0); + assert_eq!(f16::from(42_i8), 42.0); + assert_eq!(f16::from(i8::MAX), 127.0); +} From bd385f3064f558d4bba19a0447f8b08208915dc9 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Wed, 12 Mar 2025 15:48:05 +0800 Subject: [PATCH 043/163] Fix panic handler for cygwin --- library/std/src/sys/personality/gcc.rs | 5 ++++- library/unwind/src/libunwind.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index cd2c7899f4bf1..ad96774f39c37 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -248,7 +248,10 @@ cfg_if::cfg_if! { } cfg_if::cfg_if! { - if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] { + if #[cfg(any( + all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"), + target_os = "cygwin", + ))] { /// personality fn called by [Windows Structured Exception Handling][windows-eh] /// /// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH, diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1a640bbde71d7..37668a64857c3 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -27,10 +27,10 @@ pub type _Unwind_Trace_Fn = #[cfg(target_arch = "x86")] pub const unwinder_private_data_size: usize = 5; -#[cfg(all(target_arch = "x86_64", not(target_os = "windows")))] +#[cfg(all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))))] pub const unwinder_private_data_size: usize = 2; -#[cfg(all(target_arch = "x86_64", target_os = "windows"))] +#[cfg(all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")))] pub const unwinder_private_data_size: usize = 6; #[cfg(all(target_arch = "arm", not(target_vendor = "apple")))] @@ -289,7 +289,10 @@ if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = } // cfg_if! cfg_if::cfg_if! { -if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] { +if #[cfg(any( + all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"), + target_os = "cygwin", + ))] { // We declare these as opaque types. This is fine since you just need to // pass them to _GCC_specific_handler and forget about them. pub enum EXCEPTION_RECORD {} From d183da6331addfc69dfb157ef8ffc051ff0508bd Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 12 Mar 2025 08:43:21 -0700 Subject: [PATCH 044/163] Install licenses into `share/doc/rust/licenses` This changes the path from "licences" to "licenses" for consistency across the repo, including the usage directly around this line. This is a US/UK spelling difference, but I believe the US spelling is also more common in open source in general. --- src/bootstrap/src/core/build_steps/dist.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index ec0edeab9968c..15083e0a1a48e 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -519,7 +519,7 @@ impl Step for Rustc { // The REUSE-managed license files let license = |path: &Path| { - builder.install(path, &image.join("share/doc/rust/licences"), 0o644); + builder.install(path, &image.join("share/doc/rust/licenses"), 0o644); }; for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() { license(&entry.path()); From 340a45282ac8a076b0b058ac066a8872d78302b3 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sun, 2 Mar 2025 00:33:51 +1100 Subject: [PATCH 045/163] Stablize feature `anonymous_pipe` Signed-off-by: Jiahao XU --- library/std/src/io/mod.rs | 2 +- library/std/src/io/pipe.rs | 21 ++++++-------- library/std/src/sys/anonymous_pipe/unix.rs | 28 +++++++++---------- .../std/src/sys/anonymous_pipe/unsupported.rs | 4 +-- library/std/src/sys/anonymous_pipe/windows.rs | 28 +++++++++---------- library/std/tests/pipe_subprocess.rs | 2 -- src/tools/miri/tests/pass/shims/pipe.rs | 2 -- 7 files changed, 40 insertions(+), 47 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 7f610bc88bfd7..679549093b398 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -310,7 +310,7 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index 266c7bc96389b..12ac62afb3150 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -40,7 +40,6 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// # Examples /// /// ```no_run -/// #![feature(anonymous_pipe)] /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { @@ -67,19 +66,19 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// ``` /// [changes]: io#platform-specific-behavior /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) } /// Read end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug)] pub struct PipeReader(pub(crate) AnonPipe); /// Write end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug)] pub struct PipeWriter(pub(crate) AnonPipe); @@ -89,7 +88,6 @@ impl PipeReader { /// # Examples /// /// ```no_run - /// #![feature(anonymous_pipe)] /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { @@ -137,7 +135,7 @@ impl PipeReader { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] + #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } @@ -149,7 +147,6 @@ impl PipeWriter { /// # Examples /// /// ```no_run - /// #![feature(anonymous_pipe)] /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { @@ -177,13 +174,13 @@ impl PipeWriter { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] + #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(Self) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl io::Read for &PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -203,7 +200,7 @@ impl io::Read for &PipeReader { } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl io::Read for PipeReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -223,7 +220,7 @@ impl io::Read for PipeReader { } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl io::Write for &PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -241,7 +238,7 @@ impl io::Write for &PipeWriter { } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl io::Write for PipeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs index 9e398765634b7..f5e333d0b1397 100644 --- a/library/std/src/sys/anonymous_pipe/unix.rs +++ b/library/std/src/sys/anonymous_pipe/unix.rs @@ -12,88 +12,88 @@ pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsFd for PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsRawFd for PipeReader { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for OwnedFd { fn from(pipe: PipeReader) -> Self { FileDesc::into_inner(pipe.0) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl FromRawFd for PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl IntoRawFd for PipeReader { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeReader) -> Self { Self::from(OwnedFd::from(pipe)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsFd for PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsRawFd for PipeWriter { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for OwnedFd { fn from(pipe: PipeWriter) -> Self { FileDesc::into_inner(pipe.0) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl FromRawFd for PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl IntoRawFd for PipeWriter { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeWriter) -> Self { Self::from(OwnedFd::from(pipe)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for PipeReader { fn from(owned_fd: OwnedFd) -> Self { Self(FileDesc::from_inner(owned_fd)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for PipeWriter { fn from(owned_fd: OwnedFd) -> Self { Self(FileDesc::from_inner(owned_fd)) diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs index 4e79ac9c21aad..ffd07bf2d863e 100644 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ b/library/std/src/sys/anonymous_pipe/unsupported.rs @@ -7,14 +7,14 @@ pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { Err(io::Error::UNSUPPORTED_PLATFORM) } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeReader) -> Self { pipe.0.diverge() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeWriter) -> Self { pipe.0.diverge() diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs index eb7fa8ec1c9a1..48a2f3994c338 100644 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ b/library/std/src/sys/anonymous_pipe/windows.rs @@ -23,92 +23,92 @@ pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsHandle for PipeReader { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsRawHandle for PipeReader { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl FromRawHandle for PipeReader { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self(Handle::from_raw_handle(raw_handle)) } } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl IntoRawHandle for PipeReader { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for OwnedHandle { fn from(pipe: PipeReader) -> Self { Handle::into_inner(pipe.0) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeReader) -> Self { Self::from(OwnedHandle::from(pipe)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsHandle for PipeWriter { fn as_handle(&self) -> BorrowedHandle<'_> { self.0.as_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl AsRawHandle for PipeWriter { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl FromRawHandle for PipeWriter { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { unsafe { Self(Handle::from_raw_handle(raw_handle)) } } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl IntoRawHandle for PipeWriter { fn into_raw_handle(self) -> RawHandle { self.0.into_raw_handle() } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for OwnedHandle { fn from(pipe: PipeWriter) -> Self { Handle::into_inner(pipe.0) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for Stdio { fn from(pipe: PipeWriter) -> Self { Self::from(OwnedHandle::from(pipe)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for PipeReader { fn from(owned_handle: OwnedHandle) -> Self { Self(Handle::from_inner(owned_handle)) } } -#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] impl From for PipeWriter { fn from(owned_handle: OwnedHandle) -> Self { Self(Handle::from_inner(owned_handle)) diff --git a/library/std/tests/pipe_subprocess.rs b/library/std/tests/pipe_subprocess.rs index 00d99a578d580..c51a4459e718b 100644 --- a/library/std/tests/pipe_subprocess.rs +++ b/library/std/tests/pipe_subprocess.rs @@ -1,5 +1,3 @@ -#![feature(anonymous_pipe)] - fn main() { #[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))] { diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs index 1be29886d2d32..c47feb8774ad1 100644 --- a/src/tools/miri/tests/pass/shims/pipe.rs +++ b/src/tools/miri/tests/pass/shims/pipe.rs @@ -1,7 +1,5 @@ //@ignore-target: windows -#![feature(anonymous_pipe)] - use std::io::{Read, Write, pipe}; fn main() { From 6863a99841f81ea18b9a26d053fd33a9700a8345 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 8 Mar 2025 00:36:15 +1100 Subject: [PATCH 046/163] Mv os-specific trait impl of `Pipe*` into `std::os::*` Signed-off-by: Jiahao XU --- library/std/src/io/pipe.rs | 25 +++++ library/std/src/os/fd/owned.rs | 45 +++++++- library/std/src/os/fd/raw.rs | 43 ++++++++ library/std/src/os/windows/io/handle.rs | 42 ++++++++ library/std/src/os/windows/io/raw.rs | 42 ++++++++ library/std/src/process.rs | 14 +++ library/std/src/sys/anonymous_pipe/unix.rs | 94 +--------------- .../std/src/sys/anonymous_pipe/unsupported.rs | 17 +-- library/std/src/sys/anonymous_pipe/windows.rs | 101 +----------------- .../sys/pal/unix/process/process_common.rs | 6 ++ library/std/src/sys/pal/unsupported/pipe.rs | 51 +++++++++ library/std/src/sys/pal/windows/process.rs | 6 ++ 12 files changed, 278 insertions(+), 208 deletions(-) diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index 12ac62afb3150..cfed9b05cc0c6 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -1,5 +1,6 @@ use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; +use crate::sys_common::{FromInner, IntoInner}; /// Create an anonymous pipe. /// @@ -82,6 +83,30 @@ pub struct PipeReader(pub(crate) AnonPipe); #[derive(Debug)] pub struct PipeWriter(pub(crate) AnonPipe); +impl FromInner for PipeReader { + fn from_inner(inner: AnonPipe) -> Self { + Self(inner) + } +} + +impl IntoInner for PipeReader { + fn into_inner(self) -> AnonPipe { + self.0 + } +} + +impl FromInner for PipeWriter { + fn from_inner(inner: AnonPipe) -> Self { + Self(inner) + } +} + +impl IntoInner for PipeWriter { + fn into_inner(self) -> AnonPipe { + self.0 + } +} + impl PipeReader { /// Create a new [`PipeReader`] instance that shares the same underlying file description. /// diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 701cf82335757..2dcbfc966189d 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -15,8 +15,9 @@ use crate::mem::ManuallyDrop; target_os = "trusty" )))] use crate::sys::cvt; +use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, IntoInner}; use crate::{fmt, io}; type ValidRawFd = core::num::niche_types::NotAllOnes; @@ -504,3 +505,45 @@ impl<'a> AsFd for io::StderrLock<'a> { unsafe { BorrowedFd::borrow_raw(2) } } } + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsFd for io::PipeReader { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedFd { + fn from(pipe: io::PipeReader) -> Self { + pipe.0.into_inner() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsFd for io::PipeWriter { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedFd { + fn from(pipe: io::PipeWriter) -> Self { + pipe.0.into_inner() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeReader { + fn from(owned_fd: OwnedFd) -> Self { + Self(FromInner::from_inner(owned_fd)) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeWriter { + fn from(owned_fd: OwnedFd) -> Self { + Self(FromInner::from_inner(owned_fd)) + } +} diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 083ac6e3fe6b1..596b21a52044b 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -18,6 +18,7 @@ use crate::os::unix::io::AsFd; use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] use crate::os::wasi::io::OwnedFd; +use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] use crate::sys_common::{AsInner, IntoInner}; @@ -284,3 +285,45 @@ impl AsRawFd for Box { (**self).as_raw_fd() } } + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawFd for io::PipeReader { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawFd for io::PipeReader { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawFd for io::PipeReader { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawFd for io::PipeWriter { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawFd for io::PipeWriter { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawFd for io::PipeWriter { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 76f5f549dd244..7f21929b85f99 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -660,3 +660,45 @@ impl From> for OwnedHandle { join_handle.into_inner().into_handle().into_inner() } } + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsHandle for io::PipeReader { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.0.as_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedHandle { + fn from(pipe: io::PipeReader) -> Self { + pipe.into_inner().into_inner() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsHandle for io::PipeWriter { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.0.as_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedHandle { + fn from(pipe: io::PipeWriter) -> Self { + pipe.into_inner().into_inner() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeReader { + fn from(owned_handle: OwnedHandle) -> Self { + Self::from_inner(FromInner::from_inner(owned_handle)) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeWriter { + fn from(owned_handle: OwnedHandle) -> Self { + Self::from_inner(FromInner::from_inner(owned_handle)) + } +} diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index c0517fab95068..bc3e55c862962 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -310,3 +310,45 @@ impl IntoRawSocket for net::UdpSocket { self.into_inner().into_socket().into_inner().into_raw_socket() } } + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawHandle for io::PipeReader { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawHandle for io::PipeReader { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawHandle for io::PipeReader { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawHandle for io::PipeWriter { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawHandle for io::PipeWriter { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawHandle for io::PipeWriter { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 37762c65f6556..07a56010255de 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1659,6 +1659,20 @@ impl From for Stdio { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + fn from(pipe: io::PipeWriter) -> Self { + Stdio::from_inner(pipe.into_inner().into()) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + fn from(pipe: io::PipeReader) -> Self { + Stdio::from_inner(pipe.into_inner().into()) + } +} + /// Describes the result of a process after it has terminated. /// /// This `struct` is used to represent the exit status or other termination of a child process. diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs index f5e333d0b1397..dfe10f7fafe49 100644 --- a/library/std/src/sys/anonymous_pipe/unix.rs +++ b/library/std/src/sys/anonymous_pipe/unix.rs @@ -1,9 +1,7 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::process::Stdio; +use crate::io; use crate::sys::fd::FileDesc; use crate::sys::pipe::anon_pipe; -use crate::sys_common::{FromInner, IntoInner}; +use crate::sys_common::IntoInner; pub type AnonPipe = FileDesc; @@ -11,91 +9,3 @@ pub type AnonPipe = FileDesc; pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) } - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsFd for PipeReader { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsRawFd for PipeReader { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for OwnedFd { - fn from(pipe: PipeReader) -> Self { - FileDesc::into_inner(pipe.0) - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl FromRawFd for PipeReader { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl IntoRawFd for PipeReader { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - Self::from(OwnedFd::from(pipe)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsFd for PipeWriter { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsRawFd for PipeWriter { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for OwnedFd { - fn from(pipe: PipeWriter) -> Self { - FileDesc::into_inner(pipe.0) - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl FromRawFd for PipeWriter { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl IntoRawFd for PipeWriter { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - Self::from(OwnedFd::from(pipe)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for PipeReader { - fn from(owned_fd: OwnedFd) -> Self { - Self(FileDesc::from_inner(owned_fd)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for PipeWriter { - fn from(owned_fd: OwnedFd) -> Self { - Self(FileDesc::from_inner(owned_fd)) - } -} diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs index ffd07bf2d863e..a0805ba9540e0 100644 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ b/library/std/src/sys/anonymous_pipe/unsupported.rs @@ -1,22 +1,7 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::process::Stdio; +use crate::io; pub use crate::sys::pipe::AnonPipe; #[inline] pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { Err(io::Error::UNSUPPORTED_PLATFORM) } - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - pipe.0.diverge() - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - pipe.0.diverge() - } -} diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs index 48a2f3994c338..bdda7ffc5d251 100644 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ b/library/std/src/sys/anonymous_pipe/windows.rs @@ -1,12 +1,7 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::os::windows::io::{ - AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, -}; -use crate::process::Stdio; -use crate::ptr; +use crate::os::windows::io::FromRawHandle; use crate::sys::c; use crate::sys::handle::Handle; -use crate::sys_common::{FromInner, IntoInner}; +use crate::{io, ptr}; pub type AnonPipe = Handle; @@ -22,95 +17,3 @@ pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { unsafe { Ok((Handle::from_raw_handle(read_pipe), Handle::from_raw_handle(write_pipe))) } } } - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsHandle for PipeReader { - fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsRawHandle for PipeReader { - fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl FromRawHandle for PipeReader { - unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self(Handle::from_raw_handle(raw_handle)) } - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl IntoRawHandle for PipeReader { - fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for OwnedHandle { - fn from(pipe: PipeReader) -> Self { - Handle::into_inner(pipe.0) - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - Self::from(OwnedHandle::from(pipe)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsHandle for PipeWriter { - fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl AsRawHandle for PipeWriter { - fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl FromRawHandle for PipeWriter { - unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self(Handle::from_raw_handle(raw_handle)) } - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl IntoRawHandle for PipeWriter { - fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for OwnedHandle { - fn from(pipe: PipeWriter) -> Self { - Handle::into_inner(pipe.0) - } -} -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - Self::from(OwnedHandle::from(pipe)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for PipeReader { - fn from(owned_handle: OwnedHandle) -> Self { - Self(Handle::from_inner(owned_handle)) - } -} - -#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] -impl From for PipeWriter { - fn from(owned_handle: OwnedHandle) -> Self { - Self(Handle::from_inner(owned_handle)) - } -} diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs index 0ea9db211b311..bf037578fd1b5 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/pal/unix/process/process_common.rs @@ -491,6 +491,12 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(fd: FileDesc) -> Stdio { + Stdio::Fd(fd) + } +} + impl From for Stdio { fn from(file: File) -> Stdio { Stdio::Fd(file.into_inner()) diff --git a/library/std/src/sys/pal/unsupported/pipe.rs b/library/std/src/sys/pal/unsupported/pipe.rs index 6799d21a1ff75..988e551de5223 100644 --- a/library/std/src/sys/pal/unsupported/pipe.rs +++ b/library/std/src/sys/pal/unsupported/pipe.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::sys_common::{FromInner, IntoInner}; pub struct AnonPipe(!); @@ -54,3 +55,53 @@ impl AnonPipe { pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { match p1.0 {} } + +impl FromInner for AnonPipe { + fn from_inner(inner: !) -> Self { + inner + } +} + +impl IntoInner for AnonPipe { + fn into_inner(self) -> ! { + self.0 + } +} + +#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))] +mod unix_traits { + use super::AnonPipe; + use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + use crate::sys_common::FromInner; + + impl AsRawFd for AnonPipe { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.0 + } + } + + impl AsFd for AnonPipe { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0 + } + } + + impl IntoRawFd for AnonPipe { + fn into_raw_fd(self) -> RawFd { + self.0 + } + } + + impl FromRawFd for AnonPipe { + unsafe fn from_raw_fd(_: RawFd) -> Self { + panic!("creating pipe on this platform is unsupported!") + } + } + + impl FromInner for AnonPipe { + fn from_inner(_: OwnedFd) -> Self { + panic!("creating pipe on this platform is unsupported!") + } + } +} diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index c57ff355d124d..50e4baba60724 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -621,6 +621,12 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(pipe: Handle) -> Stdio { + Stdio::Handle(pipe) + } +} + impl From for Stdio { fn from(file: File) -> Stdio { Stdio::Handle(file.into_inner()) From 2579bb59a42abf35882f37aaba169c91b4545910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 15:18:58 +0100 Subject: [PATCH 047/163] Fix MCP links --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- src/doc/rustc-dev-guide/src/implementing_new_features.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 9817326f07ba9..09a7f912b9886 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -81,7 +81,7 @@ smaller user-facing changes. into a PR that ends up not getting merged!** [See this document][mcpinfo] for more info on MCPs. -[mcpinfo]: https://forge.rust-lang.org/compiler/mcp.html +[mcpinfo]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#how-do-i-submit-an-mcp [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler ### Performance diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md index fda38ef4fc01a..d7561bbbad22a 100644 --- a/src/doc/rustc-dev-guide/src/implementing_new_features.md +++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md @@ -44,7 +44,7 @@ like this; for example, the compiler team recommends filing a Major Change Proposal ([MCP][mcp]) as a lightweight way to garner support and feedback without requiring full consensus. -[mcp]: https://forge.rust-lang.org/compiler/mcp.html#public-facing-changes-require-rfcbot-fcp +[mcp]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#how-do-i-submit-an-mcp You don't need to have the implementation fully ready for r+ to propose an FCP, but it is generally a good idea to have at least a proof From 3ca5220114c1e690d876aa46c3aa0f6ec594b9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 7 Mar 2024 06:47:08 +0100 Subject: [PATCH 048/163] Represent diagnostic side effects as dep nodes --- compiler/rustc_interface/src/callbacks.rs | 5 +- .../rustc_middle/src/dep_graph/dep_node.rs | 1 + compiler/rustc_middle/src/dep_graph/mod.rs | 1 + .../rustc_middle/src/query/on_disk_cache.rs | 20 +--- compiler/rustc_middle/src/ty/context/tls.rs | 16 +-- compiler/rustc_query_impl/src/plumbing.rs | 48 ++++---- .../src/dep_graph/dep_node.rs | 5 +- .../rustc_query_system/src/dep_graph/graph.rs | 105 +++++++++++------- .../rustc_query_system/src/dep_graph/mod.rs | 12 +- compiler/rustc_query_system/src/query/mod.rs | 45 ++------ .../rustc_query_system/src/query/plumbing.rs | 60 ++++------ 11 files changed, 138 insertions(+), 180 deletions(-) diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index f66b9eb3a2856..7c6b7157f71a5 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -14,6 +14,7 @@ use std::fmt; use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC}; use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_query_impl::QueryCtxt; use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode}; @@ -41,9 +42,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { fn track_diagnostic(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { tls::with_context_opt(|icx| { if let Some(icx) = icx { - if let Some(diagnostics) = icx.diagnostics { - diagnostics.lock().extend(Some(diagnostic.clone())); - } + icx.tcx.dep_graph.record_diagnostic(QueryCtxt::new(icx.tcx), &diagnostic); // Diagnostics are tracked, we can ignore the dependency. let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() }; diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 7525aeb922729..f967d8b92c71c 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -79,6 +79,7 @@ rustc_query_append!(define_dep_nodes![ [] fn Null() -> (), /// We use this to create a forever-red node. [] fn Red() -> (), + [] fn SideEffect() -> (), [] fn TraitSelect() -> (), [] fn CompileCodegenUnit() -> (), [] fn CompileMonoItem() -> (), diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 2090c3e6da6fa..c927538b4cf37 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -46,6 +46,7 @@ impl Deps for DepsType { const DEP_KIND_NULL: DepKind = dep_kinds::Null; const DEP_KIND_RED: DepKind = dep_kinds::Red; + const DEP_KIND_SIDE_EFFECT: DepKind = dep_kinds::SideEffect; const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1; } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index d9035efaf56d0..b4c5d1c6c0558 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -357,11 +357,10 @@ impl OnDiskCache { &self, tcx: TyCtxt<'_>, dep_node_index: SerializedDepNodeIndex, - ) -> QuerySideEffects { + ) -> Option { let side_effects: Option = self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index); - - side_effects.unwrap_or_default() + side_effects } /// Stores a `QuerySideEffects` emitted during the current compilation session. @@ -395,21 +394,6 @@ impl OnDiskCache { opt_value } - /// Stores side effect emitted during computation of an anonymous query. - /// Since many anonymous queries can share the same `DepNode`, we aggregate - /// them -- as opposed to regular queries where we assume that there is a - /// 1:1 relationship between query-key and `DepNode`. - pub fn store_side_effects_for_anon_node( - &self, - dep_node_index: DepNodeIndex, - side_effects: QuerySideEffects, - ) { - let mut current_side_effects = self.current_side_effects.borrow_mut(); - - let x = current_side_effects.entry(dep_node_index).or_default(); - x.append(side_effects); - } - fn load_indexed<'tcx, T>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index eaab8474dd20c..5fc80bc793673 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -1,8 +1,6 @@ use std::{mem, ptr}; -use rustc_data_structures::sync::{self, Lock}; -use rustc_errors::DiagInner; -use thin_vec::ThinVec; +use rustc_data_structures::sync; use super::{GlobalCtxt, TyCtxt}; use crate::dep_graph::TaskDepsRef; @@ -22,10 +20,6 @@ pub struct ImplicitCtxt<'a, 'tcx> { /// `ty::query::plumbing` when executing a query. pub query: Option, - /// Where to store diagnostics for the current query job, if any. - /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. - pub diagnostics: Option<&'a Lock>>, - /// Used to prevent queries from calling too deeply. pub query_depth: usize, @@ -37,13 +31,7 @@ pub struct ImplicitCtxt<'a, 'tcx> { impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { let tcx = TyCtxt { gcx }; - ImplicitCtxt { - tcx, - query: None, - diagnostics: None, - query_depth: 0, - task_deps: TaskDepsRef::Ignore, - } + ImplicitCtxt { tcx, query: None, query_depth: 0, task_deps: TaskDepsRef::Ignore } } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f98d6421307ad..47158f6d7aaf7 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -5,9 +5,7 @@ use std::num::NonZero; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lock; use rustc_data_structures::unord::UnordMap; -use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_index::Idx; use rustc_middle::bug; @@ -32,7 +30,6 @@ use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; -use thin_vec::ThinVec; use crate::QueryConfigRestored; @@ -92,12 +89,14 @@ impl QueryContext for QueryCtxt<'_> { } // Interactions with on_disk_cache - fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects { + fn load_side_effects( + self, + prev_dep_node_index: SerializedDepNodeIndex, + ) -> Option { self.query_system .on_disk_cache .as_ref() - .map(|c| c.load_side_effects(self.tcx, prev_dep_node_index)) - .unwrap_or_default() + .and_then(|c| c.load_side_effects(self.tcx, prev_dep_node_index)) } #[inline(never)] @@ -108,27 +107,13 @@ impl QueryContext for QueryCtxt<'_> { } } - #[inline(never)] - #[cold] - fn store_side_effects_for_anon_node( - self, - dep_node_index: DepNodeIndex, - side_effects: QuerySideEffects, - ) { - if let Some(c) = self.query_system.on_disk_cache.as_ref() { - c.store_side_effects_for_anon_node(dep_node_index, side_effects) - } - } - /// Executes a job by changing the `ImplicitCtxt` to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. + /// new query job while it executes. #[inline(always)] fn start_query( self, token: QueryJobId, depth_limit: bool, - diagnostics: Option<&Lock>>, compute: impl FnOnce() -> R, ) -> R { // The `TyCtxt` stored in TLS has the same global interner lifetime @@ -143,7 +128,6 @@ impl QueryContext for QueryCtxt<'_> { let new_icx = ImplicitCtxt { tcx: self.tcx, query: Some(token), - diagnostics, query_depth: current_icx.query_depth + depth_limit as usize, task_deps: current_icx.task_deps, }; @@ -500,7 +484,7 @@ where is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(|tcx, dep_node| { + force_from_dep_node: Some(|tcx, dep_node, _| { force_from_dep_node(Q::config(tcx), tcx, dep_node) }), try_load_from_on_disk_cache: Some(|tcx, dep_node| { @@ -802,7 +786,7 @@ macro_rules! define_queries { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, - force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), + force_from_dep_node: Some(|_, dep_node, _| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, name: &"Null", } @@ -814,12 +798,26 @@ macro_rules! define_queries { is_anon: false, is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, - force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), + force_from_dep_node: Some(|_, dep_node, _| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, name: &"Red", } } + pub(crate) fn SideEffect<'tcx>() -> DepKindStruct<'tcx> { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: Some(|tcx, _, prev_index| { + tcx.dep_graph.force_diagnostic_node(QueryCtxt::new(tcx), prev_index); + true + }), + try_load_from_on_disk_cache: None, + name: &"SideEffect", + } + } + pub(crate) fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: true, diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 9d3368607a21c..c0b3bd43e25a6 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -64,7 +64,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, use rustc_hir::definitions::DefPathHash; use rustc_macros::{Decodable, Encodable}; -use super::{DepContext, FingerprintStyle}; +use super::{DepContext, FingerprintStyle, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; /// This serves as an index into arrays built by `make_dep_kind_array`. @@ -275,7 +275,8 @@ pub struct DepKindStruct { /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// is actually a `DefPathHash`, and can therefore just look up the corresponding /// `DefId` in `tcx.def_path_hash_to_def_id`. - pub force_from_dep_node: Option bool>, + pub force_from_dep_node: + Option bool>, /// Invoke a query to put the on-disk cached value in memory. pub try_load_from_on_disk_cache: Option, diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 3109d53cd2caa..de681328bcb51 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -5,13 +5,14 @@ use std::marker::PhantomData; use std::sync::Arc; use std::sync::atomic::{AtomicU32, Ordering}; -use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef}; use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_data_structures::unord::UnordMap; +use rustc_errors::DiagInner; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -91,8 +92,6 @@ pub(crate) struct DepGraphData { colors: DepNodeColorMap, - processed_side_effects: Lock>, - /// When we load, there may be `.o` files, cached MIR, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into @@ -174,7 +173,6 @@ impl DepGraph { previous_work_products: prev_work_products, dep_node_debug: Default::default(), current, - processed_side_effects: Default::default(), previous: prev_graph, colors, debug_loaded_from_disk: Default::default(), @@ -535,6 +533,24 @@ impl DepGraph { } } + #[inline] + pub fn record_diagnostic(&self, qcx: Qcx, diagnostic: &DiagInner) { + if let Some(ref data) = self.data { + self.read_index(data.encode_diagnostic(qcx, diagnostic)); + } + } + + #[inline] + pub fn force_diagnostic_node( + &self, + qcx: Qcx, + prev_index: SerializedDepNodeIndex, + ) { + if let Some(ref data) = self.data { + data.force_diagnostic_node(qcx, prev_index); + } + } + /// Create a node when we force-feed a value into the query cache. /// This is used to remove cycles during type-checking const generic parameters. /// @@ -656,6 +672,48 @@ impl DepGraphData { pub(crate) fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) { self.debug_loaded_from_disk.lock().insert(dep_node); } + + #[inline] + fn encode_diagnostic( + &self, + qcx: Qcx, + diagnostic: &DiagInner, + ) -> DepNodeIndex { + let dep_node_index = self.current.encoder.send( + DepNode { + kind: D::DEP_KIND_SIDE_EFFECT, + hash: PackedFingerprint::from(Fingerprint::ZERO), + }, + Fingerprint::ZERO, + // We want the side effect node to always be red so it will be forced and emit the + // diagnostic. + std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), + ); + let side_effects = QuerySideEffects { diagnostic: diagnostic.clone() }; + qcx.store_side_effects(dep_node_index, side_effects); + dep_node_index + } + + #[inline] + fn force_diagnostic_node( + &self, + qcx: Qcx, + prev_index: SerializedDepNodeIndex, + ) { + D::with_deps(TaskDepsRef::Ignore, || { + let side_effects = qcx.load_side_effects(prev_index).unwrap(); + + qcx.dep_context().sess().dcx().emit_diagnostic(side_effects.diagnostic.clone()); + + // Promote the previous diagnostics to the current session. + let index = self.current.promote_node_and_deps_to_current(&self.previous, prev_index); + // FIXME: Can this race with a parallel compiler? + qcx.store_side_effects(index, side_effects); + + // Mark the node as green. + self.colors.insert(prev_index, DepNodeColor::Green(index)); + }) + } } impl DepGraph { @@ -794,7 +852,7 @@ impl DepGraphData { // We failed to mark it green, so we try to force the query. debug!("trying to force dependency {dep_dep_node:?}"); - if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, frame) { + if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, parent_dep_node_index, frame) { // The DepNode could not be forced. debug!("dependency {dep_dep_node:?} could not be forced"); return None; @@ -867,16 +925,6 @@ impl DepGraphData { // ... emitting any stored diagnostic ... - // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere - // Maybe store a list on disk and encode this fact in the DepNodeState - let side_effects = qcx.load_side_effects(prev_dep_node_index); - - if side_effects.maybe_any() { - qcx.dep_context().dep_graph().with_query_deserialization(|| { - self.emit_side_effects(qcx, dep_node_index, side_effects) - }); - } - // ... and finally storing a "Green" entry in the color map. // Multiple threads can all write the same color here self.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); @@ -884,33 +932,6 @@ impl DepGraphData { debug!("successfully marked {dep_node:?} as green"); Some(dep_node_index) } - - /// Atomically emits some loaded diagnostics. - /// This may be called concurrently on multiple threads for the same dep node. - #[cold] - #[inline(never)] - fn emit_side_effects>( - &self, - qcx: Qcx, - dep_node_index: DepNodeIndex, - side_effects: QuerySideEffects, - ) { - let mut processed = self.processed_side_effects.lock(); - - if processed.insert(dep_node_index) { - // We were the first to insert the node in the set so this thread - // must process side effects - - // Promote the previous diagnostics to the current session. - qcx.store_side_effects(dep_node_index, side_effects.clone()); - - let dcx = qcx.dep_context().sess().dcx(); - - for diagnostic in side_effects.diagnostics { - dcx.emit_diagnostic(diagnostic); - } - } - } } impl DepGraph { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index e564ae0cec7a8..e3d64d1c0f802 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -58,10 +58,15 @@ pub trait DepContext: Copy { /// dep-node or when the query kind outright does not support it. #[inline] #[instrument(skip(self, frame), level = "debug")] - fn try_force_from_dep_node(self, dep_node: DepNode, frame: Option<&MarkFrame<'_>>) -> bool { + fn try_force_from_dep_node( + self, + dep_node: DepNode, + prev_index: SerializedDepNodeIndex, + frame: Option<&MarkFrame<'_>>, + ) -> bool { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.force_from_dep_node { - match panic::catch_unwind(panic::AssertUnwindSafe(|| f(self, dep_node))) { + match panic::catch_unwind(panic::AssertUnwindSafe(|| f(self, dep_node, prev_index))) { Err(value) => { if !value.is::() { print_markframe_trace(self.dep_graph(), frame); @@ -101,6 +106,9 @@ pub trait Deps { /// We use this to create a forever-red node. const DEP_KIND_RED: DepKind; + /// We use this to create a side effect node. + const DEP_KIND_SIDE_EFFECT: DepKind; + /// This is the highest value a `DepKind` can have. It's used during encoding to /// pack information into the unused bits. const DEP_KIND_MAX: u16; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 7490a3f35032e..ad246b3e8b10d 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -11,14 +11,12 @@ mod caches; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; -use rustc_data_structures::sync::Lock; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::def_id::DefId; -use thin_vec::ThinVec; pub use self::config::{HashResult, QueryConfig}; use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; @@ -70,27 +68,12 @@ impl QueryStackFrame { /// This allows us to 'replay' changes to global state /// that would otherwise only occur if we actually /// executed the query method. -#[derive(Debug, Clone, Default, Encodable, Decodable)] +#[derive(Debug, Encodable, Decodable)] pub struct QuerySideEffects { /// Stores any diagnostics emitted during query execution. /// These diagnostics will be re-emitted if we mark /// the query as green. - pub(super) diagnostics: ThinVec, -} - -impl QuerySideEffects { - /// Returns true if there might be side effects. - #[inline] - pub fn maybe_any(&self) -> bool { - let QuerySideEffects { diagnostics } = self; - // Use `has_capacity` so that the destructor for `self.diagnostics` can be skipped - // if `maybe_any` is known to be false. - diagnostics.has_capacity() - } - pub fn append(&mut self, other: QuerySideEffects) { - let QuerySideEffects { diagnostics } = self; - diagnostics.extend(other.diagnostics); - } + pub(super) diagnostic: DiagInner, } pub trait QueryContext: HasDepContext { @@ -102,28 +85,18 @@ pub trait QueryContext: HasDepContext { fn collect_active_jobs(self) -> QueryMap; /// Load side effects associated to the node in the previous session. - fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; + fn load_side_effects( + self, + prev_dep_node_index: SerializedDepNodeIndex, + ) -> Option; /// Register diagnostics for the given node, for use in next session. fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects); - /// Register diagnostics for the given node, for use in next session. - fn store_side_effects_for_anon_node( - self, - dep_node_index: DepNodeIndex, - side_effects: QuerySideEffects, - ); - /// Executes a job by changing the `ImplicitCtxt` to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - fn start_query( - self, - token: QueryJobId, - depth_limit: bool, - diagnostics: Option<&Lock>>, - compute: impl FnOnce() -> R, - ) -> R; + /// new query job while it executes. + fn start_query(self, token: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R) + -> R; fn depth_limit_error(self, job: QueryJobId); } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 18aae8c00b247..7578cb5e2aebd 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -12,11 +12,9 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::Sharded; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lock; use rustc_data_structures::{outline, sync}; use rustc_errors::{Diag, FatalError, StashKey}; use rustc_span::{DUMMY_SP, Span}; -use thin_vec::ThinVec; use tracing::instrument; use super::QueryConfig; @@ -25,9 +23,7 @@ use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeP use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle}; -use crate::query::{ - QueryContext, QueryMap, QuerySideEffects, QueryStackFrame, SerializedDepNodeIndex, -}; +use crate::query::{QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex}; pub struct QueryState { active: Sharded>, @@ -470,7 +466,7 @@ where } let prof_timer = qcx.dep_context().profiler().query_provider(); - let result = qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key)); + let result = qcx.start_query(job_id, query.depth_limit(), || query.compute(qcx, key)); let dep_node_index = qcx.dep_context().dep_graph().next_virtual_depnode_index(); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); @@ -507,7 +503,7 @@ where // The diagnostics for this query will be promoted to the current session during // `try_mark_green()`, so we can ignore them here. - if let Some(ret) = qcx.start_query(job_id, false, None, || { + if let Some(ret) = qcx.start_query(job_id, false, || { try_load_from_disk_and_cache_in_memory(query, dep_graph_data, qcx, &key, dep_node) }) { return ret; @@ -515,43 +511,31 @@ where } let prof_timer = qcx.dep_context().profiler().query_provider(); - let diagnostics = Lock::new(ThinVec::new()); - let (result, dep_node_index) = - qcx.start_query(job_id, query.depth_limit(), Some(&diagnostics), || { - if query.anon() { - return dep_graph_data.with_anon_task_inner( - *qcx.dep_context(), - query.dep_kind(), - || query.compute(qcx, key), - ); - } + let (result, dep_node_index) = qcx.start_query(job_id, query.depth_limit(), || { + if query.anon() { + return dep_graph_data.with_anon_task_inner( + *qcx.dep_context(), + query.dep_kind(), + || query.compute(qcx, key), + ); + } - // `to_dep_node` is expensive for some `DepKind`s. - let dep_node = - dep_node_opt.unwrap_or_else(|| query.construct_dep_node(*qcx.dep_context(), &key)); + // `to_dep_node` is expensive for some `DepKind`s. + let dep_node = + dep_node_opt.unwrap_or_else(|| query.construct_dep_node(*qcx.dep_context(), &key)); - dep_graph_data.with_task( - dep_node, - (qcx, query), - key, - |(qcx, query), key| query.compute(qcx, key), - query.hash_result(), - ) - }); + dep_graph_data.with_task( + dep_node, + (qcx, query), + key, + |(qcx, query), key| query.compute(qcx, key), + query.hash_result(), + ) + }); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - let side_effects = QuerySideEffects { diagnostics: diagnostics.into_inner() }; - - if std::intrinsics::unlikely(side_effects.maybe_any()) { - if query.anon() { - qcx.store_side_effects_for_anon_node(dep_node_index, side_effects); - } else { - qcx.store_side_effects(dep_node_index, side_effects); - } - } - (result, dep_node_index) } From 453b51a65ab00939d2dce3de24ce38489b5c7eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 14 Mar 2025 18:36:30 +0100 Subject: [PATCH 049/163] Rename `QuerySideEffects` to `QuerySideEffect` --- .../rustc_middle/src/query/on_disk_cache.rs | 30 +++++++++---------- compiler/rustc_query_impl/src/plumbing.rs | 12 ++++---- .../rustc_query_system/src/dep_graph/graph.rs | 16 ++++++---- compiler/rustc_query_system/src/query/mod.rs | 26 +++++++++------- compiler/rustc_session/src/options.rs | 2 +- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index b4c5d1c6c0558..ec5f8f619fe76 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, Stab use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; use rustc_macros::{Decodable, Encodable}; -use rustc_query_system::query::QuerySideEffects; +use rustc_query_system::query::QuerySideEffect; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; @@ -55,9 +55,9 @@ pub struct OnDiskCache { // The complete cache data in serialized form. serialized_data: RwLock>, - // Collects all `QuerySideEffects` created during the current compilation + // Collects all `QuerySideEffect` created during the current compilation // session. - current_side_effects: Lock>, + current_side_effects: Lock>, file_index_to_stable_id: FxHashMap, @@ -68,7 +68,7 @@ pub struct OnDiskCache { // `serialized_data`. query_result_index: FxHashMap, - // A map from dep-node to the position of any associated `QuerySideEffects` in + // A map from dep-node to the position of any associated `QuerySideEffect` in // `serialized_data`. prev_side_effects_index: FxHashMap, @@ -270,10 +270,10 @@ impl OnDiskCache { .current_side_effects .borrow() .iter() - .map(|(dep_node_index, side_effects)| { + .map(|(dep_node_index, side_effect)| { let pos = AbsoluteBytePos::new(encoder.position()); let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); - encoder.encode_tagged(dep_node_index, side_effects); + encoder.encode_tagged(dep_node_index, side_effect); (dep_node_index, pos) }) @@ -352,23 +352,23 @@ impl OnDiskCache { }) } - /// Loads a `QuerySideEffects` created during the previous compilation session. - pub fn load_side_effects( + /// Loads a `QuerySideEffect` created during the previous compilation session. + pub fn load_side_effect( &self, tcx: TyCtxt<'_>, dep_node_index: SerializedDepNodeIndex, - ) -> Option { - let side_effects: Option = + ) -> Option { + let side_effect: Option = self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index); - side_effects + side_effect } - /// Stores a `QuerySideEffects` emitted during the current compilation session. - /// Anything stored like this will be available via `load_side_effects` in + /// Stores a `QuerySideEffect` emitted during the current compilation session. + /// Anything stored like this will be available via `load_side_effect` in /// the next compilation session. - pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) { + pub fn store_side_effect(&self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) { let mut current_side_effects = self.current_side_effects.borrow_mut(); - let prev = current_side_effects.insert(dep_node_index, side_effects); + let prev = current_side_effects.insert(dep_node_index, side_effect); debug_assert!(prev.is_none()); } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 47158f6d7aaf7..e11bd6437d7b8 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{self, TyCtxt, TyEncoder}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame, + QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackFrame, force_query, }; use rustc_query_system::{QueryOverflow, QueryOverflowNote}; @@ -89,21 +89,21 @@ impl QueryContext for QueryCtxt<'_> { } // Interactions with on_disk_cache - fn load_side_effects( + fn load_side_effect( self, prev_dep_node_index: SerializedDepNodeIndex, - ) -> Option { + ) -> Option { self.query_system .on_disk_cache .as_ref() - .and_then(|c| c.load_side_effects(self.tcx, prev_dep_node_index)) + .and_then(|c| c.load_side_effect(self.tcx, prev_dep_node_index)) } #[inline(never)] #[cold] - fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) { + fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) { if let Some(c) = self.query_system.on_disk_cache.as_ref() { - c.store_side_effects(dep_node_index, side_effects) + c.store_side_effect(dep_node_index, side_effect) } } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index de681328bcb51..dbc7f034a6eb0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -25,7 +25,7 @@ use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId}; use crate::dep_graph::edges::EdgesVec; use crate::ich::StableHashingContext; -use crate::query::{QueryContext, QuerySideEffects}; +use crate::query::{QueryContext, QuerySideEffect}; #[derive(Clone)] pub struct DepGraph { @@ -689,8 +689,8 @@ impl DepGraphData { // diagnostic. std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), ); - let side_effects = QuerySideEffects { diagnostic: diagnostic.clone() }; - qcx.store_side_effects(dep_node_index, side_effects); + let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone()); + qcx.store_side_effect(dep_node_index, side_effect); dep_node_index } @@ -701,14 +701,18 @@ impl DepGraphData { prev_index: SerializedDepNodeIndex, ) { D::with_deps(TaskDepsRef::Ignore, || { - let side_effects = qcx.load_side_effects(prev_index).unwrap(); + let side_effect = qcx.load_side_effect(prev_index).unwrap(); - qcx.dep_context().sess().dcx().emit_diagnostic(side_effects.diagnostic.clone()); + match &side_effect { + QuerySideEffect::Diagnostic(diagnostic) => { + qcx.dep_context().sess().dcx().emit_diagnostic(diagnostic.clone()); + } + } // Promote the previous diagnostics to the current session. let index = self.current.promote_node_and_deps_to_current(&self.previous, prev_index); // FIXME: Can this race with a parallel compiler? - qcx.store_side_effects(index, side_effects); + qcx.store_side_effect(index, side_effect); // Mark the node as green. self.colors.insert(prev_index, DepNodeColor::Green(index)); diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ad246b3e8b10d..2ed0c810b7516 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -62,18 +62,22 @@ impl QueryStackFrame { } } -/// Tracks 'side effects' for a particular query. +/// Track a 'side effects' for a particular query. /// This struct is saved to disk along with the query result, /// and loaded from disk if we mark the query as green. /// This allows us to 'replay' changes to global state /// that would otherwise only occur if we actually /// executed the query method. +/// +/// Each side effect gets an unique dep node index which is added +/// as a dependency of the query which had the effect. #[derive(Debug, Encodable, Decodable)] -pub struct QuerySideEffects { - /// Stores any diagnostics emitted during query execution. - /// These diagnostics will be re-emitted if we mark - /// the query as green. - pub(super) diagnostic: DiagInner, +pub enum QuerySideEffect { + /// Stores a diagnostic emitted during query execution. + /// This diagnostic will be re-emitted if we mark + /// the query as green, as that query will have the side + /// effect dep node as a dependency. + Diagnostic(DiagInner), } pub trait QueryContext: HasDepContext { @@ -84,14 +88,14 @@ pub trait QueryContext: HasDepContext { fn collect_active_jobs(self) -> QueryMap; - /// Load side effects associated to the node in the previous session. - fn load_side_effects( + /// Load a side effect associated to the node in the previous session. + fn load_side_effect( self, prev_dep_node_index: SerializedDepNodeIndex, - ) -> Option; + ) -> Option; - /// Register diagnostics for the given node, for use in next session. - fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects); + /// Register a side effect for the given node, for use in next session. + fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect); /// Executes a job by changing the `ImplicitCtxt` to point to the /// new query job while it executes. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 804b46a9bec41..8d05cd14e3820 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2525,7 +2525,7 @@ written to standard error output)"), "for every macro invocation, print its name and arguments (default: no)"), track_diagnostics: bool = (false, parse_bool, [UNTRACKED], "tracks where in rustc a diagnostic was emitted"), - // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved + // Diagnostics are considered side-effects of a query (see `QuerySideEffect`) and are saved // alongside query results and changes to translation options can affect diagnostics - so // translation options should be tracked. translate_additional_ftl: Option = (None, parse_opt_pathbuf, [TRACKED], From 9a847b1ea59090d9633a8dca75510cbe91589c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 14 Mar 2025 18:55:02 +0100 Subject: [PATCH 050/163] Add comments --- compiler/rustc_query_system/src/dep_graph/graph.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index dbc7f034a6eb0..985ca64903457 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -533,6 +533,8 @@ impl DepGraph { } } + /// This encodes a diagnostic by creating a node with an unique index and assoicating + /// `diagnostic` with it, for use in the next session. #[inline] pub fn record_diagnostic(&self, qcx: Qcx, diagnostic: &DiagInner) { if let Some(ref data) = self.data { @@ -540,6 +542,8 @@ impl DepGraph { } } + /// This forces a diagnostic node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_diagnostic` in the previous session. #[inline] pub fn force_diagnostic_node( &self, @@ -673,12 +677,15 @@ impl DepGraphData { self.debug_loaded_from_disk.lock().insert(dep_node); } + /// This encodes a diagnostic by creating a node with an unique index and assoicating + /// `diagnostic` with it, for use in the next session. #[inline] fn encode_diagnostic( &self, qcx: Qcx, diagnostic: &DiagInner, ) -> DepNodeIndex { + // Use `send` so we get an unique index, even though the dep node is not. let dep_node_index = self.current.encoder.send( DepNode { kind: D::DEP_KIND_SIDE_EFFECT, @@ -694,6 +701,8 @@ impl DepGraphData { dep_node_index } + /// This forces a diagnostic node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_diagnostic` in the previous session. #[inline] fn force_diagnostic_node( &self, From 50c659fcba19f6d51d465815cadcea00d8abb02b Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 14 Mar 2025 17:30:47 +0100 Subject: [PATCH 051/163] Clarify "owned data" in E0515.md This clarifies the explanation of why this is not allowed and also what to do instead. Fixes 62071 PS There was suggestion of adding a link to the book. I did not yet do that, but if desired that could be added. --- compiler/rustc_error_codes/src/error_codes/E0515.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0515.md b/compiler/rustc_error_codes/src/error_codes/E0515.md index 0f4fbf672239c..87bbe4aea705f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0515.md +++ b/compiler/rustc_error_codes/src/error_codes/E0515.md @@ -17,10 +17,13 @@ fn get_dangling_iterator<'a>() -> Iter<'a, i32> { } ``` -Local variables, function parameters and temporaries are all dropped before the -end of the function body. So a reference to them cannot be returned. +Local variables, function parameters and temporaries are all dropped before +the end of the function body. A returned reference (or struct containing a +reference) to such a dropped value would immediately be invalid. Therefore +it is not allowed to return such a reference. -Consider returning an owned value instead: +Consider returning a value that takes ownership of local data instead of +referencing it: ``` use std::vec::IntoIter; From ae4a4794e75a9317fa9f907dc38ecb177e46c663 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Mar 2025 20:04:17 +0000 Subject: [PATCH 052/163] Improve upvar analysis for deref of child capture --- compiler/rustc_hir_typeck/src/upvar.rs | 25 +++++++--- .../async-closures/imm-deref-lending.rs | 46 +++++++++++++++++ .../async-closures/imm-deref-not-lending.rs | 49 +++++++++++++++++++ .../imm-deref-not-lending.stderr | 14 ++++++ 4 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 tests/ui/async-await/async-closures/imm-deref-lending.rs create mode 100644 tests/ui/async-await/async-closures/imm-deref-not-lending.rs create mode 100644 tests/ui/async-await/async-closures/imm-deref-not-lending.stderr diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 37f3786c00abc..fc98a603dd852 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1862,8 +1862,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// (1.) Are we borrowing data owned by the parent closure? We can determine if /// that is the case by checking if the parent capture is by move, EXCEPT if we -/// apply a deref projection, which means we're reborrowing a reference that we -/// captured by move. +/// apply a deref projection of an immutable reference, reborrows of immutable +/// references which aren't restricted to the LUB of the lifetimes of the deref +/// chain. This is why `&'short mut &'long T` can be reborrowed as `&'long T`. /// /// ```rust /// let x = &1i32; // Let's call this lifetime `'1`. @@ -1902,10 +1903,22 @@ fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>( ) -> bool { // (1.) (!parent_capture.is_by_ref() - && !matches!( - child_capture.place.projections.get(parent_capture.place.projections.len()), - Some(Projection { kind: ProjectionKind::Deref, .. }) - )) + // This is just inlined `place.deref_tys()` but truncated to just + // the child projections. Namely, look for a `&T` deref, since we + // can always extend `&'short mut &'long T` to `&'long T`. + && !child_capture + .place + .projections + .iter() + .enumerate() + .skip(parent_capture.place.projections.len()) + .any(|(idx, proj)| { + matches!(proj.kind, ProjectionKind::Deref) + && matches!( + child_capture.place.ty_before_projection(idx).kind(), + ty::Ref(.., ty::Mutability::Not) + ) + })) // (2.) || matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::Mutable)) } diff --git a/tests/ui/async-await/async-closures/imm-deref-lending.rs b/tests/ui/async-await/async-closures/imm-deref-lending.rs new file mode 100644 index 0000000000000..59f8d434d9cc0 --- /dev/null +++ b/tests/ui/async-await/async-closures/imm-deref-lending.rs @@ -0,0 +1,46 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(impl_trait_in_bindings)] + +struct FooS { + precise: i32, +} + +fn ref_inside_mut(f: &mut &FooS) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn mut_inside_ref(f: &&mut FooS) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn mut_ref_inside_mut(f: &mut &mut FooS) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn ref_inside_box(f: Box<&FooS>) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn box_inside_ref(f: &Box) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn box_inside_box(f: Box>) { + let x: impl AsyncFn() = async move || { + let y = &f.precise; + }; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/imm-deref-not-lending.rs b/tests/ui/async-await/async-closures/imm-deref-not-lending.rs new file mode 100644 index 0000000000000..bd1197cc63654 --- /dev/null +++ b/tests/ui/async-await/async-closures/imm-deref-not-lending.rs @@ -0,0 +1,49 @@ +//@ edition: 2021 + +#![feature(impl_trait_in_bindings)] + +struct FooS { + precise: i32, +} + +fn ref_inside_mut(f: &mut &FooS) { + let x: impl Fn() -> _ = async move || { + let y = &f.precise; + }; +} + +fn mut_inside_ref(f: &&mut FooS) { + let x: impl Fn() -> _ = async move || { + let y = &f.precise; + }; +} + +// Expected to fail, no immutable reference here. +fn mut_ref_inside_mut(f: &mut &mut FooS) { + let x: impl Fn() -> _ = async move || { + //~^ ERROR async closure does not implement `Fn` + let y = &f.precise; + }; +} + +fn ref_inside_box(f: Box<&FooS>) { + let x: impl Fn() -> _ = async move || { + let y = &f.precise; + }; +} + +fn box_inside_ref(f: &Box) { + let x: impl Fn() -> _ = async move || { + let y = &f.precise; + }; +} + +// Expected to fail, no immutable reference here. +fn box_inside_box(f: Box>) { + let x: impl Fn() -> _ = async move || { + //~^ ERROR async closure does not implement `Fn` + let y = &f.precise; + }; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/imm-deref-not-lending.stderr b/tests/ui/async-await/async-closures/imm-deref-not-lending.stderr new file mode 100644 index 0000000000000..cd3ff55e458ab --- /dev/null +++ b/tests/ui/async-await/async-closures/imm-deref-not-lending.stderr @@ -0,0 +1,14 @@ +error: async closure does not implement `Fn` because it captures state from its environment + --> $DIR/imm-deref-not-lending.rs:23:29 + | +LL | let x: impl Fn() -> _ = async move || { + | ^^^^^^^^^^^^^ + +error: async closure does not implement `Fn` because it captures state from its environment + --> $DIR/imm-deref-not-lending.rs:43:29 + | +LL | let x: impl Fn() -> _ = async move || { + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From b43a29711e7ab50c1ee47a2d030273c83099b15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Mar 2025 03:09:09 +0100 Subject: [PATCH 053/163] Fix `record_diagnostic` --- compiler/rustc_query_system/src/dep_graph/graph.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 985ca64903457..bfd8b3207152a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -538,10 +538,14 @@ impl DepGraph { #[inline] pub fn record_diagnostic(&self, qcx: Qcx, diagnostic: &DiagInner) { if let Some(ref data) = self.data { - self.read_index(data.encode_diagnostic(qcx, diagnostic)); + D::read_deps(|task_deps| match task_deps { + TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, + TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { + self.read_index(data.encode_diagnostic(qcx, diagnostic)); + } + }) } } - /// This forces a diagnostic node green by running its side effect. `prev_index` would /// refer to a node created used `encode_diagnostic` in the previous session. #[inline] From 899eed15adfbcda55e0eb300c037fe8d444f188d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 22:18:04 +0100 Subject: [PATCH 054/163] Refactor metrics generation step --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96c0955e871b8..47ee02ab00ed5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -241,13 +241,17 @@ jobs: - name: postprocess metrics into the summary run: | if [ -f build/metrics.json ]; then - ./build/citool/debug/citool postprocess-metrics build/metrics.json ${GITHUB_STEP_SUMMARY} + METRICS=build/metrics.json elif [ -f obj/build/metrics.json ]; then - ./build/citool/debug/citool postprocess-metrics obj/build/metrics.json ${GITHUB_STEP_SUMMARY} + METRICS=obj/build/metrics.json else echo "No metrics.json found" + exit 0 fi + ./build/citool/debug/citool postprocess-metrics \ + ${METRICS} ${GITHUB_STEP_SUMMARY} + - name: upload job metrics to DataDog if: needs.calculate_matrix.outputs.run_type != 'pr' env: From 301c384262522d0c4b5577ffbd10642ee9bee24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 22:18:41 +0100 Subject: [PATCH 055/163] Do not fail the build if metrics postprocessing or DataDog upload fails --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47ee02ab00ed5..01008d70b65b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -239,6 +239,9 @@ jobs: if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1' - name: postprocess metrics into the summary + # This step is not critical, and if some I/O problem happens, we don't want + # to cancel the build. + continue-on-error: true run: | if [ -f build/metrics.json ]; then METRICS=build/metrics.json @@ -253,6 +256,9 @@ jobs: ${METRICS} ${GITHUB_STEP_SUMMARY} - name: upload job metrics to DataDog + # This step is not critical, and if some I/O problem happens, we don't want + # to cancel the build. + continue-on-error: true if: needs.calculate_matrix.outputs.run_type != 'pr' env: DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} From 09d44a48b29fcf4c618ba38e592a1c4f365fc4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 14 Mar 2025 22:21:41 +0100 Subject: [PATCH 056/163] Print metrics postprocessing to stdout This allows the code to be simplified a little bit. --- .github/workflows/ci.yml | 2 +- src/ci/citool/src/main.rs | 7 ++----- src/ci/citool/src/metrics.rs | 33 ++++++++++----------------------- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01008d70b65b6..ffcdc40de3a70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,7 +253,7 @@ jobs: fi ./build/citool/debug/citool postprocess-metrics \ - ${METRICS} ${GITHUB_STEP_SUMMARY} + ${METRICS} >> ${GITHUB_STEP_SUMMARY} - name: upload job metrics to DataDog # This step is not critical, and if some I/O problem happens, we don't want diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index cd690ebeb0625..53fe75900750d 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -158,9 +158,6 @@ enum Args { PostprocessMetrics { /// Path to the metrics.json file metrics_path: PathBuf, - /// Path to a file where the postprocessed metrics summary will be stored. - /// Usually, this will be GITHUB_STEP_SUMMARY on CI. - summary_path: PathBuf, }, /// Upload CI metrics to Datadog. UploadBuildMetrics { @@ -211,8 +208,8 @@ fn main() -> anyhow::Result<()> { Args::UploadBuildMetrics { cpu_usage_csv } => { upload_ci_metrics(&cpu_usage_csv)?; } - Args::PostprocessMetrics { metrics_path, summary_path } => { - postprocess_metrics(&metrics_path, &summary_path)?; + Args::PostprocessMetrics { metrics_path } => { + postprocess_metrics(&metrics_path)?; } Args::PostMergeReport { current: commit, parent } => { post_merge_report(load_db(default_jobs_file)?, parent, commit)?; diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 83b3d5ceed05a..8da4d4e53e64e 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -1,6 +1,4 @@ use std::collections::BTreeMap; -use std::fs::File; -use std::io::Write; use std::path::Path; use anyhow::Context; @@ -8,57 +6,46 @@ use build_helper::metrics::{ BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, }; -pub fn postprocess_metrics(metrics_path: &Path, summary_path: &Path) -> anyhow::Result<()> { +pub fn postprocess_metrics(metrics_path: &Path) -> anyhow::Result<()> { let metrics = load_metrics(metrics_path)?; - let mut file = File::options() - .append(true) - .create(true) - .open(summary_path) - .with_context(|| format!("Cannot open summary file at {summary_path:?}"))?; - if !metrics.invocations.is_empty() { - writeln!(file, "# Bootstrap steps")?; - record_bootstrap_step_durations(&metrics, &mut file)?; - record_test_suites(&metrics, &mut file)?; + println!("# Bootstrap steps"); + record_bootstrap_step_durations(&metrics); + record_test_suites(&metrics); } Ok(()) } -fn record_bootstrap_step_durations(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> { +fn record_bootstrap_step_durations(metrics: &JsonRoot) { for invocation in &metrics.invocations { let step = BuildStep::from_invocation(invocation); let table = format_build_steps(&step); eprintln!("Step `{}`\n{table}\n", invocation.cmdline); - writeln!( - file, + println!( r"
{}
{table}
", invocation.cmdline - )?; + ); } eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); - - Ok(()) } -fn record_test_suites(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> { +fn record_test_suites(metrics: &JsonRoot) { let suites = get_test_suites(&metrics); if !suites.is_empty() { let aggregated = aggregate_test_suites(&suites); let table = render_table(aggregated); - writeln!(file, "\n# Test results\n")?; - writeln!(file, "{table}")?; + println!("\n# Test results\n"); + println!("{table}"); } else { eprintln!("No test suites found in metrics"); } - - Ok(()) } fn render_table(suites: BTreeMap) -> String { From 901102f5cb9e72f8264669e4c35137c560651277 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 15 Mar 2025 11:11:43 +0200 Subject: [PATCH 057/163] those should not get shell highlighting --- src/doc/rustc-dev-guide/src/tests/running.md | 48 ++++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index 03d4123cb02b5..c7d9247883313 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -18,7 +18,7 @@ a subset of test collections, and merge queue CI will exercise all of the test collection. -```bash +```text ./x test ``` @@ -45,7 +45,7 @@ tests. For example, a good "smoke test" that can be used after modifying rustc to see if things are generally working correctly would be to exercise the `ui` test suite ([`tests/ui`]): -```bash +```text ./x test tests/ui ``` @@ -53,14 +53,14 @@ Of course, the choice of test suites is somewhat arbitrary, and may not suit the task you are doing. For example, if you are hacking on debuginfo, you may be better off with the debuginfo test suite: -```bash +```text ./x test tests/debuginfo ``` If you only need to test a specific subdirectory of tests for any given test suite, you can pass that directory as a filter to `./x test`: -```bash +```text ./x test tests/ui/const-generics ``` @@ -73,7 +73,7 @@ suite, you can pass that directory as a filter to `./x test`: Likewise, you can test a single file by passing its path: -```bash +```text ./x test tests/ui/const-generics/const-test.rs ``` @@ -81,19 +81,19 @@ Likewise, you can test a single file by passing its path: have to use the `--test-args` argument as described [below](#running-an-individual-test). -```bash +```text ./x test src/tools/miri --test-args tests/fail/uninit/padding-enum.rs ``` ### Run only the tidy script -```bash +```text ./x test tidy ``` ### Run tests on the standard library -```bash +```text ./x test --stage 0 library/std ``` @@ -102,13 +102,13 @@ crates, you have to specify those explicitly. ### Run the tidy script and tests on the standard library -```bash +```text ./x test --stage 0 tidy library/std ``` ### Run tests on the standard library using a stage 1 compiler -```bash +```text ./x test --stage 1 library/std ``` @@ -122,7 +122,7 @@ the tests **usually** work fine with stage 1, there are some limitations. ### Run all tests using a stage 2 compiler -```bash +```text ./x test --stage 2 ``` @@ -134,13 +134,13 @@ You almost never need to do this; CI will run these tests for you. You may want to run unit tests on a specific file with following: -```bash +```text ./x test compiler/rustc_data_structures/src/thin_vec/tests.rs ``` But unfortunately, it's impossible. You should invoke the following instead: -```bash +```text ./x test compiler/rustc_data_structures/ --test-args thin_vec ``` @@ -151,7 +151,7 @@ often the test they are trying to fix. As mentioned earlier, you may pass the full file path to achieve this, or alternatively one may invoke `x` with the `--test-args` option: -```bash +```text ./x test tests/ui --test-args issue-1234 ``` @@ -203,7 +203,7 @@ When `--pass $mode` is passed, these tests will be forced to run under the given `$mode` unless the directive `//@ ignore-pass` exists in the test file. For example, you can run all the tests in `tests/ui` as `check-pass`: -```bash +```text ./x test tests/ui --pass check ``` @@ -219,7 +219,7 @@ first look for expected output in `foo.polonius.stderr`, falling back to the usual `foo.stderr` if not found. The following will run the UI test suite in Polonius mode: -```bash +```text ./x test tests/ui --compare-mode=polonius ``` @@ -232,7 +232,7 @@ just `.rs` files, so after [creating a rustup toolchain](../building/how-to-build-and-run.md#creating-a-rustup-toolchain), you can do something like: -```bash +```text rustc +stage1 tests/ui/issue-1234.rs ``` @@ -252,7 +252,7 @@ execution* so be careful where it is used. To do this, first build `remote-test-server` for the remote machine, e.g. for RISC-V -```sh +```text ./x build src/tools/remote-test-server --target riscv64gc-unknown-linux-gnu ``` @@ -264,7 +264,7 @@ On the remote machine, run the `remote-test-server` with the `--bind 0.0.0.0:12345` flag (and optionally `-v` for verbose output). Output should look like this: -```sh +```text $ ./remote-test-server -v --bind 0.0.0.0:12345 starting test server listening on 0.0.0.0:12345! @@ -278,7 +278,7 @@ restrictive IP address when binding. You can test if the `remote-test-server` is working by connecting to it and sending `ping\n`. It should reply `pong`: -```sh +```text $ nc $REMOTE_IP 12345 ping pong @@ -288,7 +288,7 @@ To run tests using the remote runner, set the `TEST_DEVICE_ADDR` environment variable then use `x` as usual. For example, to run `ui` tests for a RISC-V machine with the IP address `1.2.3.4` use -```sh +```text export TEST_DEVICE_ADDR="1.2.3.4:12345" ./x test tests/ui --target riscv64gc-unknown-linux-gnu ``` @@ -362,20 +362,20 @@ codegen-backends = ["llvm", "gcc"] Then you need to install libgccjit 12. For example with `apt`: -```bash +```text $ apt install libgccjit-12-dev ``` Now you can run the following command: -```bash +```text $ ./x test compiler/rustc_codegen_gcc/ ``` If it cannot find the `.so` library (if you installed it with `apt` for example), you need to pass the library file path with `LIBRARY_PATH`: -```bash +```text $ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/ ./x test compiler/rustc_codegen_gcc/ ``` From 35a70bd2c0a8b5e0b62f640e7495060f53a9d5d6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 15 Mar 2025 11:35:15 +0200 Subject: [PATCH 058/163] make 'mdbook test --chapter "Running tests"' pass --- src/doc/rustc-dev-guide/src/tests/running.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index c7d9247883313..6fb49810ad485 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -296,7 +296,7 @@ export TEST_DEVICE_ADDR="1.2.3.4:12345" If `remote-test-server` was run with the verbose flag, output on the test machine may look something like -``` +```text [...] run "/tmp/work/test1007/a" run "/tmp/work/test1008/a" From fdce008a92fc0b042a6fbefd76e7fad1f590cb8c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 15 Mar 2025 11:17:03 +0200 Subject: [PATCH 059/163] add some copy-paste goodness --- src/doc/rustc-dev-guide/src/tests/running.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index 6fb49810ad485..73f5603d5c653 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -363,20 +363,20 @@ codegen-backends = ["llvm", "gcc"] Then you need to install libgccjit 12. For example with `apt`: ```text -$ apt install libgccjit-12-dev +apt install libgccjit-12-dev ``` Now you can run the following command: ```text -$ ./x test compiler/rustc_codegen_gcc/ +./x test compiler/rustc_codegen_gcc/ ``` If it cannot find the `.so` library (if you installed it with `apt` for example), you need to pass the library file path with `LIBRARY_PATH`: ```text -$ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/ ./x test compiler/rustc_codegen_gcc/ +LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/ ./x test compiler/rustc_codegen_gcc/ ``` If you encounter bugs or problems, don't hesitate to open issues on the From e757deab233aea31612c593773f242b6b9c6e386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 11:16:09 +0100 Subject: [PATCH 060/163] Refactor metrics and analysis in citool to distinguish them better --- .../src/{merge_report.rs => analysis.rs} | 204 ++++++++++-------- src/ci/citool/src/main.rs | 17 +- src/ci/citool/src/metrics.rs | 190 ++++++---------- src/ci/citool/src/utils.rs | 4 + 4 files changed, 196 insertions(+), 219 deletions(-) rename src/ci/citool/src/{merge_report.rs => analysis.rs} (62%) diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/analysis.rs similarity index 62% rename from src/ci/citool/src/merge_report.rs rename to src/ci/citool/src/analysis.rs index 62daa2e68530a..87c5708fa602b 100644 --- a/src/ci/citool/src/merge_report.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,97 +1,135 @@ -use std::collections::{HashMap, HashSet}; -use std::path::PathBuf; +use crate::metrics; +use crate::metrics::{JobMetrics, JobName, get_test_suites}; +use crate::utils::pluralize; +use build_helper::metrics::{ + BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, +}; +use std::collections::{BTreeMap, HashMap, HashSet}; + +pub fn output_bootstrap_stats(metrics: &JsonRoot) { + if !metrics.invocations.is_empty() { + println!("# Bootstrap steps"); + record_bootstrap_step_durations(&metrics); + record_test_suites(&metrics); + } +} -use anyhow::Context; -use build_helper::metrics::{JsonRoot, TestOutcome, TestSuiteMetadata}; +fn record_bootstrap_step_durations(metrics: &JsonRoot) { + for invocation in &metrics.invocations { + let step = BuildStep::from_invocation(invocation); + let table = format_build_steps(&step); + eprintln!("Step `{}`\n{table}\n", invocation.cmdline); + println!( + r"
+{} +
{table}
+
+", + invocation.cmdline + ); + } + eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); +} -use crate::jobs::JobDatabase; -use crate::metrics::get_test_suites; +fn record_test_suites(metrics: &JsonRoot) { + let suites = metrics::get_test_suites(&metrics); -type Sha = String; -type JobName = String; + if !suites.is_empty() { + let aggregated = aggregate_test_suites(&suites); + let table = render_table(aggregated); + println!("\n# Test results\n"); + println!("{table}"); + } else { + eprintln!("No test suites found in metrics"); + } +} -/// Computes a post merge CI analysis report between the `parent` and `current` commits. -pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> { - let jobs = download_all_metrics(&job_db, &parent, ¤t)?; - let aggregated_test_diffs = aggregate_test_diffs(&jobs)?; +fn render_table(suites: BTreeMap) -> String { + use std::fmt::Write; - println!("Comparing {parent} (base) -> {current} (this PR)\n"); - report_test_diffs(aggregated_test_diffs); + let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string(); + writeln!(table, "|:------|------:|------:|------:|").unwrap(); - Ok(()) -} + fn compute_pct(value: f64, total: f64) -> f64 { + if total == 0.0 { 0.0 } else { value / total } + } -struct JobMetrics { - parent: Option, - current: JsonRoot, -} + fn write_row( + buffer: &mut String, + name: &str, + record: &TestSuiteRecord, + surround: &str, + ) -> std::fmt::Result { + let TestSuiteRecord { passed, ignored, failed } = record; + let total = (record.passed + record.ignored + record.failed) as f64; + let passed_pct = compute_pct(*passed as f64, total) * 100.0; + let ignored_pct = compute_pct(*ignored as f64, total) * 100.0; + let failed_pct = compute_pct(*failed as f64, total) * 100.0; + + write!(buffer, "| {surround}{name}{surround} |")?; + write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?; + write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?; + writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?; + + Ok(()) + } -/// Download before/after metrics for all auto jobs in the job database. -fn download_all_metrics( - job_db: &JobDatabase, - parent: &str, - current: &str, -) -> anyhow::Result> { - let mut jobs = HashMap::default(); - - for job in &job_db.auto_jobs { - eprintln!("Downloading metrics of job {}", job.name); - let metrics_parent = match download_job_metrics(&job.name, parent) { - Ok(metrics) => Some(metrics), - Err(error) => { - eprintln!( - r#"Did not find metrics for job `{}` at `{}`: {error:?}. -Maybe it was newly added?"#, - job.name, parent - ); - None - } - }; - let metrics_current = download_job_metrics(&job.name, current)?; - jobs.insert( - job.name.clone(), - JobMetrics { parent: metrics_parent, current: metrics_current }, - ); + let mut total = TestSuiteRecord::default(); + for (name, record) in suites { + write_row(&mut table, &name, &record, "").unwrap(); + total.passed += record.passed; + total.ignored += record.ignored; + total.failed += record.failed; } - Ok(jobs) + write_row(&mut table, "Total", &total, "**").unwrap(); + table } -/// Downloads job metrics of the given job for the given commit. -/// Caches the result on the local disk. -fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { - let cache_path = PathBuf::from(".citool-cache").join(sha).join(job_name).join("metrics.json"); - if let Some(cache_entry) = - std::fs::read_to_string(&cache_path).ok().and_then(|data| serde_json::from_str(&data).ok()) - { - return Ok(cache_entry); - } +/// Computes a post merge CI analysis report of test differences +/// between the `parent` and `current` commits. +pub fn output_test_diffs(job_metrics: HashMap) { + let aggregated_test_diffs = aggregate_test_diffs(&job_metrics); + report_test_diffs(aggregated_test_diffs); +} - let url = get_metrics_url(job_name, sha); - let mut response = ureq::get(&url).call()?; - if !response.status().is_success() { - return Err(anyhow::anyhow!( - "Cannot fetch metrics from {url}: {}\n{}", - response.status(), - response.body_mut().read_to_string()? - )); - } - let data: JsonRoot = response - .body_mut() - .read_json() - .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; - - // Ignore errors if cache cannot be created - if std::fs::create_dir_all(cache_path.parent().unwrap()).is_ok() { - if let Ok(serialized) = serde_json::to_string(&data) { - let _ = std::fs::write(&cache_path, &serialized); +#[derive(Default)] +struct TestSuiteRecord { + passed: u64, + ignored: u64, + failed: u64, +} + +fn test_metadata_name(metadata: &TestSuiteMetadata) -> String { + match metadata { + TestSuiteMetadata::CargoPackage { crates, stage, .. } => { + format!("{} (stage {stage})", crates.join(", ")) + } + TestSuiteMetadata::Compiletest { suite, stage, .. } => { + format!("{suite} (stage {stage})") } } - Ok(data) } -fn get_metrics_url(job_name: &str, sha: &str) -> String { - let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" }; - format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") +fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap { + let mut records: BTreeMap = BTreeMap::new(); + for suite in suites { + let name = test_metadata_name(&suite.metadata); + let record = records.entry(name).or_default(); + for test in &suite.tests { + match test.outcome { + TestOutcome::Passed => { + record.passed += 1; + } + TestOutcome::Failed => { + record.failed += 1; + } + TestOutcome::Ignored { .. } => { + record.ignored += 1; + } + } + } + } + records } /// Represents a difference in the outcome of tests between a base and a current commit. @@ -101,9 +139,7 @@ struct AggregatedTestDiffs { diffs: HashMap>, } -fn aggregate_test_diffs( - jobs: &HashMap, -) -> anyhow::Result { +fn aggregate_test_diffs(jobs: &HashMap) -> AggregatedTestDiffs { let mut diffs: HashMap> = HashMap::new(); // Aggregate test suites @@ -117,7 +153,7 @@ fn aggregate_test_diffs( } } - Ok(AggregatedTestDiffs { diffs }) + AggregatedTestDiffs { diffs } } #[derive(Eq, PartialEq, Hash, Debug)] @@ -312,7 +348,3 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { ); } } - -fn pluralize(text: &str, count: usize) -> String { - if count == 1 { text.to_string() } else { format!("{text}s") } -} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 53fe75900750d..5f1932854b5a0 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,7 +1,7 @@ +mod analysis; mod cpu_usage; mod datadog; mod jobs; -mod merge_report; mod metrics; mod utils; @@ -14,12 +14,13 @@ use clap::Parser; use jobs::JobDatabase; use serde_yaml::Value; +use crate::analysis::output_test_diffs; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; use crate::jobs::RunType; -use crate::merge_report::post_merge_report; -use crate::metrics::postprocess_metrics; +use crate::metrics::{download_auto_job_metrics, load_metrics}; use crate::utils::load_env_var; +use analysis::output_bootstrap_stats; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); @@ -209,10 +210,14 @@ fn main() -> anyhow::Result<()> { upload_ci_metrics(&cpu_usage_csv)?; } Args::PostprocessMetrics { metrics_path } => { - postprocess_metrics(&metrics_path)?; + let metrics = load_metrics(&metrics_path)?; + output_bootstrap_stats(&metrics); } - Args::PostMergeReport { current: commit, parent } => { - post_merge_report(load_db(default_jobs_file)?, parent, commit)?; + Args::PostMergeReport { current, parent } => { + let db = load_db(default_jobs_file)?; + let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; + println!("Comparing {parent} (base) -> {current} (this PR)\n"); + output_test_diffs(metrics); } } diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 8da4d4e53e64e..117a4f372c4c2 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -1,133 +1,11 @@ -use std::collections::BTreeMap; use std::path::Path; +use crate::jobs::JobDatabase; use anyhow::Context; -use build_helper::metrics::{ - BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, -}; +use build_helper::metrics::{JsonNode, JsonRoot, TestSuite}; +use std::collections::HashMap; -pub fn postprocess_metrics(metrics_path: &Path) -> anyhow::Result<()> { - let metrics = load_metrics(metrics_path)?; - - if !metrics.invocations.is_empty() { - println!("# Bootstrap steps"); - record_bootstrap_step_durations(&metrics); - record_test_suites(&metrics); - } - - Ok(()) -} - -fn record_bootstrap_step_durations(metrics: &JsonRoot) { - for invocation in &metrics.invocations { - let step = BuildStep::from_invocation(invocation); - let table = format_build_steps(&step); - eprintln!("Step `{}`\n{table}\n", invocation.cmdline); - println!( - r"
-{} -
{table}
-
-", - invocation.cmdline - ); - } - eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); -} - -fn record_test_suites(metrics: &JsonRoot) { - let suites = get_test_suites(&metrics); - - if !suites.is_empty() { - let aggregated = aggregate_test_suites(&suites); - let table = render_table(aggregated); - println!("\n# Test results\n"); - println!("{table}"); - } else { - eprintln!("No test suites found in metrics"); - } -} - -fn render_table(suites: BTreeMap) -> String { - use std::fmt::Write; - - let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string(); - writeln!(table, "|:------|------:|------:|------:|").unwrap(); - - fn compute_pct(value: f64, total: f64) -> f64 { - if total == 0.0 { 0.0 } else { value / total } - } - - fn write_row( - buffer: &mut String, - name: &str, - record: &TestSuiteRecord, - surround: &str, - ) -> std::fmt::Result { - let TestSuiteRecord { passed, ignored, failed } = record; - let total = (record.passed + record.ignored + record.failed) as f64; - let passed_pct = compute_pct(*passed as f64, total) * 100.0; - let ignored_pct = compute_pct(*ignored as f64, total) * 100.0; - let failed_pct = compute_pct(*failed as f64, total) * 100.0; - - write!(buffer, "| {surround}{name}{surround} |")?; - write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?; - write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?; - writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?; - - Ok(()) - } - - let mut total = TestSuiteRecord::default(); - for (name, record) in suites { - write_row(&mut table, &name, &record, "").unwrap(); - total.passed += record.passed; - total.ignored += record.ignored; - total.failed += record.failed; - } - write_row(&mut table, "Total", &total, "**").unwrap(); - table -} - -#[derive(Default)] -struct TestSuiteRecord { - passed: u64, - ignored: u64, - failed: u64, -} - -fn test_metadata_name(metadata: &TestSuiteMetadata) -> String { - match metadata { - TestSuiteMetadata::CargoPackage { crates, stage, .. } => { - format!("{} (stage {stage})", crates.join(", ")) - } - TestSuiteMetadata::Compiletest { suite, stage, .. } => { - format!("{suite} (stage {stage})") - } - } -} - -fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap { - let mut records: BTreeMap = BTreeMap::new(); - for suite in suites { - let name = test_metadata_name(&suite.metadata); - let record = records.entry(name).or_default(); - for test in &suite.tests { - match test.outcome { - TestOutcome::Passed => { - record.passed += 1; - } - TestOutcome::Failed => { - record.failed += 1; - } - TestOutcome::Ignored { .. } => { - record.ignored += 1; - } - } - } - } - records -} +pub type JobName = String; pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) { @@ -150,10 +28,68 @@ pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { suites } -fn load_metrics(path: &Path) -> anyhow::Result { +pub fn load_metrics(path: &Path) -> anyhow::Result { let metrics = std::fs::read_to_string(path) .with_context(|| format!("Cannot read JSON metrics from {path:?}"))?; let metrics: JsonRoot = serde_json::from_str(&metrics) .with_context(|| format!("Cannot deserialize JSON metrics from {path:?}"))?; Ok(metrics) } + +pub struct JobMetrics { + pub parent: Option, + pub current: JsonRoot, +} + +/// Download before/after metrics for all auto jobs in the job database. +/// `parent` and `current` should be commit SHAs. +pub fn download_auto_job_metrics( + job_db: &JobDatabase, + parent: &str, + current: &str, +) -> anyhow::Result> { + let mut jobs = HashMap::default(); + + for job in &job_db.auto_jobs { + eprintln!("Downloading metrics of job {}", job.name); + let metrics_parent = match download_job_metrics(&job.name, parent) { + Ok(metrics) => Some(metrics), + Err(error) => { + eprintln!( + r#"Did not find metrics for job `{}` at `{}`: {error:?}. +Maybe it was newly added?"#, + job.name, parent + ); + None + } + }; + let metrics_current = download_job_metrics(&job.name, current)?; + jobs.insert( + job.name.clone(), + JobMetrics { parent: metrics_parent, current: metrics_current }, + ); + } + Ok(jobs) +} + +pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { + let url = get_metrics_url(job_name, sha); + let mut response = ureq::get(&url).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Cannot fetch metrics from {url}: {}\n{}", + response.status(), + response.body_mut().read_to_string()? + )); + } + let data: JsonRoot = response + .body_mut() + .read_json() + .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; + Ok(data) +} + +fn get_metrics_url(job_name: &str, sha: &str) -> String { + let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" }; + format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") +} diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index 9cc220987bdfd..a18af96bf3de6 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -9,3 +9,7 @@ pub fn load_env_var(name: &str) -> anyhow::Result { pub fn read_to_string>(path: P) -> anyhow::Result { std::fs::read_to_string(&path).with_context(|| format!("Cannot read file {:?}", path.as_ref())) } + +pub fn pluralize(text: &str, count: usize) -> String { + if count == 1 { text.to_string() } else { format!("{text}s") } +} From 413fd52ea98a1cd986afa3201a259304a3b58599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 09:32:57 +0100 Subject: [PATCH 061/163] Print number of found test diffs --- src/ci/citool/src/analysis.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 87c5708fa602b..8e4ab03f3b3a9 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -244,6 +244,7 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { println!("No test diffs found"); return; } + println!("\n{} test {} found\n", diff.diffs.len(), pluralize("difference", diff.diffs.len())); fn format_outcome(outcome: &TestOutcome) -> String { match outcome { From 6c24c9c088a0eb858976781090a5b1fbb57981bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 09:34:35 +0100 Subject: [PATCH 062/163] Use first-level heading for test differences header --- src/ci/citool/src/analysis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 8e4ab03f3b3a9..02199636fc798 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -239,7 +239,7 @@ fn normalize_test_name(name: &str) -> String { /// Prints test changes in Markdown format to stdout. fn report_test_diffs(diff: AggregatedTestDiffs) { - println!("## Test differences"); + println!("# Test differences"); if diff.diffs.is_empty() { println!("No test diffs found"); return; From 30d57576b9040a438adc2414540da3778addf34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 09:35:29 +0100 Subject: [PATCH 063/163] Print test diffs into GitHub summary So that we can also observe them for try builds, before merging a PR. --- .github/workflows/ci.yml | 5 +++++ src/ci/citool/src/main.rs | 41 +++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffcdc40de3a70..aaae67c28bc70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,7 +252,12 @@ jobs: exit 0 fi + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + ./build/citool/debug/citool postprocess-metrics \ + --job-name ${CI_JOB_NAME} \ + --parent ${PARENT_COMMIT} \ ${METRICS} >> ${GITHUB_STEP_SUMMARY} - name: upload job metrics to DataDog diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 5f1932854b5a0..fb0639367bd0e 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -5,7 +5,7 @@ mod jobs; mod metrics; mod utils; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -18,7 +18,7 @@ use crate::analysis::output_test_diffs; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; use crate::jobs::RunType; -use crate::metrics::{download_auto_job_metrics, load_metrics}; +use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::utils::load_env_var; use analysis::output_bootstrap_stats; @@ -138,6 +138,27 @@ fn upload_ci_metrics(cpu_usage_csv: &Path) -> anyhow::Result<()> { Ok(()) } +fn postprocess_metrics( + metrics_path: PathBuf, + parent: Option, + job_name: Option, +) -> anyhow::Result<()> { + let metrics = load_metrics(&metrics_path)?; + output_bootstrap_stats(&metrics); + + let (Some(parent), Some(job_name)) = (parent, job_name) else { + return Ok(()); + }; + + let parent_metrics = + download_job_metrics(&job_name, &parent).context("cannot download parent metrics")?; + let job_metrics = + HashMap::from([(job_name, JobMetrics { parent: Some(parent_metrics), current: metrics })]); + output_test_diffs(job_metrics); + + Ok(()) +} + #[derive(clap::Parser)] enum Args { /// Calculate a list of jobs that should be executed on CI. @@ -155,10 +176,19 @@ enum Args { #[clap(long = "type", default_value = "auto")] job_type: JobType, }, - /// Postprocess the metrics.json file generated by bootstrap. + /// Postprocess the metrics.json file generated by bootstrap and output + /// various statistics. + /// If `--parent` and `--job-name` are provided, also display a diff + /// against previous metrics that are downloaded from CI. PostprocessMetrics { /// Path to the metrics.json file metrics_path: PathBuf, + /// A parent SHA against which to compare. + #[clap(long, requires("job_name"))] + parent: Option, + /// The name of the current job. + #[clap(long, requires("parent"))] + job_name: Option, }, /// Upload CI metrics to Datadog. UploadBuildMetrics { @@ -209,9 +239,8 @@ fn main() -> anyhow::Result<()> { Args::UploadBuildMetrics { cpu_usage_csv } => { upload_ci_metrics(&cpu_usage_csv)?; } - Args::PostprocessMetrics { metrics_path } => { - let metrics = load_metrics(&metrics_path)?; - output_bootstrap_stats(&metrics); + Args::PostprocessMetrics { metrics_path, parent, job_name } => { + postprocess_metrics(metrics_path, parent, job_name)?; } Args::PostMergeReport { current, parent } => { let db = load_db(default_jobs_file)?; From 634a11ef4864eb3cdaefa34d320f4be4f679b542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 09:37:19 +0100 Subject: [PATCH 064/163] Add bootstrap stage to test names --- src/ci/citool/src/analysis.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 02199636fc798..566b8e603fbb6 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -225,16 +225,23 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { // Poor man's detection of doctests based on the "(line XYZ)" suffix let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) && test.name.contains("(line"); - let test_entry = Test { name: normalize_test_name(&test.name), is_doctest }; + let test_entry = Test { name: generate_test_name(&test.name, &suite), is_doctest }; tests.insert(test_entry, test.outcome.clone()); } } TestSuiteData { tests } } -/// Normalizes Windows-style path delimiters to Unix-style paths. -fn normalize_test_name(name: &str) -> String { - name.replace('\\', "/") +/// Normalizes Windows-style path delimiters to Unix-style paths +/// and adds suite metadata to the test name. +fn generate_test_name(name: &str, suite: &TestSuite) -> String { + let name = name.replace('\\', "/"); + let stage = match suite.metadata { + TestSuiteMetadata::CargoPackage { stage, .. } => stage, + TestSuiteMetadata::Compiletest { stage, .. } => stage, + }; + + format!("{name} (stage {stage})") } /// Prints test changes in Markdown format to stdout. From 232be8614d8bc396f3c0917916c96ef0ee939ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 09:41:00 +0100 Subject: [PATCH 065/163] Add a helper function for outputting details --- src/ci/citool/src/analysis.rs | 13 ++++--------- src/ci/citool/src/utils.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 566b8e603fbb6..8a37544357700 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,6 +1,6 @@ use crate::metrics; use crate::metrics::{JobMetrics, JobName, get_test_suites}; -use crate::utils::pluralize; +use crate::utils::{output_details, pluralize}; use build_helper::metrics::{ BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, }; @@ -19,14 +19,9 @@ fn record_bootstrap_step_durations(metrics: &JsonRoot) { let step = BuildStep::from_invocation(invocation); let table = format_build_steps(&step); eprintln!("Step `{}`\n{table}\n", invocation.cmdline); - println!( - r"
-{} -
{table}
-
-", - invocation.cmdline - ); + output_details(&invocation.cmdline, || { + println!("
{table}
"); + }); } eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); } diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index a18af96bf3de6..bbe24c3633bc0 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -13,3 +13,17 @@ pub fn read_to_string>(path: P) -> anyhow::Result { pub fn pluralize(text: &str, count: usize) -> String { if count == 1 { text.to_string() } else { format!("{text}s") } } + +/// Outputs a HTML
section with the provided summary. +/// Output printed by `func` will be contained within the section. +pub fn output_details(summary: &str, func: F) +where + F: FnOnce(), +{ + println!( + r"
+{summary}" + ); + func(); + println!("
\n"); +} From b4cccf01587ac672dee7a92df7e3e21728f5b7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 10:00:11 +0100 Subject: [PATCH 066/163] Put test differences into a `
` section and add better explanation of the post merge report --- src/ci/citool/src/analysis.rs | 63 +++++++++++++++++++---------------- src/ci/citool/src/main.rs | 23 ++++++++++--- src/ci/citool/src/utils.rs | 4 ++- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 8a37544357700..6469bc251be66 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -246,7 +246,6 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { println!("No test diffs found"); return; } - println!("\n{} test {} found\n", diff.diffs.len(), pluralize("difference", diff.diffs.len())); fn format_outcome(outcome: &TestOutcome) -> String { match outcome { @@ -320,34 +319,42 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { // Sort diffs by job group and test name grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name))); - for (diff, job_group) in grouped_diffs { - println!( - "- `{}`: {} ({})", - diff.test.name, - format_diff(&diff.diff), - format_job_group(job_group) - ); - } + output_details( + &format!("Show {} test {}\n", original_diff_count, pluralize("diff", original_diff_count)), + || { + for (diff, job_group) in grouped_diffs { + println!( + "- `{}`: {} ({})", + diff.test.name, + format_diff(&diff.diff), + format_job_group(job_group) + ); + } - let extra_diffs = diffs.len().saturating_sub(max_diff_count); - if extra_diffs > 0 { - println!("\n(and {extra_diffs} additional {})", pluralize("test diff", extra_diffs)); - } + let extra_diffs = diffs.len().saturating_sub(max_diff_count); + if extra_diffs > 0 { + println!( + "\n(and {extra_diffs} additional {})", + pluralize("test diff", extra_diffs) + ); + } - if doctest_count > 0 { - println!( - "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", - pluralize("diff", doctest_count) - ); - } + if doctest_count > 0 { + println!( + "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + pluralize("diff", doctest_count) + ); + } - // Now print the job group index - println!("\n**Job group index**\n"); - for (group, jobs) in job_index.into_iter().enumerate() { - println!( - "- {}: {}", - format_job_group(group as u64), - jobs.iter().map(|j| format!("`{j}`")).collect::>().join(", ") - ); - } + // Now print the job group index + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter().map(|j| format!("`{j}`")).collect::>().join(", ") + ); + } + }, + ); } diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index fb0639367bd0e..01483a2633d0a 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -19,7 +19,7 @@ use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; -use crate::utils::load_env_var; +use crate::utils::{load_env_var, output_details}; use analysis::output_bootstrap_stats; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); @@ -159,6 +159,22 @@ fn postprocess_metrics( Ok(()) } +fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> { + let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; + + output_details("What is this?", || { + println!( + r#"This is an experimental post-merge analysis report that shows differences in +test outcomes between the merged PR and its parent PR."# + ); + }); + + println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); + output_test_diffs(metrics); + + Ok(()) +} + #[derive(clap::Parser)] enum Args { /// Calculate a list of jobs that should be executed on CI. @@ -243,10 +259,7 @@ fn main() -> anyhow::Result<()> { postprocess_metrics(metrics_path, parent, job_name)?; } Args::PostMergeReport { current, parent } => { - let db = load_db(default_jobs_file)?; - let metrics = download_auto_job_metrics(&db, &parent, ¤t)?; - println!("Comparing {parent} (base) -> {current} (this PR)\n"); - output_test_diffs(metrics); + post_merge_report(load_db(default_jobs_file)?, current, parent)?; } } diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index bbe24c3633bc0..b9b1bf4d45502 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -22,7 +22,9 @@ where { println!( r"
-{summary}" +{summary} + +" ); func(); println!("
\n"); From e84531811160308fbdd0a8ec3e9b697bb17ccd02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 11:11:56 +0100 Subject: [PATCH 067/163] Do not error out on missing parent metrics --- src/ci/citool/src/main.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 01483a2633d0a..29f94e2be5dbd 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -150,11 +150,24 @@ fn postprocess_metrics( return Ok(()); }; - let parent_metrics = - download_job_metrics(&job_name, &parent).context("cannot download parent metrics")?; - let job_metrics = - HashMap::from([(job_name, JobMetrics { parent: Some(parent_metrics), current: metrics })]); - output_test_diffs(job_metrics); + // This command is executed also on PR builds, which might not have parent metrics + // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics + // due to missing permissions. + // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs, + // we simply print an error if the parent metrics were not found, but otherwise exit + // successfully. + match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") { + Ok(parent_metrics) => { + let job_metrics = HashMap::from([( + job_name, + JobMetrics { parent: Some(parent_metrics), current: metrics }, + )]); + output_test_diffs(job_metrics); + } + Err(error) => { + eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}"); + } + } Ok(()) } From 4801dba9af6e6c1b3bb06959893f68ed031f6325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 11:34:55 +0100 Subject: [PATCH 068/163] Reformat code --- src/ci/citool/src/analysis.rs | 10 ++++++---- src/ci/citool/src/main.rs | 2 +- src/ci/citool/src/metrics.rs | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 6469bc251be66..2088ce2962097 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -1,10 +1,12 @@ -use crate::metrics; -use crate::metrics::{JobMetrics, JobName, get_test_suites}; -use crate::utils::{output_details, pluralize}; +use std::collections::{BTreeMap, HashMap, HashSet}; + use build_helper::metrics::{ BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, }; -use std::collections::{BTreeMap, HashMap, HashSet}; + +use crate::metrics; +use crate::metrics::{JobMetrics, JobName, get_test_suites}; +use crate::utils::{output_details, pluralize}; pub fn output_bootstrap_stats(metrics: &JsonRoot) { if !metrics.invocations.is_empty() { diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 29f94e2be5dbd..9e4b558d77aa0 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -9,6 +9,7 @@ use std::collections::{BTreeMap, HashMap}; use std::path::{Path, PathBuf}; use std::process::Command; +use analysis::output_bootstrap_stats; use anyhow::Context; use clap::Parser; use jobs::JobDatabase; @@ -20,7 +21,6 @@ use crate::datadog::upload_datadog_metric; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::utils::{load_env_var, output_details}; -use analysis::output_bootstrap_stats; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 117a4f372c4c2..263011a337089 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -1,9 +1,10 @@ +use std::collections::HashMap; use std::path::Path; -use crate::jobs::JobDatabase; use anyhow::Context; use build_helper::metrics::{JsonNode, JsonRoot, TestSuite}; -use std::collections::HashMap; + +use crate::jobs::JobDatabase; pub type JobName = String; From 7c792e29d71f83407318e730015caa0003bbb9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 15 Mar 2025 13:10:49 +0100 Subject: [PATCH 069/163] Only use `DIST_TRY_BUILD` for try jobs that were not selected explicitly --- src/ci/citool/src/jobs.rs | 14 ++++++++++++++ src/ci/citool/tests/jobs.rs | 10 +++++----- src/ci/citool/tests/test-jobs.yml | 7 ------- src/ci/github-actions/jobs.yml | 12 +++++------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 0de8b740227d7..13880ad466a6b 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -185,6 +185,20 @@ fn calculate_jobs( env.extend(crate::yaml_map_to_json(&job.env)); let full_name = format!("{prefix} - {}", job.name); + // When the default `@bors try` job is executed (which is usually done + // for benchmarking performance, running crater or for downloading the + // built toolchain using `rustup-toolchain-install-master`), + // we inject the `DIST_TRY_BUILD` environment variable to the jobs + // to tell `opt-dist` to make the build faster by skipping certain steps. + if let RunType::TryJob { job_patterns } = run_type { + if job_patterns.is_none() { + env.insert( + "DIST_TRY_BUILD".to_string(), + serde_json::value::Value::Number(1.into()), + ); + } + } + GithubActionsJob { name: job.name, full_name, diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs index 788f5e7e4f661..c644f885be30c 100644 --- a/src/ci/citool/tests/jobs.rs +++ b/src/ci/citool/tests/jobs.rs @@ -14,10 +14,10 @@ fn auto_jobs() { #[test] fn try_jobs() { let stdout = get_matrix("push", "commit", "refs/heads/try"); - insta::assert_snapshot!(stdout, @r#" + insta::assert_snapshot!(stdout, @r###" jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}] run_type=try - "#); + "###); } #[test] @@ -30,10 +30,10 @@ try-job: aarch64-gnu try-job: dist-i686-msvc"#, "refs/heads/try", ); - insta::assert_snapshot!(stdout, @r#" - jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"DIST_TRY_BUILD":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] + insta::assert_snapshot!(stdout, @r###" + jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] run_type=try - "#); + "###); } #[test] diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index ff4d1772f59b9..3593b3f7df633 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -53,13 +53,6 @@ envs: try: <<: *production - # The following env var activates faster `try` builds in `opt-dist` by, e.g. - # - building only the more commonly useful components (we rarely need e.g. rust-docs in try - # builds) - # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain - # - # If you *want* these to happen however, temporarily comment it before triggering a try build. - DIST_TRY_BUILD: 1 auto: <<: *production diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index d8c3625af2861..ae029cb777995 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -82,15 +82,13 @@ envs: AWS_REGION: us-west-1 TOOLSTATE_PUBLISH: 1 + # Try builds started through `@bors try` (without specifying custom jobs + # in the PR description) will be passed the `DIST_TRY_BUILD` environment + # variable by citool. + # This tells the `opt-dist` tool to skip building certain components + # and skip running tests, so that the try build finishes faster. try: <<: *production - # The following env var activates faster `try` builds in `opt-dist` by, e.g. - # - building only the more commonly useful components (we rarely need e.g. rust-docs in try - # builds) - # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain - # - # If you *want* these to happen however, temporarily comment it before triggering a try build. - DIST_TRY_BUILD: 1 auto: <<: *production From 9d9bac0e968362ff3da4788cc04c65d5f0b6898f Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 10 Feb 2025 12:18:23 +0000 Subject: [PATCH 070/163] refactor `notable_traits_button` to use iterator combinators instead of for loop --- src/librustdoc/html/render/mod.rs | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b2ad2fa773ae5..8dfde1679fe11 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1465,8 +1465,6 @@ pub(crate) fn notable_traits_button( ty: &clean::Type, cx: &Context<'_>, ) -> Option { - let mut has_notable_trait = false; - if ty.is_unit() { // Very common fast path. return None; @@ -1484,27 +1482,19 @@ pub(crate) fn notable_traits_button( return None; } - if let Some(impls) = cx.cache().impls.get(&did) { - for i in impls { - let impl_ = i.inner_impl(); - if impl_.polarity != ty::ImplPolarity::Positive { - continue; - } - - if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { + let impls = cx.cache().impls.get(&did)?; + let has_notable_trait = impls + .iter() + .map(Impl::inner_impl) + .filter(|impl_| { + impl_.polarity == ty::ImplPolarity::Positive // Two different types might have the same did, // without actually being the same. - continue; - } - if let Some(trait_) = &impl_.trait_ { - let trait_did = trait_.def_id(); - - if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) { - has_notable_trait = true; - } - } - } - } + && ty.is_doc_subtype_of(&impl_.for_, cx.cache()) + }) + .filter_map(|impl_| impl_.trait_.as_ref()) + .filter_map(|trait_| cx.cache().traits.get(&trait_.def_id())) + .any(|t| t.is_notable_trait(cx.tcx())); has_notable_trait.then(|| { cx.types_with_notable_traits.borrow_mut().insert(ty.clone()); From bfe536342f3bfaacea11ad4957e541d4219ae4ea Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 15 Mar 2025 14:14:25 +0000 Subject: [PATCH 071/163] Optimize multi-char string patterns --- library/core/src/slice/cmp.rs | 2 +- library/core/src/str/pattern.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 804bdfcbb4fc7..da85f42926e6b 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -282,4 +282,4 @@ macro_rules! impl_slice_contains { }; } -impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize); +impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize, char); diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 2d941adfd859c..bcbbb11c83b2f 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -644,21 +644,21 @@ where impl MultiCharEq for [char; N] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&m| m == c) + self.contains(&c) } } impl MultiCharEq for &[char; N] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&m| m == c) + self.contains(&c) } } impl MultiCharEq for &[char] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&m| m == c) + self.contains(&c) } } From e1388bfb036d1511587dd75e917038b9080a43d1 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Sat, 15 Mar 2025 13:54:40 -0400 Subject: [PATCH 072/163] core/slice: Mark some `split_off` variants unstably const Introduce feature `const_split_off_first_last` Mark `split_off_first`, `split_off_first_mut`, `split_off_last`, and `split_off_last_mut` unstably const --- library/core/src/slice/mod.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3570d8d087660..abc1d69357312 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4446,8 +4446,10 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] - pub fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { - let (first, rem) = self.split_first()?; + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((first, rem)) = self.split_first() else { return None }; *self = rem; Some(first) } @@ -4469,8 +4471,11 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] - pub fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { - let (first, rem) = mem::take(self).split_first_mut()?; + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_first_mut()?` + let Some((first, rem)) = mem::replace(self, &mut []).split_first_mut() else { return None }; *self = rem; Some(first) } @@ -4491,8 +4496,10 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] - pub fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { - let (last, rem) = self.split_last()?; + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + // FIXME(const-hack): Use `?` when available in const instead of `let-else`. + let Some((last, rem)) = self.split_last() else { return None }; *self = rem; Some(last) } @@ -4514,8 +4521,11 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] - pub fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { - let (last, rem) = mem::take(self).split_last_mut()?; + #[rustc_const_unstable(feature = "const_split_off_first_last", issue = "138539")] + pub const fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + // FIXME(const-hack): Use `mem::take` and `?` when available in const. + // Original: `mem::take(self).split_last_mut()?` + let Some((last, rem)) = mem::replace(self, &mut []).split_last_mut() else { return None }; *self = rem; Some(last) } From bca5f567d25f81e1924b33938a850f89cd8d4770 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 23 Feb 2025 15:20:53 +1100 Subject: [PATCH 073/163] Add a mir-opt test that demonstrates user type annotations --- ..._type_annotations.let_else.built.after.mir | 81 +++++++++++++++++++ ...otations.let_else_bindless.built.after.mir | 63 +++++++++++++++ ..._type_annotations.let_init.built.after.mir | 54 +++++++++++++ ...otations.let_init_bindless.built.after.mir | 39 +++++++++ ...ype_annotations.let_uninit.built.after.mir | 28 +++++++ ...ations.let_uninit_bindless.built.after.mir | 16 ++++ ...otations.match_assoc_const.built.after.mir | 46 +++++++++++ ...ns.match_assoc_const_range.built.after.mir | 74 +++++++++++++++++ .../mir-opt/building/user_type_annotations.rs | 66 +++++++++++++++ 9 files changed, 467 insertions(+) create mode 100644 tests/mir-opt/building/user_type_annotations.let_else.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.let_init.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir create mode 100644 tests/mir-opt/building/user_type_annotations.rs diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir new file mode 100644 index 0000000000000..4029930c855a4 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -0,0 +1,81 @@ +// MIR for `let_else` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) +| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) +| +fn let_else() -> () { + let mut _0: (); + let mut _1: !; + let _2: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] }; + let _3: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] }; + let _4: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] }; + let mut _5: (u32, u64, &char); + let mut _6: &char; + let _7: &char; + let _8: char; + scope 1 { + debug x => _2; + debug y => _3; + debug z => _4; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + StorageLive(_8); + _8 = const 'u'; + _7 = &_8; + _6 = &(*_7); + _5 = (const 7_u32, const 12_u64, move _6); + StorageDead(_6); + PlaceMention(_5); + falseEdge -> [real: bb4, imaginary: bb3]; + } + + bb1: { + _1 = core::panicking::panic(const "internal error: entered unreachable code") -> bb6; + } + + bb2: { + unreachable; + } + + bb3: { + goto -> bb5; + } + + bb4: { + AscribeUserType(_5, +, UserTypeProjection { base: UserType(2), projs: [] }); + _2 = copy (_5.0: u32); + _3 = copy (_5.1: u64); + _4 = copy (_5.2: &char); + StorageDead(_7); + StorageDead(_5); + _0 = const (); + StorageDead(_8); + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + return; + } + + bb5: { + StorageDead(_7); + StorageDead(_5); + StorageDead(_8); + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + goto -> bb1; + } + + bb6 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir new file mode 100644 index 0000000000000..ffac242e54ed2 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir @@ -0,0 +1,63 @@ +// MIR for `let_else_bindless` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) +| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) +| +fn let_else_bindless() -> () { + let mut _0: (); + let mut _1: !; + let mut _2: (u32, u64, &char); + let mut _3: &char; + let _4: &char; + let _5: char; + scope 1 { + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = const 'u'; + _4 = &_5; + _3 = &(*_4); + _2 = (const 7_u32, const 12_u64, move _3); + StorageDead(_3); + PlaceMention(_2); + falseEdge -> [real: bb4, imaginary: bb3]; + } + + bb1: { + _1 = core::panicking::panic(const "internal error: entered unreachable code") -> bb6; + } + + bb2: { + unreachable; + } + + bb3: { + goto -> bb5; + } + + bb4: { + AscribeUserType(_2, +, UserTypeProjection { base: UserType(2), projs: [] }); + StorageDead(_4); + StorageDead(_2); + _0 = const (); + StorageDead(_5); + return; + } + + bb5: { + StorageDead(_4); + StorageDead(_2); + StorageDead(_5); + goto -> bb1; + } + + bb6 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir new file mode 100644 index 0000000000000..d1b8f823e9bc5 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir @@ -0,0 +1,54 @@ +// MIR for `let_init` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char) +| +fn let_init() -> () { + let mut _0: (); + let _1: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] }; + let _2: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] }; + let _3: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] }; + let mut _4: (u32, u64, &char); + let mut _5: &char; + let _6: &char; + let _7: char; + scope 1 { + debug x => _1; + debug y => _2; + debug z => _3; + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = const 'u'; + _6 = &_7; + _5 = &(*_6); + _4 = (const 7_u32, const 12_u64, move _5); + StorageDead(_5); + PlaceMention(_4); + AscribeUserType(_4, +, UserTypeProjection { base: UserType(1), projs: [] }); + StorageLive(_1); + _1 = copy (_4.0: u32); + StorageLive(_2); + _2 = copy (_4.1: u64); + StorageLive(_3); + _3 = copy (_4.2: &char); + StorageDead(_6); + StorageDead(_4); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + StorageDead(_7); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _4); + unreachable; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir new file mode 100644 index 0000000000000..6702f9300607f --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir @@ -0,0 +1,39 @@ +// MIR for `let_init_bindless` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char) +| +fn let_init_bindless() -> () { + let mut _0: (); + let mut _1: (u32, u64, &char); + let mut _2: &char; + let _3: &char; + let _4: char; + scope 1 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = const 'u'; + _3 = &_4; + _2 = &(*_3); + _1 = (const 7_u32, const 12_u64, move _2); + StorageDead(_2); + PlaceMention(_1); + AscribeUserType(_1, +, UserTypeProjection { base: UserType(1), projs: [] }); + StorageDead(_3); + StorageDead(_1); + _0 = const (); + StorageDead(_4); + return; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir new file mode 100644 index 0000000000000..d86cbc5b192c1 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir @@ -0,0 +1,28 @@ +// MIR for `let_uninit` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char) +| +fn let_uninit() -> () { + let mut _0: (); + let _1: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] }; + let _2: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] }; + let _3: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] }; + scope 1 { + debug x => _1; + debug y => _2; + debug z => _3; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _0 = const (); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir new file mode 100644 index 0000000000000..a85bdacad235e --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir @@ -0,0 +1,16 @@ +// MIR for `let_uninit_bindless` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char) +| +fn let_uninit_bindless() -> () { + let mut _0: (); + scope 1 { + } + + bb0: { + _0 = const (); + return; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir new file mode 100644 index 0000000000000..c0ce6f1d06b5e --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir @@ -0,0 +1,46 @@ +// MIR for `match_assoc_const` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32 +| +fn match_assoc_const() -> () { + let mut _0: (); + let mut _1: u32; + + bb0: { + StorageLive(_1); + _1 = const 8_u32; + PlaceMention(_1); + switchInt(copy _1) -> [99: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const (); + goto -> bb6; + } + + bb2: { + falseEdge -> [real: bb5, imaginary: bb1]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb5: { + AscribeUserType(_1, -, UserTypeProjection { base: UserType(1), projs: [] }); + _0 = const (); + goto -> bb6; + } + + bb6: { + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir new file mode 100644 index 0000000000000..3a6aa5b7c2ca4 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir @@ -0,0 +1,74 @@ +// MIR for `match_assoc_const_range` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32 +| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32 +| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32 +| +fn match_assoc_const_range() -> () { + let mut _0: (); + let mut _1: u32; + let mut _2: bool; + let mut _3: bool; + + bb0: { + StorageLive(_1); + _1 = const 8_u32; + PlaceMention(_1); + _3 = Lt(copy _1, const 99_u32); + switchInt(move _3) -> [0: bb4, otherwise: bb2]; + } + + bb1: { + _0 = const (); + goto -> bb11; + } + + bb2: { + falseEdge -> [real: bb10, imaginary: bb4]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + _2 = Le(const 99_u32, copy _1); + switchInt(move _2) -> [0: bb5, otherwise: bb6]; + } + + bb5: { + goto -> bb1; + } + + bb6: { + falseEdge -> [real: bb9, imaginary: bb1]; + } + + bb7: { + goto -> bb5; + } + + bb8: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb9: { + AscribeUserType(_1, -, UserTypeProjection { base: UserType(3), projs: [] }); + _0 = const (); + goto -> bb11; + } + + bb10: { + AscribeUserType(_1, -, UserTypeProjection { base: UserType(1), projs: [] }); + _0 = const (); + goto -> bb11; + } + + bb11: { + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/building/user_type_annotations.rs b/tests/mir-opt/building/user_type_annotations.rs new file mode 100644 index 0000000000000..d55c678d5ae35 --- /dev/null +++ b/tests/mir-opt/building/user_type_annotations.rs @@ -0,0 +1,66 @@ +//@ edition: 2024 +// skip-filecheck + +// This test demonstrates how many user type annotations are recorded in MIR +// for various binding constructs. In particular, this makes it possible to see +// the number of duplicate user-type-annotation entries, and whether that +// number has changed. +// +// Duplicates are mostly harmless, other than being inefficient. +// "Unused" entries that are _not_ duplicates may nevertheless be necessary so +// that they are seen by MIR lifetime checks. + +// EMIT_MIR user_type_annotations.let_uninit.built.after.mir +fn let_uninit() { + let (x, y, z): (u32, u64, &'static char); +} + +// EMIT_MIR user_type_annotations.let_uninit_bindless.built.after.mir +fn let_uninit_bindless() { + let (_, _, _): (u32, u64, &'static char); +} + +// EMIT_MIR user_type_annotations.let_init.built.after.mir +fn let_init() { + let (x, y, z): (u32, u64, &'static char) = (7, 12, &'u'); +} + +// EMIT_MIR user_type_annotations.let_init_bindless.built.after.mir +fn let_init_bindless() { + let (_, _, _): (u32, u64, &'static char) = (7, 12, &'u'); +} + +// EMIT_MIR user_type_annotations.let_else.built.after.mir +fn let_else() { + let (x, y, z): (u32, u64, &'static char) = (7, 12, &'u') else { unreachable!() }; +} + +// EMIT_MIR user_type_annotations.let_else_bindless.built.after.mir +fn let_else_bindless() { + let (_, _, _): (u32, u64, &'static char) = (7, 12, &'u') else { unreachable!() }; +} + +trait MyTrait<'a> { + const FOO: u32; +} +struct MyStruct {} +impl MyTrait<'static> for MyStruct { + const FOO: u32 = 99; +} + +// EMIT_MIR user_type_annotations.match_assoc_const.built.after.mir +fn match_assoc_const() { + match 8 { + >::FOO => {} + _ => {} + } +} + +// EMIT_MIR user_type_annotations.match_assoc_const_range.built.after.mir +fn match_assoc_const_range() { + match 8 { + ..>::FOO => {} + >::FOO.. => {} + _ => {} + } +} From 977106a215f53cf115cc37cca22cea48501b41e0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 17:43:11 +1100 Subject: [PATCH 074/163] Simplify handling of `visibility_scope` in `declare_bindings` This avoids the need to unwrap an option after ensuring that it is some. --- compiler/rustc_mir_build/src/builder/matches/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b05052a3455ea..89faf705d19ac 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -759,15 +759,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, UserTypeProjections::none(), &mut |this, name, mode, var, span, ty, user_ty| { - if visibility_scope.is_none() { - visibility_scope = - Some(this.new_source_scope(scope_span, LintLevel::Inherited)); - } + let vis_scope = *visibility_scope + .get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited)); let source_info = SourceInfo { span, scope: this.source_scope }; - let visibility_scope = visibility_scope.unwrap(); + this.declare_binding( source_info, - visibility_scope, + vis_scope, name, mode, var, From 7805b465fdb91664a3a41192f4ce40aff313131f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 00:57:37 +1100 Subject: [PATCH 075/163] Split `visit_primary_bindings` into two variants The existing method does some non-obvious extra work to collect user types and build user-type projections, which is specifically needed by `declare_bindings` and not by the other two callers. --- compiler/rustc_middle/src/thir.rs | 4 ++ compiler/rustc_mir_build/src/builder/block.rs | 46 ++++++------- .../src/builder/matches/mod.rs | 65 ++++++++++++------- ..._type_annotations.let_else.built.after.mir | 3 +- ...otations.let_else_bindless.built.after.mir | 3 +- ...ype_annotations.let_uninit.built.after.mir | 1 - ...ations.let_uninit_bindless.built.after.mir | 1 - 7 files changed, 67 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f7b98d935d4de..1056644b813a2 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -783,8 +783,12 @@ pub enum PatKind<'tcx> { var: LocalVarId, ty: Ty<'tcx>, subpattern: Option>>, + /// Is this the leftmost occurrence of the binding, i.e., is `var` the /// `HirId` of this pattern? + /// + /// (The same binding can occur multiple times in different branches of + /// an or-pattern, but only one of them will be primary.) is_primary: bool, }, diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index 7c76e02fcef6a..a71196f79d78d 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -199,19 +199,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, Some((Some(&destination), initializer_span)), ); - this.visit_primary_bindings( - pattern, - UserTypeProjections::none(), - &mut |this, _, _, node, span, _, _| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - ScheduleDrops::Yes, - ); - }, - ); + this.visit_primary_bindings(pattern, &mut |this, node, span| { + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); + }); let else_block_span = this.thir[*else_block].span; let (matching, failure) = this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { @@ -295,20 +291,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); debug!("ast_block_stmts: pattern={:?}", pattern); - this.visit_primary_bindings( - pattern, - UserTypeProjections::none(), - &mut |this, _, _, node, span, _, _| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - ScheduleDrops::Yes, - ); - this.schedule_drop_for_binding(node, span, OutsideGuard); - }, - ) + this.visit_primary_bindings(pattern, &mut |this, node, span| { + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); + this.schedule_drop_for_binding(node, span, OutsideGuard); + }) } // Enter the visibility scope, after evaluating the initializer. diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 89faf705d19ac..60cd8a2c89cb7 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -755,7 +755,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { - self.visit_primary_bindings( + self.visit_primary_bindings_special( pattern, UserTypeProjections::none(), &mut |this, name, mode, var, span, ty, user_ty| { @@ -846,10 +846,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Visit all of the primary bindings in a patterns, that is, visit the - /// leftmost occurrence of each variable bound in a pattern. A variable - /// will occur more than once in an or-pattern. + /// Visits all of the "primary" bindings in a pattern, i.e. the leftmost + /// occurrence of each variable bound by the pattern. + /// See [`PatKind::Binding::is_primary`] for more context. + /// + /// This variant provides only the limited subset of binding data needed + /// by its callers, and should be a "pure" visit without side-effects. pub(super) fn visit_primary_bindings( + &mut self, + pattern: &Pat<'tcx>, + f: &mut impl FnMut(&mut Self, LocalVarId, Span), + ) { + pattern.walk_always(|pat| { + if let PatKind::Binding { var, is_primary: true, .. } = pat.kind { + f(self, var, pat.span); + } + }) + } + + /// Visits all of the "primary" bindings in a pattern, while preparing + /// additional user-type-annotation data needed by `declare_bindings`. + /// + /// This also has the side-effect of pushing all user type annotations + /// onto `canonical_user_type_annotations`, so that they end up in MIR + /// even if they aren't associated with any bindings. + #[instrument(level = "debug", skip(self, f))] + fn visit_primary_bindings_special( &mut self, pattern: &Pat<'tcx>, pattern_user_ty: UserTypeProjections, @@ -863,17 +885,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { UserTypeProjections, ), ) { - debug!( - "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}", - pattern, pattern_user_ty - ); + // Avoid having to write the full method name at each recursive call. + let visit_subpat = |this: &mut Self, subpat, user_tys, f: &mut _| { + this.visit_primary_bindings_special(subpat, user_tys, f) + }; + match pattern.kind { PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => { if is_primary { f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); } if let Some(subpattern) = subpattern.as_ref() { - self.visit_primary_bindings(subpattern, pattern_user_ty, f); + visit_subpat(self, subpattern, pattern_user_ty, f); } } @@ -882,17 +905,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let from = u64::try_from(prefix.len()).unwrap(); let to = u64::try_from(suffix.len()).unwrap(); for subpattern in prefix.iter() { - self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); + visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f); } if let Some(subpattern) = slice { - self.visit_primary_bindings( - subpattern, - pattern_user_ty.clone().subslice(from, to), - f, - ); + visit_subpat(self, subpattern, pattern_user_ty.clone().subslice(from, to), f); } for subpattern in suffix.iter() { - self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); + visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f); } } @@ -903,11 +922,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { - self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); + visit_subpat(self, subpattern, pattern_user_ty.deref(), f); } PatKind::DerefPattern { ref subpattern, .. } => { - self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); + visit_subpat(self, subpattern, UserTypeProjections::none(), f); } PatKind::AscribeUserType { @@ -925,18 +944,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty); - self.visit_primary_bindings(subpattern, subpattern_user_ty, f) + visit_subpat(self, subpattern, subpattern_user_ty, f) } PatKind::ExpandedConstant { ref subpattern, .. } => { - self.visit_primary_bindings(subpattern, pattern_user_ty, f) + visit_subpat(self, subpattern, pattern_user_ty, f) } PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty); - self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); + visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f); } } @@ -944,7 +963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field); - self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f); + visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f); } } PatKind::Or { ref pats } => { @@ -953,7 +972,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `let (x | y) = ...`, the primary binding of `y` occurs in // the right subpattern for subpattern in pats.iter() { - self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f); + visit_subpat(self, subpattern, pattern_user_ty.clone(), f); } } } diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir index 4029930c855a4..3a515787c10b0 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -3,7 +3,6 @@ | User Type Annotations | 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) | 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) -| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char) | fn let_else() -> () { let mut _0: (); @@ -51,7 +50,7 @@ fn let_else() -> () { } bb4: { - AscribeUserType(_5, +, UserTypeProjection { base: UserType(2), projs: [] }); + AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] }); _2 = copy (_5.0: u32); _3 = copy (_5.1: u64); _4 = copy (_5.2: &char); diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir index ffac242e54ed2..52a6d904d4580 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir @@ -3,7 +3,6 @@ | User Type Annotations | 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) | 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) -| 2: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char) | fn let_else_bindless() -> () { let mut _0: (); @@ -42,7 +41,7 @@ fn let_else_bindless() -> () { } bb4: { - AscribeUserType(_2, +, UserTypeProjection { base: UserType(2), projs: [] }); + AscribeUserType(_2, +, UserTypeProjection { base: UserType(1), projs: [] }); StorageDead(_4); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir index d86cbc5b192c1..76b5938b87d2a 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir @@ -2,7 +2,6 @@ | User Type Annotations | 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char) | fn let_uninit() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir index a85bdacad235e..0cd125587714d 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir @@ -2,7 +2,6 @@ | User Type Annotations | 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char) | fn let_uninit_bindless() -> () { let mut _0: (); From 5434242af764d1525bd6ddf6e53ee5567042e381 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 20 Feb 2025 21:44:01 +1100 Subject: [PATCH 076/163] Build `UserTypeProjections` lazily when visiting bindings --- compiler/rustc_middle/src/mir/mod.rs | 85 +---------- .../src/builder/matches/mod.rs | 66 +++++---- .../src/builder/matches/user_ty.rs | 140 ++++++++++++++++++ 3 files changed, 179 insertions(+), 112 deletions(-) create mode 100644 compiler/rustc_mir_build/src/builder/matches/user_ty.rs diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7090e93549e69..4dfb362f3a22b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -33,8 +33,8 @@ use crate::mir::interpret::{AllocRange, Scalar}; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::{ - self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, - TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex, + self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypeVisitableExt, + TypingEnv, UserTypeAnnotationIndex, }; mod basic_blocks; @@ -1482,53 +1482,10 @@ pub struct UserTypeProjections { pub contents: Vec, } -impl<'tcx> UserTypeProjections { - pub fn none() -> Self { - UserTypeProjections { contents: vec![] } - } - - pub fn is_empty(&self) -> bool { - self.contents.is_empty() - } - +impl UserTypeProjections { pub fn projections(&self) -> impl Iterator + ExactSizeIterator { self.contents.iter() } - - pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self { - self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] }); - self - } - - fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self { - self.contents = self.contents.into_iter().map(f).collect(); - self - } - - pub fn index(self) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.index()) - } - - pub fn subslice(self, from: u64, to: u64) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) - } - - pub fn deref(self) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) - } - - pub fn leaf(self, field: FieldIdx) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) - } - - pub fn variant( - self, - adt_def: AdtDef<'tcx>, - variant_index: VariantIdx, - field_index: FieldIdx, - ) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index)) - } } /// Encodes the effect of a user-supplied type annotation on the @@ -1553,42 +1510,6 @@ pub struct UserTypeProjection { pub projs: Vec, } -impl UserTypeProjection { - pub(crate) fn index(mut self) -> Self { - self.projs.push(ProjectionElem::Index(())); - self - } - - pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self { - self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); - self - } - - pub(crate) fn deref(mut self) -> Self { - self.projs.push(ProjectionElem::Deref); - self - } - - pub(crate) fn leaf(mut self, field: FieldIdx) -> Self { - self.projs.push(ProjectionElem::Field(field, ())); - self - } - - pub(crate) fn variant( - mut self, - adt_def: AdtDef<'_>, - variant_index: VariantIdx, - field_index: FieldIdx, - ) -> Self { - self.projs.push(ProjectionElem::Downcast( - Some(adt_def.variant(variant_index).name), - variant_index, - )); - self.projs.push(ProjectionElem::Field(field_index, ())); - self - } -} - rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 60cd8a2c89cb7..ea341b604e0be 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,6 +5,11 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. +use std::assert_matches::assert_matches; +use std::borrow::Borrow; +use std::mem; +use std::sync::Arc; + use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -19,6 +24,7 @@ use tracing::{debug, instrument}; use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::builder::expr::as_place::PlaceBuilder; +use crate::builder::matches::user_ty::ProjectedUserTypesNode; use crate::builder::scope::DropKind; use crate::builder::{ BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, @@ -27,13 +33,9 @@ use crate::builder::{ // helper functions, broken out by category: mod match_pair; mod test; +mod user_ty; mod util; -use std::assert_matches::assert_matches; -use std::borrow::Borrow; -use std::mem; -use std::sync::Arc; - /// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded /// to recursive invocations. #[derive(Clone, Copy)] @@ -757,11 +759,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Option { self.visit_primary_bindings_special( pattern, - UserTypeProjections::none(), - &mut |this, name, mode, var, span, ty, user_ty| { + &ProjectedUserTypesNode::None, + &mut |this, name, mode, var, span, ty, user_tys| { let vis_scope = *visibility_scope .get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited)); let source_info = SourceInfo { span, scope: this.source_scope }; + let user_tys = user_tys.build_user_type_projections(); this.declare_binding( source_info, @@ -770,7 +773,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mode, var, ty, - user_ty, + user_tys, ArmHasGuard(guard.is_some()), opt_match_place.map(|(x, y)| (x.cloned(), y)), pattern.span, @@ -874,7 +877,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn visit_primary_bindings_special( &mut self, pattern: &Pat<'tcx>, - pattern_user_ty: UserTypeProjections, + user_tys: &ProjectedUserTypesNode<'_>, f: &mut impl FnMut( &mut Self, Symbol, @@ -882,21 +885,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LocalVarId, Span, Ty<'tcx>, - UserTypeProjections, + &ProjectedUserTypesNode<'_>, ), ) { // Avoid having to write the full method name at each recursive call. - let visit_subpat = |this: &mut Self, subpat, user_tys, f: &mut _| { + let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| { this.visit_primary_bindings_special(subpat, user_tys, f) }; match pattern.kind { PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => { if is_primary { - f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); + f(self, name, mode, var, pattern.span, ty, user_tys); } if let Some(subpattern) = subpattern.as_ref() { - visit_subpat(self, subpattern, pattern_user_ty, f); + visit_subpat(self, subpattern, user_tys, f); } } @@ -905,13 +908,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let from = u64::try_from(prefix.len()).unwrap(); let to = u64::try_from(suffix.len()).unwrap(); for subpattern in prefix.iter() { - visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f); + visit_subpat(self, subpattern, &user_tys.index(), f); } if let Some(subpattern) = slice { - visit_subpat(self, subpattern, pattern_user_ty.clone().subslice(from, to), f); + visit_subpat(self, subpattern, &user_tys.subslice(from, to), f); } for subpattern in suffix.iter() { - visit_subpat(self, subpattern, pattern_user_ty.clone().index(), f); + visit_subpat(self, subpattern, &user_tys.index(), f); } } @@ -922,11 +925,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { - visit_subpat(self, subpattern, pattern_user_ty.deref(), f); + visit_subpat(self, subpattern, &user_tys.deref(), f); } PatKind::DerefPattern { ref subpattern, .. } => { - visit_subpat(self, subpattern, UserTypeProjections::none(), f); + visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } PatKind::AscribeUserType { @@ -942,28 +945,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Note that the variance doesn't apply here, as we are tracking the effect // of `user_ty` on any bindings contained with subpattern. + // Caution: Pushing this user type here is load-bearing even for + // patterns containing no bindings, to ensure that the type ends + // up represented in MIR _somewhere_. let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); - let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty); - visit_subpat(self, subpattern, subpattern_user_ty, f) + let subpattern_user_tys = user_tys.push_user_type(base_user_ty); + visit_subpat(self, subpattern, &subpattern_user_tys, f) } PatKind::ExpandedConstant { ref subpattern, .. } => { - visit_subpat(self, subpattern, pattern_user_ty, f) + visit_subpat(self, subpattern, user_tys, f) } PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); - debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty); - visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f); + let subpattern_user_tys = user_tys.leaf(subpattern.field); + debug!("visit_primary_bindings: subpattern_user_tys={subpattern_user_tys:?}"); + visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f); } } PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = - pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field); - visit_subpat(self, &subpattern.pattern, subpattern_user_ty, f); + let subpattern_user_tys = + user_tys.variant(adt_def, variant_index, subpattern.field); + visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f); } } PatKind::Or { ref pats } => { @@ -972,7 +978,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `let (x | y) = ...`, the primary binding of `y` occurs in // the right subpattern for subpattern in pats.iter() { - visit_subpat(self, subpattern, pattern_user_ty.clone(), f); + visit_subpat(self, subpattern, user_tys, f); } } } @@ -2764,7 +2770,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mode: BindingMode, var_id: LocalVarId, var_ty: Ty<'tcx>, - user_ty: UserTypeProjections, + user_ty: Option>, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, @@ -2774,7 +2780,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local = LocalDecl { mutability: mode.1, ty: var_ty, - user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, + user_ty, source_info, local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( VarBindingForm { diff --git a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs new file mode 100644 index 0000000000000..df9f93ac328a6 --- /dev/null +++ b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs @@ -0,0 +1,140 @@ +//! Helper code for building a linked list of user-type projections on the +//! stack while visiting a THIR pattern. +//! +//! This avoids having to repeatedly clone a partly-built [`UserTypeProjections`] +//! at every step of the traversal, which is what the previous code was doing. + +use std::assert_matches::assert_matches; +use std::iter; + +use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; +use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex}; +use rustc_span::Symbol; + +/// One of a list of "operations" that can be used to lazily build projections +/// of user-specified types. +#[derive(Clone, Debug)] +pub(crate) enum ProjectedUserTypesOp { + PushUserType { base: UserTypeAnnotationIndex }, + + Index, + Subslice { from: u64, to: u64 }, + Deref, + Leaf { field: FieldIdx }, + Variant { name: Symbol, variant: VariantIdx, field: FieldIdx }, +} + +#[derive(Debug)] +pub(crate) enum ProjectedUserTypesNode<'a> { + None, + Chain { parent: &'a Self, op: ProjectedUserTypesOp }, +} + +impl<'a> ProjectedUserTypesNode<'a> { + pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self { + // Pushing a base user type always causes the chain to become non-empty. + Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } } + } + + /// Push another projection op onto the chain, but only if it is already non-empty. + fn maybe_push(&'a self, op_fn: impl FnOnce() -> ProjectedUserTypesOp) -> Self { + match self { + Self::None => Self::None, + Self::Chain { .. } => Self::Chain { parent: self, op: op_fn() }, + } + } + + pub(crate) fn index(&'a self) -> Self { + self.maybe_push(|| ProjectedUserTypesOp::Index) + } + + pub(crate) fn subslice(&'a self, from: u64, to: u64) -> Self { + self.maybe_push(|| ProjectedUserTypesOp::Subslice { from, to }) + } + + pub(crate) fn deref(&'a self) -> Self { + self.maybe_push(|| ProjectedUserTypesOp::Deref) + } + + pub(crate) fn leaf(&'a self, field: FieldIdx) -> Self { + self.maybe_push(|| ProjectedUserTypesOp::Leaf { field }) + } + + pub(crate) fn variant( + &'a self, + adt_def: AdtDef<'_>, + variant: VariantIdx, + field: FieldIdx, + ) -> Self { + self.maybe_push(|| { + let name = adt_def.variant(variant).name; + ProjectedUserTypesOp::Variant { name, variant, field } + }) + } + + /// Traverses the chain of nodes to yield each op in the chain. + /// Because this walks from child node to parent node, the ops are + /// naturally yielded in "reverse" order. + fn iter_ops_reversed(&'a self) -> impl Iterator { + let mut next = self; + iter::from_fn(move || match next { + Self::None => None, + Self::Chain { parent, op } => { + next = parent; + Some(op) + } + }) + } + + /// Assembles this chain of user-type projections into a proper data structure. + pub(crate) fn build_user_type_projections(&self) -> Option> { + // If we know there's nothing to do, just return None immediately. + if matches!(self, Self::None) { + return None; + } + + let ops_reversed = self.iter_ops_reversed().cloned().collect::>(); + // The "first" op should always be `PushUserType`. + // Other projections are only added if there is at least one user type. + assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserType { .. })); + + let mut projections = vec![]; + for op in ops_reversed.into_iter().rev() { + match op { + ProjectedUserTypesOp::PushUserType { base } => { + projections.push(UserTypeProjection { base, projs: vec![] }) + } + + ProjectedUserTypesOp::Index => { + for p in &mut projections { + p.projs.push(ProjectionElem::Index(())) + } + } + ProjectedUserTypesOp::Subslice { from, to } => { + for p in &mut projections { + p.projs.push(ProjectionElem::Subslice { from, to, from_end: true }) + } + } + ProjectedUserTypesOp::Deref => { + for p in &mut projections { + p.projs.push(ProjectionElem::Deref) + } + } + ProjectedUserTypesOp::Leaf { field } => { + for p in &mut projections { + p.projs.push(ProjectionElem::Field(field, ())) + } + } + ProjectedUserTypesOp::Variant { name, variant, field } => { + for p in &mut projections { + p.projs.push(ProjectionElem::Downcast(Some(name), variant)); + p.projs.push(ProjectionElem::Field(field, ())); + } + } + } + } + + Some(Box::new(UserTypeProjections { contents: projections })) + } +} From ec4b3c2779883a6b7ebb1ce5954904ef2c95d3a4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 16 Mar 2025 14:28:10 +0100 Subject: [PATCH 077/163] Add test for new proc_macro literal methods --- library/literal-escaper/README.md | 2 +- library/proc_macro/src/lib.rs | 1 + tests/ui/proc-macro/auxiliary/api/literal.rs | 53 ++++++++++++++++++- .../auxiliary/api/proc_macro_api_tests.rs | 1 + 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/library/literal-escaper/README.md b/library/literal-escaper/README.md index 5384ac4556a13..9986d2451c759 100644 --- a/library/literal-escaper/README.md +++ b/library/literal-escaper/README.md @@ -1,4 +1,4 @@ # literal-escaper This crate provides code to unescape string literals. It is used by `rustc_lexer` -and `proc-macro`. +and `proc_macro`. diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 57dd47f106089..b1de87a4b0819 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -61,6 +61,7 @@ use crate::escape::{EscapeOptions, escape_bytes}; /// Errors returned when trying to retrieve a literal unescaped value. #[unstable(feature = "proc_macro_value", issue = "136652")] +#[derive(Debug, PartialEq, Eq)] pub enum ConversionErrorKind { /// The literal failed to be escaped, take a look at [`EscapeError`] for more information. FailedToUnescape(EscapeError), diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs index 7109340bb645b..941de1521ade9 100644 --- a/tests/ui/proc-macro/auxiliary/api/literal.rs +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -1,10 +1,11 @@ // ignore-tidy-linelength -use proc_macro::Literal; +use proc_macro::{ConversionErrorKind, Literal}; pub fn test() { test_display_literal(); test_parse_literal(); + test_str_value_methods(); } fn test_display_literal() { @@ -81,3 +82,53 @@ fn test_parse_literal() { assert!("- 10".parse::().is_err()); assert!("-'x'".parse::().is_err()); } + +fn test_str_value_methods() { + // Testing `str_value` + let lit = "\"\n\"".parse::().unwrap(); + assert_eq!(lit.str_value(), Ok("\n".to_string())); + + let lit = "r#\"\n\"#".parse::().unwrap(); + assert_eq!(lit.str_value(), Ok("\n".to_string())); + + let lit = "1".parse::().unwrap(); + assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "b\"\n\"".parse::().unwrap(); + assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "c\"\n\"".parse::().unwrap(); + assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + // Testing `cstr_value` + let lit = "\"\n\"".parse::().unwrap(); + assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "r#\"\n\"#".parse::().unwrap(); + assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "1".parse::().unwrap(); + assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "b\"\n\"".parse::().unwrap(); + assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "c\"\n\"".parse::().unwrap(); + assert_eq!(lit.cstr_value(), Ok(vec![b'\n', 0])); + + // Testing `byte_str_value` + let lit = "\"\n\"".parse::().unwrap(); + assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "r#\"\n\"#".parse::().unwrap(); + assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "1".parse::().unwrap(); + assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); + + let lit = "b\"\n\"".parse::().unwrap(); + assert_eq!(lit.byte_str_value(), Ok(vec![b'\n'])); + + let lit = "c\"\n\"".parse::().unwrap(); + assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind)); +} diff --git a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs index abd667d8ce1d0..390d46852cd54 100644 --- a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs +++ b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs @@ -1,6 +1,7 @@ //@ edition: 2021 #![feature(proc_macro_span)] +#![feature(proc_macro_value)] #![deny(dead_code)] // catch if a test function is never called extern crate proc_macro; From ab7fb0d483027632f22e22ecd7d2c7bfc1f3ac10 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 16 Mar 2025 13:01:11 +0800 Subject: [PATCH 078/163] Add a centralized test for print request stability gating I can't find any dedicated tests that actually exercises the stability gating (via `-Z unstable-options`) of print requests, so here's a dedicated one. I coalesced `tests/ui/feature-gates/feature-gate-print-check-cfg.rs` into this test, because AFAICT that print request is not feature gated, but only `-Z unstable-options`-gated just like other unstable print requests. --- .../feature-gate-print-check-cfg.rs | 3 - .../feature-gate-print-check-cfg.stderr | 2 - tests/ui/print-request/stability.rs | 103 ++++++++++++++++++ 3 files changed, 103 insertions(+), 5 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-print-check-cfg.rs delete mode 100644 tests/ui/feature-gates/feature-gate-print-check-cfg.stderr create mode 100644 tests/ui/print-request/stability.rs diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.rs b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs deleted file mode 100644 index 304e0c132e50a..0000000000000 --- a/tests/ui/feature-gates/feature-gate-print-check-cfg.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@ compile-flags: --print=check-cfg - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr deleted file mode 100644 index 62ee44b94a489..0000000000000 --- a/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the check-cfg print option - diff --git a/tests/ui/print-request/stability.rs b/tests/ui/print-request/stability.rs new file mode 100644 index 0000000000000..b205b05556912 --- /dev/null +++ b/tests/ui/print-request/stability.rs @@ -0,0 +1,103 @@ +//! Check that we properly gate unstable print requests (`--print=KIND`) and require the user to +//! specify `-Z unstable-options` to use unstable print requests. + +// We don't care about the exact *stdout* output (i.e. what the print requests actually give back) +// for the purposes of this test. +//@ dont-check-compiler-stdout + +// We want to check for the core error message of the unstable print requests being `-Z +// unstable-options`-gated and not the help because the help can change with addition of a new print +// request, which is not important for the purposes of this test. +//@ dont-check-compiler-stderr + +// ======================= +// Unstable print requests +// ======================= + +//@ revisions: all_target_specs_json +//@[all_target_specs_json] compile-flags: --print=all-target-specs-json +//@[all_target_specs_json] error-pattern: the `-Z unstable-options` flag must also be passed + +//@ revisions: check_cfg +//@[check_cfg] compile-flags: --print=check-cfg +//@[check_cfg] error-pattern: the `-Z unstable-options` flag must also be passed + +//@ revisions: target_spec_json +//@[target_spec_json] compile-flags: --print=target-spec-json +//@[target_spec_json] error-pattern: the `-Z unstable-options` flag must also be passed + +// ======================= +// Stable print requests +// ======================= + +//@ revisions: calling_conventions +//@[calling_conventions] compile-flags: --print=calling-conventions +//@[calling_conventions] check-pass + +//@ revisions: cfg +//@[cfg] compile-flags: --print=cfg +//@[cfg] check-pass + +//@ revisions: code_models +//@[code_models] compile-flags: --print=code-models +//@[code_models] check-pass + +//@ revisions: crate_name +//@[crate_name] compile-flags: --print=crate-name +//@[crate_name] check-pass + +// Note: `--print=deployment_target` is only accepted on Apple targets. +//@ revisions: deployment_target +//@[deployment_target] only-apple +//@[deployment_target] compile-flags: --print=deployment-target +//@[deployment_target] check-pass + +//@ revisions: file_names +//@[file_names] compile-flags: --print=file-names +//@[file_names] check-pass + +//@ revisions: host_tuple +//@[host_tuple] compile-flags: --print=host-tuple +//@[host_tuple] check-pass + +//@ revisions: link_args +//@[link_args] compile-flags: --print=link-args +//@[link_args] check-pass + +//@ revisions: native_static_libs +//@[native_static_libs] compile-flags: --print=native-static-libs +//@[native_static_libs] check-pass + +//@ revisions: relocation_models +//@[relocation_models] compile-flags: --print=relocation-models +//@[relocation_models] check-pass + +//@ revisions: split_debuginfo +//@[split_debuginfo] compile-flags: --print=split-debuginfo +//@[split_debuginfo] check-pass + +//@ revisions: stack_protector_strategies +//@[stack_protector_strategies] compile-flags: --print=stack-protector-strategies +//@[stack_protector_strategies] check-pass + +//@ revisions: target_cpus +//@[target_cpus] compile-flags: --print=target-cpus +//@[target_cpus] check-pass + +//@ revisions: target_features +//@[target_features] compile-flags: --print=target-features +//@[target_features] check-pass + +//@ revisions: target_libdir +//@[target_libdir] compile-flags: --print=target-libdir +//@[target_libdir] check-pass + +//@ revisions: target_list +//@[target_list] compile-flags: --print=target-list +//@[target_list] check-pass + +//@ revisions: tls_models +//@[tls_models] compile-flags: --print=tls-models +//@[tls_models] check-pass + +fn main() {} From 5f8e0920f9911d7919d087295543ac3432cf1326 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 16 Mar 2025 11:46:09 +0800 Subject: [PATCH 079/163] Alphabetically sort `PrintKind` and enforce with tidy --- compiler/rustc_session/src/config.rs | 32 +++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 34755249b60b1..96006433b60f4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -873,27 +873,29 @@ pub struct PrintRequest { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PrintKind { + // tidy-alphabetical-start + AllTargetSpecs, + CallingConventions, + Cfg, + CheckCfg, + CodeModels, + CrateName, + DeploymentTarget, FileNames, HostTuple, + LinkArgs, + NativeStaticLibs, + RelocationModels, + SplitDebuginfo, + StackProtectorStrategies, Sysroot, - TargetLibdir, - CrateName, - Cfg, - CheckCfg, - CallingConventions, - TargetList, TargetCPUs, TargetFeatures, - RelocationModels, - CodeModels, - TlsModels, + TargetLibdir, + TargetList, TargetSpec, - AllTargetSpecs, - NativeStaticLibs, - StackProtectorStrategies, - LinkArgs, - SplitDebuginfo, - DeploymentTarget, + TlsModels, + // tidy-alphabetical-end } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] From f9eabc28d94aec376f7649ba785c86e922702a37 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 16 Mar 2025 12:19:16 +0800 Subject: [PATCH 080/163] Extract print request stability gating and unknown print request help into helpers To avoid duplicating stability check logic and make the print request collection logic more straightforward. --- compiler/rustc_session/src/config.rs | 78 +++++++++++++--------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 96006433b60f4..bc20d97096861 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2032,49 +2032,13 @@ fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); - let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { - Some((_, PrintKind::TargetSpec)) => { - if unstable_opts.unstable_options { - PrintKind::TargetSpec - } else { - early_dcx.early_fatal( - "the `-Z unstable-options` flag must also be passed to \ - enable the target-spec-json print option", - ); - } - } - Some((_, PrintKind::AllTargetSpecs)) => { - if unstable_opts.unstable_options { - PrintKind::AllTargetSpecs - } else { - early_dcx.early_fatal( - "the `-Z unstable-options` flag must also be passed to \ - enable the all-target-specs-json print option", - ); - } - } - Some((_, PrintKind::CheckCfg)) => { - if unstable_opts.unstable_options { - PrintKind::CheckCfg - } else { - early_dcx.early_fatal( - "the `-Z unstable-options` flag must also be passed to \ - enable the check-cfg print option", - ); - } - } - Some(&(_, print_kind)) => print_kind, - None => { - let prints = - PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); - let prints = prints.join(", "); - - let mut diag = - early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); - #[allow(rustc::diagnostic_outside_of_impl)] - diag.help(format!("valid print requests are: {prints}")); - diag.emit() - } + let kind = if let Some((print_name, print_kind)) = + PRINT_KINDS.iter().find(|&&(name, _)| name == req) + { + check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind)); + *print_kind + } else { + emit_unknown_print_request_help(early_dcx, req) }; let out = out.unwrap_or(OutFileName::Stdout); @@ -2093,6 +2057,34 @@ fn collect_print_requests( prints } +fn check_print_request_stability( + early_dcx: &EarlyDiagCtxt, + unstable_opts: &UnstableOptions, + (print_name, print_kind): (&str, PrintKind), +) { + match print_kind { + PrintKind::AllTargetSpecs | PrintKind::CheckCfg | PrintKind::TargetSpec + if !unstable_opts.unstable_options => + { + early_dcx.early_fatal(format!( + "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \ + print option" + )); + } + _ => {} + } +} + +fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! { + let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); + let prints = prints.join(", "); + + let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); + #[allow(rustc::diagnostic_outside_of_impl)] + diag.help(format!("valid print requests are: {prints}")); + diag.emit() +} + pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple { match matches.opt_str("target") { Some(target) if target.ends_with(".json") => { From 24edbfbc2433be60207daefbdf1d59ed3b1cbf7d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 16 Mar 2025 12:58:53 +0800 Subject: [PATCH 081/163] Rename `PrintKind::{AllTargetSpecs,TargetSpec}` to `{AllTargetSpecsJson,TargetSpecJson}` To correspond to their actual print request names, `target-spec-json` and `all-target-specs-json`, and for consistency with other print name <-> print kind mappings. --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- compiler/rustc_session/src/config.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index ed5662da16dc9..2d636da4a128b 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -649,10 +649,10 @@ fn print_crate_info( HostTuple => println_info!("{}", rustc_session::config::host_tuple()), Sysroot => println_info!("{}", sess.sysroot.display()), TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()), - TargetSpec => { + TargetSpecJson => { println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } - AllTargetSpecs => { + AllTargetSpecsJson => { let mut targets = BTreeMap::new(); for name in rustc_target::spec::TARGETS { let triple = TargetTuple::from_tuple(name); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index bc20d97096861..701d06e4fd403 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -44,7 +44,7 @@ pub mod sigpipe; pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ // tidy-alphabetical-start - ("all-target-specs-json", PrintKind::AllTargetSpecs), + ("all-target-specs-json", PrintKind::AllTargetSpecsJson), ("calling-conventions", PrintKind::CallingConventions), ("cfg", PrintKind::Cfg), ("check-cfg", PrintKind::CheckCfg), @@ -63,7 +63,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ ("target-features", PrintKind::TargetFeatures), ("target-libdir", PrintKind::TargetLibdir), ("target-list", PrintKind::TargetList), - ("target-spec-json", PrintKind::TargetSpec), + ("target-spec-json", PrintKind::TargetSpecJson), ("tls-models", PrintKind::TlsModels), // tidy-alphabetical-end ]; @@ -874,7 +874,7 @@ pub struct PrintRequest { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PrintKind { // tidy-alphabetical-start - AllTargetSpecs, + AllTargetSpecsJson, CallingConventions, Cfg, CheckCfg, @@ -893,7 +893,7 @@ pub enum PrintKind { TargetFeatures, TargetLibdir, TargetList, - TargetSpec, + TargetSpecJson, TlsModels, // tidy-alphabetical-end } @@ -2063,7 +2063,7 @@ fn check_print_request_stability( (print_name, print_kind): (&str, PrintKind), ) { match print_kind { - PrintKind::AllTargetSpecs | PrintKind::CheckCfg | PrintKind::TargetSpec + PrintKind::AllTargetSpecsJson | PrintKind::CheckCfg | PrintKind::TargetSpecJson if !unstable_opts.unstable_options => { early_dcx.early_fatal(format!( From 24396232784c706c603ce686c08d8715106e2d59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Feb 2025 23:57:56 +0000 Subject: [PATCH 082/163] Make ControlFlow must_use --- library/core/src/ops/control_flow.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 0d910685927e0..ef7e6f9c2f491 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -80,6 +80,7 @@ use crate::{convert, ops}; /// [`Continue`]: ControlFlow::Continue #[stable(feature = "control_flow_enum_type", since = "1.55.0")] #[rustc_diagnostic_item = "ControlFlow"] +#[must_use] // ControlFlow should not implement PartialOrd or Ord, per RFC 3058: // https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] From 380ce744010a260b7357a147562c7698a731cc50 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Feb 2025 23:55:08 +0000 Subject: [PATCH 083/163] Suppress must_use in compiler and tools --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 18 +++++--- .../infer/nice_region_error/find_anon_type.rs | 4 +- .../src/traits/project.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 2 +- compiler/rustc_type_ir/src/binder.rs | 6 +-- src/librustdoc/html/length_limit/tests.rs | 46 +++++++++---------- src/librustdoc/html/markdown.rs | 2 +- .../clippy_lints/src/loops/mut_range_bound.rs | 2 +- .../src/methods/read_line_without_trim.rs | 2 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- .../src/unconditional_recursion.rs | 2 +- 13 files changed, 49 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ea961f222db04..74f4393754670 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2131,7 +2131,7 @@ fn add_library_search_dirs( } let fallback = Some(NativeLibSearchFallback { self_contained_components, apple_sdk_root }); - walk_native_lib_search_dirs(sess, fallback, |dir, is_framework| { + let _ = walk_native_lib_search_dirs(sess, fallback, |dir, is_framework| { if is_framework { cmd.framework_path(dir); } else { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 1a1540f505d37..943661fbd56e9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -533,7 +533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } _ => { - intravisit::walk_pat(self, p); + let _ = intravisit::walk_pat(self, p); } } ControlFlow::Continue(()) @@ -556,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method_name, sugg_let: None, }; - let_visitor.visit_body(&body); + let _ = let_visitor.visit_body(&body); if let Some(sugg_let) = let_visitor.sugg_let && let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index cf32f237b8676..6ed7aabcb290a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1361,12 +1361,12 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { - self.visit(self.tcx.type_of(param.def_id).instantiate_identity()); + let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity()); } } // FIXME(generic_const_exprs): May want to look inside const here GenericParamDefKind::Const { .. } => { - self.visit(self.tcx.type_of(param.def_id).instantiate_identity()); + let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity()); } } } @@ -1381,19 +1381,19 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { // consider the ones that the user wrote. This is important // for the inferred outlives rules; see // `tests/ui/rfc-2093-infer-outlives/privacy.rs`. - self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id)); + let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id)); self } fn bounds(&mut self) -> &mut Self { self.in_primary_interface = false; - self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder()); + let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder()); self } fn ty(&mut self) -> &mut Self { self.in_primary_interface = true; - self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity()); + let _ = self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity()); self } @@ -1785,7 +1785,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let module = tcx.hir_module_items(module_def_id); for def_id in module.definitions() { - rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor); + let _ = rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor); if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) { visitor.visit_nested_body(body_id.id()); @@ -1798,7 +1798,11 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap(); let trait_ref = trait_ref.instantiate_identity(); visitor.span = item.path.span; - visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path()); + let _ = visitor.visit_def_id( + trait_ref.def_id, + "trait", + &trait_ref.print_only_trait_path(), + ); } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 5a303c3cd03c7..139b299713688 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -77,7 +77,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { match arg.kind { hir::TyKind::BareFn(_) => { self.current_index.shift_in(1); - intravisit::walk_ty(self, arg); + let _ = intravisit::walk_ty(self, arg); self.current_index.shift_out(1); return ControlFlow::Continue(()); } @@ -85,7 +85,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { hir::TyKind::TraitObject(bounds, ..) => { for bound in bounds { self.current_index.shift_in(1); - self.visit_poly_trait_ref(bound); + let _ = self.visit_poly_trait_ref(bound); self.current_index.shift_out(1); } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index be5d6286e2604..2c60be63bd561 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -743,7 +743,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ) { debug!("assemble_candidates_from_trait_def(..)"); let mut ambiguous = false; - selcx.for_each_item_bound( + let _ = selcx.for_each_item_bound( obligation.predicate.self_ty(), |selcx, clause, _| { let Some(clause) = clause.as_projection_clause() else { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a8d8003ead6ea..fc352499146eb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -176,7 +176,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // normalization, so try to deduplicate when possible to avoid // unnecessary ambiguity. let mut distinct_normalized_bounds = FxHashSet::default(); - self.for_each_item_bound::( + let _ = self.for_each_item_bound::( placeholder_trait_predicate.self_ty(), |selcx, bound, idx| { let Some(bound) = bound.as_trait_clause() else { diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index c8b71074de7b4..e9055940310d0 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -112,7 +112,7 @@ where pub fn bind_with_vars(value: T, bound_vars: I::BoundVarKinds) -> Binder { if cfg!(debug_assertions) { let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); + let _ = value.visit_with(&mut validator); } Binder { value, bound_vars } } @@ -196,7 +196,7 @@ impl Binder { let value = f(value); if cfg!(debug_assertions) { let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); + let _ = value.visit_with(&mut validator); } Binder { value, bound_vars } } @@ -209,7 +209,7 @@ impl Binder { let value = f(value)?; if cfg!(debug_assertions) { let mut validator = ValidateBoundVars::new(bound_vars); - value.visit_with(&mut validator); + let _ = value.visit_with(&mut validator); } Ok(Binder { value, bound_vars }) } diff --git a/src/librustdoc/html/length_limit/tests.rs b/src/librustdoc/html/length_limit/tests.rs index 2185c034890fa..4ebecfd5f2414 100644 --- a/src/librustdoc/html/length_limit/tests.rs +++ b/src/librustdoc/html/length_limit/tests.rs @@ -9,41 +9,41 @@ fn empty() { #[test] fn basic() { let mut buf = HtmlWithLimit::new(60); - buf.push("Hello "); + let _ = buf.push("Hello "); buf.open_tag("em"); - buf.push("world"); + let _ = buf.push("world"); buf.close_tag(); - buf.push("!"); + let _ = buf.push("!"); assert_eq!(buf.finish(), "Hello world!"); } #[test] fn no_tags() { let mut buf = HtmlWithLimit::new(60); - buf.push("Hello"); - buf.push(" world!"); + let _ = buf.push("Hello"); + let _ = buf.push(" world!"); assert_eq!(buf.finish(), "Hello world!"); } #[test] fn limit_0() { let mut buf = HtmlWithLimit::new(0); - buf.push("Hello "); + let _ = buf.push("Hello "); buf.open_tag("em"); - buf.push("world"); + let _ = buf.push("world"); buf.close_tag(); - buf.push("!"); + let _ = buf.push("!"); assert_eq!(buf.finish(), ""); } #[test] fn exactly_limit() { let mut buf = HtmlWithLimit::new(12); - buf.push("Hello "); + let _ = buf.push("Hello "); buf.open_tag("em"); - buf.push("world"); + let _ = buf.push("world"); buf.close_tag(); - buf.push("!"); + let _ = buf.push("!"); assert_eq!(buf.finish(), "Hello world!"); } @@ -51,11 +51,11 @@ fn exactly_limit() { fn multiple_nested_tags() { let mut buf = HtmlWithLimit::new(60); buf.open_tag("p"); - buf.push("This is a "); + let _ = buf.push("This is a "); buf.open_tag("em"); - buf.push("paragraph"); + let _ = buf.push("paragraph"); buf.open_tag("strong"); - buf.push("!"); + let _ = buf.push("!"); buf.close_tag(); buf.close_tag(); buf.close_tag(); @@ -66,11 +66,11 @@ fn multiple_nested_tags() { fn forgot_to_close_tags() { let mut buf = HtmlWithLimit::new(60); buf.open_tag("p"); - buf.push("This is a "); + let _ = buf.push("This is a "); buf.open_tag("em"); - buf.push("paragraph"); + let _ = buf.push("paragraph"); buf.open_tag("strong"); - buf.push("!"); + let _ = buf.push("!"); assert_eq!(buf.finish(), "

This is a paragraph!

"); } @@ -78,10 +78,10 @@ fn forgot_to_close_tags() { fn past_the_limit() { let mut buf = HtmlWithLimit::new(20); buf.open_tag("p"); - (0..10).try_for_each(|n| { + let _ = (0..10).try_for_each(|n| { buf.open_tag("strong"); - buf.push("word#")?; - buf.push(&n.to_string())?; + let _ = buf.push("word#")?; + let _ = buf.push(&n.to_string())?; buf.close_tag(); ControlFlow::Continue(()) }); @@ -100,8 +100,8 @@ fn past_the_limit() { fn quickly_past_the_limit() { let mut buf = HtmlWithLimit::new(6); buf.open_tag("p"); - buf.push("Hello"); - buf.push(" World"); + let _ = buf.push("Hello"); + let _ = buf.push(" World"); // intentionally not closing

before finishing assert_eq!(buf.finish(), "

Hello

"); } @@ -110,7 +110,7 @@ fn quickly_past_the_limit() { fn close_too_many() { let mut buf = HtmlWithLimit::new(60); buf.open_tag("p"); - buf.push("Hello"); + let _ = buf.push("Hello"); buf.close_tag(); // This call does not panic because there are valid cases // where `close_tag()` is called with no tags left to close. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 079651e860319..b067dbf750e7d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1568,7 +1568,7 @@ fn markdown_summary_with_limit( let mut buf = HtmlWithLimit::new(length_limit); let mut stopped_early = false; - p.try_for_each(|event| { + let _ = p.try_for_each(|event| { match &event { Event::Text(text) => { let r = diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index fb5d49a100475..5afcf51167d47 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -129,7 +129,7 @@ impl BreakAfterExprVisitor { }; get_enclosing_block(cx, hir_id).is_some_and(|block| { - visitor.visit_block(block); + let _ = visitor.visit_block(block); visitor.break_after_expr }) } diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index c9251c1b84979..fe999a3b5f8f2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -40,7 +40,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< // We've checked that `call` is a call to `Stdin::read_line()` with the right receiver, // now let's check if the first use of the string passed to `::read_line()` // is used for operations that will always fail (e.g. parsing "6\n" into a number) - for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| { + let _ = for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| { if let Some(parent) = get_parent_expr(cx, expr) { let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind { if args.is_empty() diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 320c0286bb7be..0a8e288564875 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -141,7 +141,7 @@ impl PassByRefOrValue { // Gather all the lifetimes found in the output type which may affect whether // `TRIVIALLY_COPY_PASS_BY_REF` should be linted. let mut output_regions = FxHashSet::default(); - for_each_top_level_late_bound_region(fn_sig.skip_binder().output(), |region| -> ControlFlow { + let _ = for_each_top_level_late_bound_region(fn_sig.skip_binder().output(), |region| -> ControlFlow { output_regions.insert(region); ControlFlow::Continue(()) }); diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index a443043bef902..51c7d6fce3128 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -381,7 +381,7 @@ impl UnconditionalRecursion { implemented_ty_id, method_span, }; - walk_body(&mut c, body); + let _ = walk_body(&mut c, body); } } } From e250bd16da5d3016c45e91431fd7b97822f771c0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 22 Feb 2025 23:54:56 +0000 Subject: [PATCH 084/163] Suppress must_use for ControlFlow in rust-analyzer --- src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs | 8 ++++---- .../rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs | 4 ++-- .../crates/hir-ty/src/dyn_compatibility/tests.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/method_resolution.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/attrs.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +++--- .../crates/ide-assists/src/handlers/extract_function.rs | 2 +- .../crates/ide-db/src/syntax_helpers/node_ext.rs | 4 ++-- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 67fb73696f766..65fb342f75258 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -145,19 +145,19 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { let mut result = vec![]; if fps.is_empty() { debug!("Unrestricted search for {:?} impls...", trait_); - self.for_trait_impls(trait_, self_ty_fp, |impls| { + let _ = self.for_trait_impls(trait_, self_ty_fp, |impls| { result.extend(impls.for_trait(trait_).map(id_to_chalk)); ControlFlow::Continue(()) - }) + }); } else { - self.for_trait_impls(trait_, self_ty_fp, |impls| { + let _ = self.for_trait_impls(trait_, self_ty_fp, |impls| { result.extend( fps.iter().flat_map(move |fp| { impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) }), ); ControlFlow::Continue(()) - }) + }); }; debug!("impls_for_trait returned {} impls", result.len()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 6a01579bccc9d..e042c35d0c6f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -116,7 +116,7 @@ pub fn dyn_compatibility_of_trait_query( trait_: TraitId, ) -> Option { let mut res = None; - dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| { + let _ = dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| { res = Some(osv); ControlFlow::Break(()) }); @@ -597,7 +597,7 @@ fn contains_illegal_impl_trait_in_trait( let ret = sig.skip_binders().ret(); let mut visitor = OpaqueTypeCollector(FxHashSet::default()); - ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST); + let _ = ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST); // Since we haven't implemented RPITIT in proper way like rustc yet, // just check whether `ret` contains RPIT for now diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 3060b610bb694..50851325bd519 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -53,7 +53,7 @@ fn check_dyn_compatibility<'a>( continue; }; let mut osvs = FxHashSet::default(); - dyn_compatibility_with_callback(&db, trait_id, &mut |osv| { + let _ = dyn_compatibility_with_callback(&db, trait_id, &mut |osv| { osvs.insert(match osv { DynCompatibilityViolation::SizedSelf => SizedSelf, DynCompatibilityViolation::SelfReferential => SelfReferential, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 556091c404614..3e0ce7f1933a3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1143,7 +1143,7 @@ impl<'a> InferenceContext<'a> { non_assocs: FxHashMap::default(), }; for ty in tait_candidates { - ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); + let _ = ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); } // Non-assoc TAITs can be define-used everywhere as long as they are diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 624767cedf822..cc02b71f05c19 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -1033,7 +1033,7 @@ where T: ?Sized + TypeVisitable, { let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() }; - value.visit_with(&mut collector, DebruijnIndex::INNERMOST); + let _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST); collector.placeholders.into_iter().collect() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index db94351dcc995..c722800527190 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -596,7 +596,7 @@ pub(crate) fn iterate_method_candidates( mut callback: impl FnMut(ReceiverAdjustments, AssocItemId, bool) -> Option, ) -> Option { let mut slot = None; - iterate_method_candidates_dyn( + let _ = iterate_method_candidates_dyn( ty, db, env, diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 4351a34e82282..4e45b5a250eb5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -260,7 +260,7 @@ fn resolve_impl_trait_item( // attributes here. Use path resolution directly instead. // // FIXME: resolve type aliases (which are not yielded by iterate_path_candidates) - method_resolution::iterate_path_candidates( + let _ = method_resolution::iterate_path_candidates( &canonical, db, environment, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index a8075509474ab..29f4584665087 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2911,7 +2911,7 @@ impl Trait { db: &dyn HirDatabase, ) -> Option> { let mut violations = vec![]; - hir_ty::dyn_compatibility::dyn_compatibility_with_callback(db, self.id, &mut |violation| { + let _ = hir_ty::dyn_compatibility::dyn_compatibility_with_callback(db, self.id, &mut |violation| { violations.push(violation); ControlFlow::Continue(()) }); @@ -5497,7 +5497,7 @@ impl Type { .generic_def() .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); - method_resolution::iterate_method_candidates_dyn( + let _ = method_resolution::iterate_method_candidates_dyn( &canonical, db, environment, @@ -5584,7 +5584,7 @@ impl Type { .generic_def() .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); - method_resolution::iterate_path_candidates( + let _ = method_resolution::iterate_path_candidates( &canonical, db, environment, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 330587e0dbfbe..6f4b886a28d75 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -750,7 +750,7 @@ impl FunctionBody { ast::Stmt::Item(_) => (), ast::Stmt::LetStmt(stmt) => { if let Some(pat) = stmt.pat() { - walk_pat(&pat, &mut |pat| { + let _ = walk_pat(&pat, &mut |pat| { cb(pat); std::ops::ControlFlow::<(), ()>::Continue(()) }); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs index 0b2e8aa6836f2..56a66070ef7f3 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -121,7 +121,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { match ast::Stmt::cast(node.clone()) { Some(ast::Stmt::LetStmt(l)) => { if let Some(pat) = l.pat() { - walk_pat(&pat, &mut |pat| { + let _ = walk_pat(&pat, &mut |pat| { cb(pat); ControlFlow::<(), ()>::Continue(()) }); @@ -159,7 +159,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { } } else if let Some(pat) = ast::Pat::cast(node) { preorder.skip_subtree(); - walk_pat(&pat, &mut |pat| { + let _ = walk_pat(&pat, &mut |pat| { cb(pat); ControlFlow::<(), ()>::Continue(()) }); From b2fda93aacd2ad795199140068b9c8a055840b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 16 Mar 2025 20:42:37 +0100 Subject: [PATCH 085/163] Add a note to rustc-dev-guide --- src/doc/rustc-dev-guide/src/tests/ci.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 0c0f750a45d72..2af09a60513b0 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -180,6 +180,8 @@ their results can be seen [here](https://github.com/rust-lang-ci/rust/actions), although usually you will be notified of the result by a comment made by bors on the corresponding PR. +Note that if you start the default try job using `@bors try`, it will skip building several `dist` components and running post-optimization tests, to make the build duration shorter. If you want to execute the full build as it would happen before a merge, add an explicit `try-job` pattern with the name of the default try job (currently `dist-x86_64-linux`). + Multiple try builds can execute concurrently across different PRs.
From f5ecb74bf9aa01201c5c7aa5dca16b3686a400e9 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 16 Mar 2025 20:23:22 +0000 Subject: [PATCH 086/163] rustdoc-json: Add tests for `#[repr(...)]` Co-authored-by: Predrag Gruevski --- tests/rustdoc-json/attrs/repr_align.rs | 8 ++ tests/rustdoc-json/attrs/repr_c.rs | 18 +++++ tests/rustdoc-json/attrs/repr_combination.rs | 78 ++++++++++++++++++++ tests/rustdoc-json/attrs/repr_int_enum.rs | 19 +++++ tests/rustdoc-json/attrs/repr_packed.rs | 18 +++++ tests/rustdoc-json/attrs/repr_transparent.rs | 22 ++++++ 6 files changed, 163 insertions(+) create mode 100644 tests/rustdoc-json/attrs/repr_align.rs create mode 100644 tests/rustdoc-json/attrs/repr_c.rs create mode 100644 tests/rustdoc-json/attrs/repr_combination.rs create mode 100644 tests/rustdoc-json/attrs/repr_int_enum.rs create mode 100644 tests/rustdoc-json/attrs/repr_packed.rs create mode 100644 tests/rustdoc-json/attrs/repr_transparent.rs diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs new file mode 100644 index 0000000000000..bebbe1fea349d --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -0,0 +1,8 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]' +#[repr(align(4))] +pub struct Aligned { + a: i8, + b: i64, +} diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs new file mode 100644 index 0000000000000..609d33d94de76 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -0,0 +1,18 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]' +#[repr(C)] +pub struct ReprCStruct(pub i64); + +//@ is "$.index[*][?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]' +#[repr(C)] +pub enum ReprCEnum { + First, +} + +//@ is "$.index[*][?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]' +#[repr(C)] +pub union ReprCUnion { + pub left: i64, + pub right: u64, +} diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs new file mode 100644 index 0000000000000..662bfef67cb87 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -0,0 +1,78 @@ +#![no_std] + +// Combinations of `#[repr(..)]` attributes. + +//@ is "$.index[*][?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]' +#[repr(C, i8)] +pub enum ReprCI8 { + First, +} + +//@ is "$.index[*][?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]' +#[repr(C)] +#[repr(i16)] +pub enum SeparateReprCI16 { + First, +} + +//@ is "$.index[*][?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]' +#[repr(usize, C)] +pub enum ReversedReprCUsize { + First, +} + +//@ is "$.index[*][?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]' +#[repr(C, packed)] +pub struct ReprCPacked { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]' +#[repr(C)] +#[repr(packed(2))] +pub struct SeparateReprCPacked { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]' +#[repr(packed(2), C)] +pub struct ReversedReprCPacked { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]' +#[repr(C, align(16))] +pub struct ReprCAlign { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]' +#[repr(C)] +#[repr(align(2))] +pub struct SeparateReprCAlign { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]' +#[repr(align(2), C)] +pub struct ReversedReprCAlign { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]' +#[repr(C, align(16), isize)] +pub enum AlignedExplicitRepr { + First, +} + +//@ is "$.index[*][?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]' +#[repr(isize, C, align(16))] +pub enum ReorderedAlignedExplicitRepr { + First, +} diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs new file mode 100644 index 0000000000000..2ad57de279887 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -0,0 +1,19 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]' +#[repr(i8)] +pub enum I8 { + First, +} + +//@ is "$.index[*][?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +#[repr(i32)] +pub enum I32 { + First, +} + +//@ is "$.index[*][?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]' +#[repr(usize)] +pub enum Usize { + First, +} diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs new file mode 100644 index 0000000000000..33acc23b7c894 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -0,0 +1,18 @@ +#![no_std] + +// Note the normalization: +// `#[repr(packed)]` in has the implict "1" in rustdoc JSON. + +//@ is "$.index[*][?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]' +#[repr(packed)] +pub struct Packed { + a: i8, + b: i64, +} + +//@ is "$.index[*][?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]' +#[repr(packed(4))] +pub struct PackedAligned { + a: i8, + b: i64, +} diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs new file mode 100644 index 0000000000000..ef6e69f8703b1 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_transparent.rs @@ -0,0 +1,22 @@ +#![no_std] + +// Rustdoc JSON currently includes `#[repr(transparent)]` +// even if the transparency is not part of the public API +// +// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent + +//@ is "$.index[*][?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +#[repr(transparent)] +pub struct Transparent(pub i64); + +//@ is "$.index[*][?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +#[repr(transparent)] +pub struct TransparentNonPub(i64); + +//@ is "$.index[*][?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +#[repr(transparent)] +pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ()); + +//@ is "$.index[*][?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +#[repr(transparent)] +pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ()); From f20a6c70fb7a1b9bf1b855e6d1e711c1afd6bb48 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 16 Mar 2025 21:32:41 +0100 Subject: [PATCH 087/163] make `_Unwind_Action` a type alias, not enum It's bitflags in practice, so an enum is unsound, as an enum must only have the described values. The x86_64 psABI declares it as a `typedef int _Unwind_Action`, which seems reasonable. I made a newtype first but that was more annoying than just a typedef. We don't really use this value for much other than a short check. --- library/std/src/sys/personality/gcc.rs | 4 ++-- library/unwind/src/libunwind.rs | 17 +++++++---------- library/unwind/src/unwinding.rs | 17 +++++++---------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index cd2c7899f4bf1..9a5b3b2fd197a 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -220,7 +220,7 @@ cfg_if::cfg_if! { Ok(action) => action, Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, }; - if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { + if actions & uw::_UA_SEARCH_PHASE != 0 { match eh_action { EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND, EHAction::Catch(_) | EHAction::Filter(_) => uw::_URC_HANDLER_FOUND, @@ -230,7 +230,7 @@ cfg_if::cfg_if! { match eh_action { EHAction::None => uw::_URC_CONTINUE_UNWIND, // Forced unwinding hits a terminate action. - EHAction::Filter(_) if actions as i32 & uw::_UA_FORCE_UNWIND as i32 != 0 => uw::_URC_CONTINUE_UNWIND, + EHAction::Filter(_) if actions & uw::_UA_FORCE_UNWIND != 0 => uw::_URC_CONTINUE_UNWIND, EHAction::Cleanup(lpad) | EHAction::Catch(lpad) | EHAction::Filter(lpad) => { uw::_Unwind_SetGR( context, diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1a640bbde71d7..1283c8e3a01f7 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -125,16 +125,13 @@ if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "a // // 32-bit ARM on iOS/tvOS/watchOS use either DWARF/Compact unwinding or // "setjmp-longjmp" / SjLj unwinding. - #[repr(C)] - #[derive(Copy, Clone, PartialEq)] - pub enum _Unwind_Action { - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16, - } - pub use _Unwind_Action::*; + pub type _Unwind_Action = c_int; + + pub const _UA_SEARCH_PHASE: c_int = 1; + pub const _UA_CLEANUP_PHASE: c_int = 2; + pub const _UA_HANDLER_FRAME: c_int = 4; + pub const _UA_FORCE_UNWIND: c_int = 8; + pub const _UA_END_OF_STACK: c_int = 16; #[cfg_attr( all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")), diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs index 1b94005ab6cd0..ba4258033037f 100644 --- a/library/unwind/src/unwinding.rs +++ b/library/unwind/src/unwinding.rs @@ -2,16 +2,13 @@ use core::ffi::{c_int, c_void}; -#[repr(C)] -#[derive(Copy, Clone, PartialEq)] -pub enum _Unwind_Action { - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16, -} -pub use _Unwind_Action::*; +pub type _Unwind_Action = c_int; + +pub const _UA_SEARCH_PHASE: c_int = 1; +pub const _UA_CLEANUP_PHASE: c_int = 2; +pub const _UA_HANDLER_FRAME: c_int = 4; +pub const _UA_FORCE_UNWIND: c_int = 8; +pub const _UA_END_OF_STACK: c_int = 16; #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq)] From 417bfe2125cfb371c3ce4b80437152e429b0e45c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 16 Mar 2025 21:46:39 +0100 Subject: [PATCH 088/163] Exclude `literal-escaper` from `library` workspace --- library/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Cargo.toml b/library/Cargo.toml index 1205f7c9ed6b5..1e2d996278e77 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -7,6 +7,7 @@ members = [ ] exclude = [ + "literal-escaper", # stdarch has its own Cargo workspace "stdarch", "windows_targets" From 2ff28159d3e9915772e65955488f447cb2b98ffa Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 16 Mar 2025 21:09:46 +0000 Subject: [PATCH 089/163] rustdoc-json: Add tests for `#[deprecated(...)]` --- tests/rustdoc-json/attrs/deprecated.rs | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/rustdoc-json/attrs/deprecated.rs diff --git a/tests/rustdoc-json/attrs/deprecated.rs b/tests/rustdoc-json/attrs/deprecated.rs new file mode 100644 index 0000000000000..c54dca1dddfaf --- /dev/null +++ b/tests/rustdoc-json/attrs/deprecated.rs @@ -0,0 +1,38 @@ +//@ is "$.index[*][?(@.name=='not')].attrs" '[]' +//@ is "$.index[*][?(@.name=='not')].deprecation" null +pub fn not() {} + +//@ is "$.index[*][?(@.name=='raw')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]' +//@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}' +#[deprecated] +pub fn raw() {} + +//@ is "$.index[*][?(@.name=='equals_string')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"here is a reason\"}}]\n"]' +//@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}' +#[deprecated = "here is a reason"] +pub fn equals_string() {} + +//@ is "$.index[*][?(@.name=='since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"yoinks ago\")}}]\n"]' +//@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}' +#[deprecated(since = "yoinks ago")] +pub fn since() {} + +//@ is "$.index[*][?(@.name=='note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"7\"}}]\n"]' +//@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}' +#[deprecated(note = "7")] +pub fn note() {} + +//@ is "$.index[*][?(@.name=='since_and_note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"tomorrow\"), note: \"sorry\"}}]\n"]' +//@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}' +#[deprecated(since = "tomorrow", note = "sorry")] +pub fn since_and_note() {} + +//@ is "$.index[*][?(@.name=='note_and_since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"a year from tomorrow\"), note: \"your welcome\"}}]\n"]' +//@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}' +#[deprecated(note = "your welcome", since = "a year from tomorrow")] +pub fn note_and_since() {} + +//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]' +//@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}' +#[deprecated()] +pub fn neither_but_parens() {} From a8a913dcd23c75744486773e491a18af0555cdd8 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 16 Mar 2025 21:15:49 +0000 Subject: [PATCH 090/163] rustdoc: Rename `Item::attributes` param to `is_json` This makes it clearer what it's actually used for, and makes it easier to think about modifying `Item::attributes`. --- src/librustdoc/clean/types.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3f9023659dbac..8200fa3a35d26 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -756,12 +756,7 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes( - &self, - tcx: TyCtxt<'_>, - cache: &Cache, - keep_as_is: bool, - ) -> Vec { + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; @@ -772,7 +767,7 @@ impl Item { .other_attrs .iter() .filter_map(|attr| { - if keep_as_is { + if is_json { Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { Some( @@ -786,7 +781,8 @@ impl Item { } }) .collect(); - if !keep_as_is + + if !is_json && let Some(def_id) = self.def_id() && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() { From 6698c26b3ab9ef90a31af1afc367bab3a359563c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 12 Mar 2025 13:45:48 +1100 Subject: [PATCH 091/163] Fix `is_relevant_impl`. It determines if a function should have any `inline` attributes checked. For `ItemKind::Fn` it returns true or false depending on the details of the function; for anything other item kind it returns *true*. This latter case should instead be *false*. (In the nearby and similar functions `is_relevant_impl` and `is_relevant_trait` the non-function cases return false.) The effect of this is that non-functions are no longer checked. But rustc already disallows `inline` on any non-function items. So if anything its a tiny performance win, because that was useless anyway. --- src/tools/clippy/clippy_lints/src/attrs/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 0e650e4939252..a5ce2137bffeb 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -24,7 +24,7 @@ pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if let ItemKind::Fn { body: eid, .. } = item.kind { is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value) } else { - true + false } } From 677489fb3ee6808303046c5dd1956195972c84ca Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 16 Mar 2025 21:27:54 +0000 Subject: [PATCH 092/163] rustdoc-json: Don't also include `#[deprecated]` in `Item::attrs` --- src/librustdoc/clean/types.rs | 11 +++++++++-- tests/rustdoc-json/attrs/deprecated.rs | 16 ++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8200fa3a35d26..e6f88128a7006 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,7 +5,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince}; +use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -768,7 +768,13 @@ impl Item { .iter() .filter_map(|attr| { if is_json { - Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) + if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) { + // rustdoc-json stores this in `Item::deprecation`, so we + // don't want it it `Item::attrs`. + None + } else { + Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) + } } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { Some( rustc_hir_pretty::attribute_to_string(&tcx, attr) @@ -782,6 +788,7 @@ impl Item { }) .collect(); + // Add #[repr(...)] if !is_json && let Some(def_id) = self.def_id() && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() diff --git a/tests/rustdoc-json/attrs/deprecated.rs b/tests/rustdoc-json/attrs/deprecated.rs index c54dca1dddfaf..5cde7af841f72 100644 --- a/tests/rustdoc-json/attrs/deprecated.rs +++ b/tests/rustdoc-json/attrs/deprecated.rs @@ -1,38 +1,38 @@ -//@ is "$.index[*][?(@.name=='not')].attrs" '[]' +//@ is "$.index[*][?(@.name=='not')].attrs" [] //@ is "$.index[*][?(@.name=='not')].deprecation" null pub fn not() {} -//@ is "$.index[*][?(@.name=='raw')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]' +//@ is "$.index[*][?(@.name=='raw')].attrs" [] //@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}' #[deprecated] pub fn raw() {} -//@ is "$.index[*][?(@.name=='equals_string')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"here is a reason\"}}]\n"]' +//@ is "$.index[*][?(@.name=='equals_string')].attrs" [] //@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}' #[deprecated = "here is a reason"] pub fn equals_string() {} -//@ is "$.index[*][?(@.name=='since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"yoinks ago\")}}]\n"]' +//@ is "$.index[*][?(@.name=='since')].attrs" [] //@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}' #[deprecated(since = "yoinks ago")] pub fn since() {} -//@ is "$.index[*][?(@.name=='note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:\n\"7\"}}]\n"]' +//@ is "$.index[*][?(@.name=='note')].attrs" [] //@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}' #[deprecated(note = "7")] pub fn note() {} -//@ is "$.index[*][?(@.name=='since_and_note')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"tomorrow\"), note: \"sorry\"}}]\n"]' +//@ is "$.index[*][?(@.name=='since_and_note')].attrs" [] //@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}' #[deprecated(since = "tomorrow", note = "sorry")] pub fn since_and_note() {} -//@ is "$.index[*][?(@.name=='note_and_since')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since:\nNonStandard(\"a year from tomorrow\"), note: \"your welcome\"}}]\n"]' +//@ is "$.index[*][?(@.name=='note_and_since')].attrs" [] //@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}' #[deprecated(note = "your welcome", since = "a year from tomorrow")] pub fn note_and_since() {} -//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" '["#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]\n"]' +//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" [] //@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}' #[deprecated()] pub fn neither_but_parens() {} From b14810669a805003cf6392447c08eed79441936f Mon Sep 17 00:00:00 2001 From: Charalampos Mitrodimas Date: Sun, 16 Mar 2025 11:28:21 +0100 Subject: [PATCH 093/163] Fix ICE: attempted to remap an already remapped filename This commit fixes an internal compiler error (ICE) that occurs when rustdoc attempts to process macros with a remapped filename. The issue arose during macro expansion when the `--remap-path-prefix` option was used. Instead of passing remapped filenames through, which would trigger the "attempted to remap an already remapped filename" panic, we now extract the original local path from remapped filenames before processing them. A test case has been added to verify this behavior. Fixes #138520 Signed-off-by: Charalampos Mitrodimas --- src/librustdoc/clean/render_macro_matchers.rs | 4 ++-- tests/rustdoc-ui/remap-path-prefix-macro.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc-ui/remap-path-prefix-macro.rs diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 88db853d7c38f..31f9c284d7dd5 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -4,8 +4,8 @@ use rustc_ast_pretty::pprust::PrintState; use rustc_ast_pretty::pprust::state::State as Printer; use rustc_middle::ty::TyCtxt; use rustc_session::parse::ParseSess; -use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{FileName, Span}; /// Render a macro matcher in a format suitable for displaying to the user /// as part of an item declaration. @@ -63,7 +63,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option parser, diff --git a/tests/rustdoc-ui/remap-path-prefix-macro.rs b/tests/rustdoc-ui/remap-path-prefix-macro.rs new file mode 100644 index 0000000000000..1be22694b8cdc --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-macro.rs @@ -0,0 +1,9 @@ +// Regression test for "attempted to remap an already remapped filename" ICE in rustdoc +// when using --remap-path-prefix with macro rendering. +// + +//@ compile-flags:-Z unstable-options --remap-path-prefix={{src-base}}=remapped_path +//@ rustc-env:RUST_BACKTRACE=0 +//@ build-pass + +macro_rules! f(() => {}); From 4aee99575035d1dbddd534df12399f5ba911627e Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 16 Mar 2025 21:06:18 -0400 Subject: [PATCH 094/163] expand ${workspaceFolder} in sample vim config --- .../rustc-dev-guide/src/building/suggested.md | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 2498838144e70..772b0a778f890 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -123,6 +123,30 @@ Another way is without a plugin, and creating your own logic in your configuration. The following code will work for any checkout of rust-lang/rust (newer than Febuary 2025): ```lua +local function expand_config_variables(option) + local var_placeholders = { + ['${workspaceFolder}'] = function(_) + return vim.lsp.buf.list_workspace_folders()[1] + end, + } + + if type(option) == "table" then + local mt = getmetatable(option) + local result = {} + for k, v in pairs(option) do + result[expand_config_variables(k)] = expand_config_variables(v) + end + return setmetatable(result, mt) + end + if type(option) ~= "string" then + return option + end + local ret = option + for key, fn in pairs(var_placeholders) do + ret = ret:gsub(key, fn) + end + return ret +end lspconfig.rust_analyzer.setup { root_dir = function() local default = lspconfig.rust_analyzer.config_def.default_config.root_dir() @@ -142,7 +166,7 @@ lspconfig.rust_analyzer.setup { -- load rust-lang/rust settings local file = io.open(config) local json = vim.json.decode(file:read("*a")) - client.config.settings["rust-analyzer"] = json.lsp["rust-analyzer"].initialization_options + client.config.settings["rust-analyzer"] = expand_config_variables(json.lsp["rust-analyzer"].initialization_options) client.notify("workspace/didChangeConfiguration", { settings = client.config.settings }) end return true From 04c9956c9a470ca6b809bb76620846641ac8c892 Mon Sep 17 00:00:00 2001 From: Alex Touchet <26315797+atouchet@users.noreply.github.com> Date: Sun, 16 Mar 2025 19:03:40 -0700 Subject: [PATCH 095/163] Update Rust Foundation links in Readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d84d96a0e9173..611260470f12b 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,11 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and trademarks and logos (the "Rust Trademarks"). If you want to use these names or brands, please read the -[media guide][media-guide]. +[Rust language trademark policy][trademark-policy]. Third-party logos may be subject to third-party copyrights and trademarks. See [Licenses][policies-licenses] for details. -[rust-foundation]: https://foundation.rust-lang.org/ -[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/ +[rust-foundation]: https://rustfoundation.org/ +[trademark-policy]: https://rustfoundation.org/policy/rust-trademark-policy/ [policies-licenses]: https://www.rust-lang.org/policies/licenses From 87457f6e00bf53119db370ba5ee9b95def9a617b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Mar 2025 15:20:22 +1100 Subject: [PATCH 096/163] Inline and remove `LoweringContext::new_named_lifetime_with_res`. It has a single call site. --- compiler/rustc_ast_lowering/src/lib.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index df671cf4b8604..0de2dd2ba20ef 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1774,12 +1774,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn new_named_lifetime_with_res( + fn new_named_lifetime( &mut self, id: NodeId, + new_id: NodeId, ident: Ident, - res: LifetimeRes, ) -> &'hir hir::Lifetime { + let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), LifetimeRes::Fresh { param, .. } => { @@ -1797,23 +1798,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!(?res); self.arena.alloc(hir::Lifetime { - hir_id: self.lower_node_id(id), + hir_id: self.lower_node_id(new_id), ident: self.lower_ident(ident), res, }) } - #[instrument(level = "debug", skip(self))] - fn new_named_lifetime( - &mut self, - id: NodeId, - new_id: NodeId, - ident: Ident, - ) -> &'hir hir::Lifetime { - let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); - self.new_named_lifetime_with_res(new_id, ident, res) - } - fn lower_generic_params_mut( &mut self, params: &[GenericParam], From fe4d14495f0d913033baf63c0af943583657450d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Mar 2025 15:23:05 +1100 Subject: [PATCH 097/163] Avoid double lowering of lifetime identifiers. `LoweringContext::new_named_lifetime` lowers the `ident` passed in. Both of its call sites *also* lower `ident` *before* passing it in. I.e. both call sites cause the ident to be lowered twice. This commit removes the lowering at the two call sites, so the ident is only lowered once. --- compiler/rustc_ast_lowering/src/item.rs | 1 - compiler/rustc_ast_lowering/src/lib.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9adc8bdd3616d..c419ac988c966 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1757,7 +1757,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } GenericParamKind::Lifetime => { - let ident = self.lower_ident(ident); let lt_id = self.next_node_id(); let lifetime = self.new_named_lifetime(id, lt_id, ident); hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0de2dd2ba20ef..8997e4f119406 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1769,8 +1769,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - let ident = self.lower_ident(l.ident); - self.new_named_lifetime(l.id, l.id, ident) + self.new_named_lifetime(l.id, l.id, l.ident) } #[instrument(level = "debug", skip(self))] From 6496d6943fbf152d54149797558dccb87434de31 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Mar 2025 15:44:43 +1100 Subject: [PATCH 098/163] Make the `match` in `new_named_lifetime` exhaustive. --- compiler/rustc_ast_lowering/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8997e4f119406..e24b45c5b1947 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1789,10 +1789,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Infer => hir::LifetimeName::Infer, LifetimeRes::Static { .. } => hir::LifetimeName::Static, LifetimeRes::Error => hir::LifetimeName::Error, - res => panic!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, ident, ident.span - ), + LifetimeRes::ElidedAnchor { .. } => { + panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span); + } }; debug!(?res); From adf2bb75ea4643d061a1c0933c7f3c8ea8f86808 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Mar 2025 15:47:33 +1100 Subject: [PATCH 099/163] Avoid double lowering of generic identifiers. `lower_generic_bound_predicate` calls `lower_ident`, and then passes the lowered ident into `new_named_lifetime`, which lowers it again. This commit avoids the first lowering. This requires adding a `lower_ident` call on a path that doesn't involve `new_named_lifetime`. --- compiler/rustc_ast_lowering/src/item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c419ac988c966..3b2e8581c004f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1720,7 +1720,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let bounds = self.lower_param_bounds(bounds, itctx); - let ident = self.lower_ident(ident); let param_span = ident.span; // Reconstruct the span of the entire predicate from the individual generic bounds. @@ -1739,6 +1738,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let def_id = self.local_def_id(id).to_def_id(); let hir_id = self.next_id(); let res = Res::Def(DefKind::TyParam, def_id); + let ident = self.lower_ident(ident); let ty_path = self.arena.alloc(hir::Path { span: param_span, res, From 10bc5acf0d6736bc0a99d55beae739878f94de16 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 16 Mar 2025 22:27:09 -0400 Subject: [PATCH 100/163] Document `#![register_tool]` --- .../src/language-features/register-tool.md | 55 +++++++++++++++++++ tests/ui/tool-attributes/crate-attr.rs | 5 ++ .../ui/tool-attributes/multiple-registered.rs | 7 +++ tests/ui/tool-attributes/nested-disallowed.rs | 4 ++ .../tool-attributes/nested-disallowed.stderr | 8 +++ 5 files changed, 79 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/register-tool.md create mode 100644 tests/ui/tool-attributes/crate-attr.rs create mode 100644 tests/ui/tool-attributes/multiple-registered.rs create mode 100644 tests/ui/tool-attributes/nested-disallowed.rs create mode 100644 tests/ui/tool-attributes/nested-disallowed.stderr diff --git a/src/doc/unstable-book/src/language-features/register-tool.md b/src/doc/unstable-book/src/language-features/register-tool.md new file mode 100644 index 0000000000000..58b923aab5775 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/register-tool.md @@ -0,0 +1,55 @@ +# `register_tool` + +The tracking issue for this feature is: [#66079] + +[#66079]: https://github.com/rust-lang/rust/issues/66079 + +------------------------ + +The `register_tool` language feature informs the compiler that attributes in your code are meant to be used with tools other than the compiler itself. This can be useful if your code has semantic meaning without the external tool, but enables additional features when the tool is present. + +`register_tool` also allows configuring lint levels for external tools. + +Tool attributes are only meant for ignorable attributes. If your code *changes* meaning when the attribute is present, it should not use a tool attribute (because it cannot be compiled with anything other than the external tool, and in a sense is a fork of the language). + +------------------------ + +`#![register_tool(tool)]` is an attribute, and is only valid at the crate root. +Attributes using the registered tool are checked for valid syntax, and lint attributes are checked to be in a valid format. However, the compiler cannot validate the semantics of the attribute, nor can it tell whether the configured lint is present in the external tool. + +Semantically, `clippy::*`, `rustdoc::*`, and `rustfmt::*` lints and attributes all behave as if `#![register_tool(clippy, rustdoc, rustfmt)]` were injected into the crate root, except that the `rustdoc` namespace can only be used for lints, not for attributes. +When compiling with `-Z unstable-features`, `rustc::*` lints can also be used. Like `rustdoc`, the `rustc` namespace can only be used with lints, not attributes. + +The compiler will emit an error if it encounters a lint/attribute whose namespace isn't a registered tool. + +Tool namespaces cannot be nested; `register_tool(main_tool::subtool)` is an error. + +## Examples + +Tool attributes: + +```rust +#![feature(register_tool)] +#![register_tool(c2rust)] + +// Mark which C header file this module was generated from. +#[c2rust::header_src = "operations.h"] +pub mod operations_h { + use std::ffi::c_int; + + // Mark which source line this struct was generated from. + #[c2rust::src_loc = "11:0"] + pub struct Point { + pub x: c_int, + pub y: c_int, + } +} +``` + +Tool lints: + +``` +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::duplicate_bevy_dependencies)] +``` diff --git a/tests/ui/tool-attributes/crate-attr.rs b/tests/ui/tool-attributes/crate-attr.rs new file mode 100644 index 0000000000000..c6d7974945f4a --- /dev/null +++ b/tests/ui/tool-attributes/crate-attr.rs @@ -0,0 +1,5 @@ +//@ check-pass +//@ compile-flags: -Z crate-attr=feature(register_tool) -Z crate-attr=register_tool(foo) + +#[allow(foo::bar)] +fn main() {} diff --git a/tests/ui/tool-attributes/multiple-registered.rs b/tests/ui/tool-attributes/multiple-registered.rs new file mode 100644 index 0000000000000..4d54c2dcb0820 --- /dev/null +++ b/tests/ui/tool-attributes/multiple-registered.rs @@ -0,0 +1,7 @@ +//@ check-pass + +#![feature(register_tool)] +#![register_tool(foo, bar, baz)] + +#[allow(foo::a, bar::b, baz::c)] +fn main() {} diff --git a/tests/ui/tool-attributes/nested-disallowed.rs b/tests/ui/tool-attributes/nested-disallowed.rs new file mode 100644 index 0000000000000..8e78042776106 --- /dev/null +++ b/tests/ui/tool-attributes/nested-disallowed.rs @@ -0,0 +1,4 @@ +#![feature(register_tool)] +#![register_tool(foo::bar)] //~ ERROR only accepts identifiers + +fn main() {} diff --git a/tests/ui/tool-attributes/nested-disallowed.stderr b/tests/ui/tool-attributes/nested-disallowed.stderr new file mode 100644 index 0000000000000..1af73fc2f1995 --- /dev/null +++ b/tests/ui/tool-attributes/nested-disallowed.stderr @@ -0,0 +1,8 @@ +error: `register_tool` only accepts identifiers + --> $DIR/nested-disallowed.rs:2:18 + | +LL | #![register_tool(foo::bar)] + | ^^^^^^^^ not an identifier + +error: aborting due to 1 previous error + From f478853f425fc0207add653b48c49c937acaa94e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 17 Mar 2025 00:25:15 -0500 Subject: [PATCH 101/163] If a label is placed on the block of a loop instead of the header, suggest moving it to the header. --- .../rustc_parse/src/parser/diagnostics.rs | 29 +++- compiler/rustc_parse/src/parser/expr.rs | 36 +++-- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 22 ++- tests/ui/loops/label-on-block-suggest-move.rs | 90 +++++++++++ .../loops/label-on-block-suggest-move.stderr | 140 ++++++++++++++++++ 7 files changed, 296 insertions(+), 25 deletions(-) create mode 100644 tests/ui/loops/label-on-block-suggest-move.rs create mode 100644 tests/ui/loops/label-on-block-suggest-move.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 716ababb00802..c1cca1186af49 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2874,7 +2874,12 @@ impl<'a> Parser<'a> { first_pat } - pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool { + /// If `loop_header` is `Some` and an unexpected block label is encountered, + /// it is suggested to be moved just before `loop_header`, else it is suggested to be removed. + pub(crate) fn maybe_recover_unexpected_block_label( + &mut self, + loop_header: Option, + ) -> bool { // Check for `'a : {` if !(self.check_lifetime() && self.look_ahead(1, |t| *t == token::Colon) @@ -2885,16 +2890,28 @@ impl<'a> Parser<'a> { let label = self.eat_label().expect("just checked if a label exists"); self.bump(); // eat `:` let span = label.ident.span.to(self.prev_token.span); - self.dcx() + let mut diag = self + .dcx() .struct_span_err(span, "block label not supported here") - .with_span_label(span, "not supported here") - .with_tool_only_span_suggestion( + .with_span_label(span, "not supported here"); + if let Some(loop_header) = loop_header { + diag.multipart_suggestion( + "if you meant to label the loop, move this label before the loop", + vec![ + (label.ident.span.until(self.token.span), String::from("")), + (loop_header.shrink_to_lo(), format!("{}: ", label.ident)), + ], + Applicability::MachineApplicable, + ); + } else { + diag.tool_only_span_suggestion( label.ident.span.until(self.token.span), "remove this block label", "", Applicability::MachineApplicable, - ) - .emit(); + ); + } + diag.emit(); true } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0774324eae742..cd931888fbaa1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2286,7 +2286,7 @@ impl<'a> Parser<'a> { }); } - let (attrs, blk) = self.parse_block_common(lo, blk_mode, true)?; + let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?; Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) } @@ -2851,7 +2851,11 @@ impl<'a> Parser<'a> { )); } - let (attrs, loop_block) = self.parse_inner_attrs_and_block()?; + let (attrs, loop_block) = self.parse_inner_attrs_and_block( + // Only suggest moving erroneous block label to the loop header + // if there is not already a label there + opt_label.is_none().then_some(lo), + )?; let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind }; @@ -2894,11 +2898,17 @@ impl<'a> Parser<'a> { err.span_label(lo, "while parsing the condition of this `while` expression"); err })?; - let (attrs, body) = self.parse_inner_attrs_and_block().map_err(|mut err| { - err.span_label(lo, "while parsing the body of this `while` expression"); - err.span_label(cond.span, "this `while` condition successfully parsed"); - err - })?; + let (attrs, body) = self + .parse_inner_attrs_and_block( + // Only suggest moving erroneous block label to the loop header + // if there is not already a label there + opt_label.is_none().then_some(lo), + ) + .map_err(|mut err| { + err.span_label(lo, "while parsing the body of this `while` expression"); + err.span_label(cond.span, "this `while` condition successfully parsed"); + err + })?; self.recover_loop_else("while", lo)?; @@ -2912,7 +2922,11 @@ impl<'a> Parser<'a> { /// Parses `loop { ... }` (`loop` token already eaten). fn parse_expr_loop(&mut self, opt_label: Option