From 38a5fee3a0e31f9f9c072d8d9af1321e0bf6752a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 19 May 2023 16:03:35 -0400 Subject: [PATCH 1/9] Print a backtrace in const eval if interrupted --- Cargo.lock | 1 + .../src/const_eval/eval_queries.rs | 8 +++++++- compiler/rustc_data_structures/src/lib.rs | 7 +++++++ compiler/rustc_driver_impl/Cargo.toml | 1 + compiler/rustc_driver_impl/src/lib.rs | 15 +++++++++++++++ compiler/rustc_middle/src/mir/interpret/error.rs | 3 +++ src/tools/miri/src/concurrency/thread.rs | 14 ++++++++------ src/tools/tidy/src/deps.rs | 3 +++ 8 files changed, 45 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7f3935753442..c1cff4558c07e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3413,6 +3413,7 @@ dependencies = [ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ + "ctrlc", "libc", "rustc_ast", "rustc_ast_lowering", diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 046d2052968a3..0e88fb77aa894 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,8 +1,10 @@ use crate::const_eval::CheckAlignment; use std::borrow::Cow; +use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; +use rustc_data_structures::CTRL_C_RECEIVED; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -66,7 +68,11 @@ fn eval_body_using_ecx<'mir, 'tcx>( )?; // The main interpreter loop. - while ecx.step()? {} + while ecx.step()? { + if CTRL_C_RECEIVED.load(Relaxed) { + throw_exhaust!(Interrupted); + } + } // Intern the result let intern_kind = if cid.promoted.is_some() { diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 859e384d8b529..30cda015a0571 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -46,6 +46,8 @@ extern crate cfg_if; #[macro_use] extern crate rustc_macros; +use std::sync::atomic::AtomicBool; + pub use rustc_index::static_assert_size; #[inline(never)] @@ -129,3 +131,8 @@ impl Drop for OnDrop { // See comments in src/librustc_middle/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} + +/// `rustc_driver::main` installs a handler that will set this to `true` if +/// the compiler has been sent a request to shut down, such as by a Ctrl-C. +/// This static is placed here so that it is available to all parts of the compiler. +pub static CTRL_C_RECEIVED: AtomicBool = AtomicBool::new(false); diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 67352c55c9019..405e5215b43d3 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [lib] [dependencies] +ctrlc = "3.3.0" tracing = { version = "0.1.35" } serde_json = "1.0.59" rustc_log = { path = "../rustc_log" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 40aa69e5a4105..a7775ed9110f1 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -23,6 +23,7 @@ use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; use rustc_data_structures::sync::SeqCst; +use rustc_data_structures::CTRL_C_RECEIVED; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl, @@ -55,6 +56,7 @@ use std::panic::{self, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; +use std::sync::atomic::Ordering::Relaxed; use std::sync::OnceLock; use std::time::Instant; @@ -1403,6 +1405,19 @@ pub fn main() -> ! { signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); + + ctrlc::set_handler(move || { + // Indicate that we have been signaled to stop. If we were already signaled, exit + // immediately. In our interpreter loop we try to consult this value often, but if for + // whatever reason we don't get to that check or the cleanup we do upon finding that + // this bool has become true takes a long time, the exit here will promptly exit the + // process on the second Ctrl-C. + if CTRL_C_RECEIVED.swap(true, Relaxed) { + std::process::exit(1); + } + }) + .expect("Unable to install ctrlc handler"); + let exit_code = catch_with_exit_code(|| { let args = env::args_os() .enumerate() diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 055d8e9a352bc..e87f30deb4e0b 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -473,6 +473,8 @@ pub enum ResourceExhaustionInfo { MemoryExhausted, /// The address space (of the target) is full. AddressSpaceFull, + /// The compiler got an interrupt signal (a user ran out of patience). + Interrupted, } impl fmt::Display for ResourceExhaustionInfo { @@ -491,6 +493,7 @@ impl fmt::Display for ResourceExhaustionInfo { AddressSpaceFull => { write!(f, "there are no more free addresses in the address space") } + Interrupted => write!(f, "compilation was interrupted"), } } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d85cac7bcbb58..0d97f2de7c24f 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -3,13 +3,14 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::num::TryFromIntError; -use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; +use std::sync::atomic::Ordering::Relaxed; use std::task::Poll; use std::time::{Duration, SystemTime}; use log::trace; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::CTRL_C_RECEIVED; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::Mutability; @@ -1013,21 +1014,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program /// termination). fn run_threads(&mut self) -> InterpResult<'tcx, !> { - static SIGNALED: AtomicBool = AtomicBool::new(false); + // In normal rustc, rustc_driver::main installs this handler. But we don't use that + // function, see src/bin/miri.rs. ctrlc::set_handler(move || { - // Indicate that we have ben signaled to stop. If we were already signaled, exit + // Indicate that we have been signaled to stop. If we were already signaled, exit // immediately. In our interpreter loop we try to consult this value often, but if for // whatever reason we don't get to that check or the cleanup we do upon finding that // this bool has become true takes a long time, the exit here will promptly exit the // process on the second Ctrl-C. - if SIGNALED.swap(true, Relaxed) { + if CTRL_C_RECEIVED.swap(true, Relaxed) { std::process::exit(1); } }) - .unwrap(); + .expect("Unable to install ctrlc handler"); let this = self.eval_context_mut(); loop { - if SIGNALED.load(Relaxed) { + if CTRL_C_RECEIVED.load(Relaxed) { this.machine.handle_abnormal_termination(); std::process::exit(1); } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2e7781109311a..b52f779fc684a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -134,6 +134,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "crossbeam-utils", "crypto-common", "cstr", + "ctrlc", "datafrog", "derive_more", "digest", @@ -185,6 +186,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "memmap2", "memoffset", "miniz_oxide", + "nix", "num_cpus", "object", "odht", @@ -281,6 +283,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "winapi-util", "winapi-x86_64-pc-windows-gnu", "windows", + "windows-sys", "windows-targets", "windows_aarch64_gnullvm", "windows_aarch64_msvc", From 7f8846a9ef4426d18b911783ab83b83a80a852d1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 17:12:45 +0200 Subject: [PATCH 2/9] Uplift clippy::invalid_utf8_in_unchecked as invalid_from_utf8_unchecked --- compiler/rustc_lint/messages.ftl | 4 + compiler/rustc_lint/src/invalid_from_utf8.rs | 85 ++++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lints.rs | 10 +++ compiler/rustc_span/src/symbol.rs | 2 + library/core/src/str/converts.rs | 2 + tests/ui/lint/invalid_from_utf8.rs | 49 +++++++++++ tests/ui/lint/invalid_from_utf8.stderr | 56 +++++++++++++ 8 files changed, 211 insertions(+) create mode 100644 compiler/rustc_lint/src/invalid_from_utf8.rs create mode 100644 tests/ui/lint/invalid_from_utf8.rs create mode 100644 tests/ui/lint/invalid_from_utf8.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d34a3afcba53a..35edb45847808 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -304,6 +304,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs new file mode 100644 index 0000000000000..2118deba5c718 --- /dev/null +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -0,0 +1,85 @@ +use std::str::Utf8Error; + +use rustc_ast::{BorrowKind, LitKind}; +use rustc_hir::{Expr, ExprKind}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; + +use crate::lints::InvalidFromUtf8UncheckedDiag; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_from_utf8_unchecked` lint checks for calls to + /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #[allow(unused)] + /// unsafe { + /// std::str::from_utf8_unchecked(b"Ru\x82st"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating such a `str` would result in undefined behavior as per documentation + /// for `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`. + pub INVALID_FROM_UTF8_UNCHECKED, + Deny, + "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED]); + +impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + && [sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + { + let lint = |utf8_error: Utf8Error| { + let method = diag_item.as_str().strip_prefix("str_").unwrap(); + cx.emit_spanned_lint(INVALID_FROM_UTF8_UNCHECKED, expr.span, InvalidFromUtf8UncheckedDiag { + method: format!("std::str::{method}"), + valid_up_to: utf8_error.valid_up_to(), + label: arg.span, + }) + }; + + match &arg.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => { + if let LitKind::ByteStr(bytes, _) = &lit + && let Err(utf8_error) = std::str::from_utf8(bytes) + { + lint(utf8_error); + } + }, + ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + let elements = args.iter().map(|e|{ + match &e.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => match lit { + LitKind::Byte(b) => Some(*b), + LitKind::Int(b, _) => Some(*b as u8), + _ => None + } + _ => None + } + }).collect::>>(); + + if let Some(elements) = elements + && let Err(utf8_error) = std::str::from_utf8(&elements) + { + lint(utf8_error); + } + } + _ => {} + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index dfddfe09ab3c1..c62109b298629 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -60,6 +60,7 @@ mod expect; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; +mod invalid_from_utf8; mod late; mod let_underscore; mod levels; @@ -102,6 +103,7 @@ use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; +use invalid_from_utf8::*; use let_underscore::*; use map_unit_fn::*; use methods::*; @@ -207,6 +209,7 @@ late_lint_methods!( HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, + InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index de1c2be287576..5969bc5ca5a3c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -699,6 +699,16 @@ pub struct ForgetCopyDiag<'a> { pub label: Span, } +// invalid_from_utf8.rs +#[derive(LintDiagnostic)] +#[diag(lint_invalid_from_utf8_unchecked)] +pub struct InvalidFromUtf8UncheckedDiag { + pub method: String, + pub valid_up_to: usize, + #[label] + pub label: Span, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 874d578fe1db3..4fc73c4ae8646 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,8 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8_unchecked, + str_from_utf8_unchecked_mut, str_split_whitespace, str_trim, str_trim_end, diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 5f8748206d764..12fac0567cb43 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -167,6 +167,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +195,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs new file mode 100644 index 0000000000000..4a27c659c73d4 --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -0,0 +1,49 @@ +// check-pass + +#![feature(concat_bytes)] +#![warn(invalid_from_utf8_unchecked)] + +pub fn from_utf8_unchecked_mut() { + // Valid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xA0; + std::str::from_utf8_unchecked_mut(&mut [0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + } +} + +pub fn from_utf8_unchecked() { + // Valid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8_unchecked(b"clippy"); + + let x = 0xA0; + std::str::from_utf8_unchecked(&[0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8_unchecked` + } +} + +fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr new file mode 100644 index 0000000000000..63cd906237dd7 --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -0,0 +1,56 @@ +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:18:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:4:9 + | +LL | #![warn(invalid_from_utf8_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:20:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:38:9 + | +LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:40:9 + | +LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:42:9 + | +LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:44:9 + | +LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 6 warnings emitted + From a0612d90b08e2ee3fac4e807f56e51dd665ec882 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 18:11:27 +0200 Subject: [PATCH 3/9] Drop uplifted clippy::invalid_utf8_in_unchecked --- .../clippy/clippy_lints/src/declared_lints.rs | 1 - .../src/invalid_utf8_in_unchecked.rs | 74 ------------- src/tools/clippy/clippy_lints/src/lib.rs | 2 - .../clippy/clippy_lints/src/renamed_lints.rs | 1 + .../tests/ui/invalid_utf8_in_unchecked.rs | 20 ---- .../tests/ui/invalid_utf8_in_unchecked.stderr | 22 ---- src/tools/clippy/tests/ui/rename.fixed | 2 + src/tools/clippy/tests/ui/rename.rs | 2 + src/tools/clippy/tests/ui/rename.stderr | 104 +++++++++--------- 9 files changed, 60 insertions(+), 168 deletions(-) delete mode 100644 src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs delete mode 100644 src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 423eee47742e0..0ae95b045e03c 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -212,7 +212,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, - crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, diff --git a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs b/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 6a4861747d267..0000000000000 --- a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_function_call, paths}; -use rustc_ast::{BorrowKind, LitKind}; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal - /// - /// ### Why is this bad? - /// Creating such a `str` would result in undefined behavior - /// - /// ### Example - /// ```rust - /// # #[allow(unused)] - /// unsafe { - /// std::str::from_utf8_unchecked(b"cl\x82ippy"); - /// } - /// ``` - #[clippy::version = "1.64.0"] - pub INVALID_UTF8_IN_UNCHECKED, - correctness, - "using a non UTF-8 literal in `std::std::from_utf8_unchecked`" -} -declare_lint_pass!(InvalidUtf8InUnchecked => [INVALID_UTF8_IN_UNCHECKED]); - -impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) { - match &arg.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes, _) = &lit - && std::str::from_utf8(bytes).is_err() - { - lint(cx, expr.span); - } - }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { - let elements = args.iter().map(|e|{ - match &e.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => match lit { - LitKind::Byte(b) => Some(*b), - #[allow(clippy::cast_possible_truncation)] - LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::>>(); - - if let Some(elements) = elements - && std::str::from_utf8(&elements).is_err() - { - lint(cx, expr.span); - } - } - _ => {} - } - } - } -} - -fn lint(cx: &LateContext<'_>, span: Span) { - span_lint( - cx, - INVALID_UTF8_IN_UNCHECKED, - span, - "non UTF-8 literal in `std::str::from_utf8_unchecked`", - ); -} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b442a4ac5f611..fcca595c2bc4c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -157,7 +157,6 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; -mod invalid_utf8_in_unchecked; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; @@ -937,7 +936,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); - store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index b0db56bb417ea..7c2a100efdac6 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -43,6 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), ("clippy::let_underscore_drop", "let_underscore_drop"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 3dc096d3197fb..0000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![warn(clippy::invalid_utf8_in_unchecked)] - -fn main() { - // Valid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"clippy"); - - let x = 0xA0; - std::str::from_utf8_unchecked(&[0xC0, x]); - } - - // Invalid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"cl\x82ippy"); - } -} diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr deleted file mode 100644 index c89cd2758ee9f..0000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:16:9 - | -LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::invalid-utf8-in-unchecked` implied by `-D warnings` - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:17:9 - | -LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'/x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:18:9 - | -LL | std::str::from_utf8_unchecked(b"cl/x82ippy"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index dfe45dec8a745..53ac65473b827 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] +#![warn(invalid_from_utf8_unchecked)] #![warn(let_underscore_drop)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index ce8eca5a3081c..722c0b3eb2750 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] +#![warn(clippy::invalid_utf8_in_unchecked)] #![warn(clippy::let_underscore_drop)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 3fca60aa2ebd3..1ff8391766023 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,286 +7,292 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` + --> $DIR/rename.rs:91:9 + | +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` + error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 48 previous errors +error: aborting due to 49 previous errors From 7f99c7d3e64143bdeda8f519a656ad1963162fb2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 18:33:19 +0200 Subject: [PATCH 4/9] Add invalid_from_utf8 analogous to invalid_from_utf8_unchecked --- compiler/rustc_lint/messages.ftl | 4 ++ compiler/rustc_lint/src/invalid_from_utf8.rs | 49 +++++++++++--- compiler/rustc_lint/src/lints.rs | 21 ++++-- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/str/converts.rs | 2 + tests/ui/lint/invalid_from_utf8.rs | 44 +++++++++++++ tests/ui/lint/invalid_from_utf8.stderr | 68 ++++++++++++++++++-- 7 files changed, 169 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 35edb45847808..e707ac41a050d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -304,6 +304,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + # FIXME: we should ordinalize $valid_up_to when we add support for doing so lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 2118deba5c718..3291286ad679b 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_span::source_map::Spanned; use rustc_span::sym; -use crate::lints::InvalidFromUtf8UncheckedDiag; +use crate::lints::InvalidFromUtf8Diag; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -33,7 +33,30 @@ declare_lint! { "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" } -declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED]); +declare_lint! { + /// The `invalid_from_utf8` lint checks for calls to + /// `std::str::from_utf8` and `std::str::from_utf8_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust + /// # #[allow(unused)] + /// std::str::from_utf8(b"Ru\x82st"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to create such a `str` would always return an error as per documentation + /// for `std::str::from_utf8` and `std::str::from_utf8_mut`. + pub INVALID_FROM_UTF8, + Warn, + "using a non UTF-8 literal in `std::str::from_utf8`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED, INVALID_FROM_UTF8]); impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -41,15 +64,25 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) - && [sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + && [sym::str_from_utf8, sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) { let lint = |utf8_error: Utf8Error| { + let label = arg.span; let method = diag_item.as_str().strip_prefix("str_").unwrap(); - cx.emit_spanned_lint(INVALID_FROM_UTF8_UNCHECKED, expr.span, InvalidFromUtf8UncheckedDiag { - method: format!("std::str::{method}"), - valid_up_to: utf8_error.valid_up_to(), - label: arg.span, - }) + let method = format!("std::str::{method}"); + let valid_up_to = utf8_error.valid_up_to(); + let is_unchecked_variant = diag_item.as_str().contains("unchecked"); + + cx.emit_spanned_lint( + if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + expr.span, + if is_unchecked_variant { + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + } else { + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + } + ) }; match &arg.kind { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5969bc5ca5a3c..dcfef84f550bb 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -701,12 +701,21 @@ pub struct ForgetCopyDiag<'a> { // invalid_from_utf8.rs #[derive(LintDiagnostic)] -#[diag(lint_invalid_from_utf8_unchecked)] -pub struct InvalidFromUtf8UncheckedDiag { - pub method: String, - pub valid_up_to: usize, - #[label] - pub label: Span, +pub enum InvalidFromUtf8Diag { + #[diag(lint_invalid_from_utf8_unchecked)] + Unchecked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, + #[diag(lint_invalid_from_utf8_checked)] + Checked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, } // hidden_unicode_codepoints.rs diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fc73c4ae8646..1185563ea8063 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,8 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8, + str_from_utf8_mut, str_from_utf8_unchecked, str_from_utf8_unchecked_mut, str_split_whitespace, diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 12fac0567cb43..0f23cf7ae239f 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -84,6 +84,7 @@ use super::Utf8Error; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_allow_const_fn_unstable(str_internals)] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 4a27c659c73d4..9c8c636812e0d 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -2,6 +2,7 @@ #![feature(concat_bytes)] #![warn(invalid_from_utf8_unchecked)] +#![warn(invalid_from_utf8)] pub fn from_utf8_unchecked_mut() { // Valid @@ -46,4 +47,47 @@ pub fn from_utf8_unchecked() { } } +pub fn from_utf8_mut() { + // Valid + { + std::str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xa0; + std::str::from_utf8_mut(&mut [0xc0, x]); + } + + // Invalid + { + std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_mut` + std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_mut` + } +} + +pub fn from_utf8() { + // Valid + { + std::str::from_utf8(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8(b"clippy"); + + let x = 0xA0; + std::str::from_utf8(&[0xC0, x]); + } + + // Invalid + { + std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8` + } +} + fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 63cd906237dd7..8e00d3bf872f4 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,5 +1,5 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:18:9 + --> $DIR/invalid_from_utf8.rs:19:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ @@ -13,7 +13,7 @@ LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:20:9 + --> $DIR/invalid_from_utf8.rs:21:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ @@ -21,7 +21,7 @@ LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:38:9 + --> $DIR/invalid_from_utf8.rs:39:9 | LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ @@ -29,7 +29,7 @@ LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:40:9 + --> $DIR/invalid_from_utf8.rs:41:9 | LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ @@ -37,7 +37,7 @@ LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b' | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:42:9 + --> $DIR/invalid_from_utf8.rs:43:9 | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ @@ -45,12 +45,66 @@ LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:44:9 + --> $DIR/invalid_from_utf8.rs:45:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ | | | the literal was valid UTF-8 up to the 2 bytes -warning: 6 warnings emitted +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:62:9 + | +LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:5:9 + | +LL | #![warn(invalid_from_utf8)] + | ^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:64:9 + | +LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:82:9 + | +LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:84:9 + | +LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:86:9 + | +LL | std::str::from_utf8(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:88:9 + | +LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 12 warnings emitted From b84c190b9ac872fc07ac59c9ec7712dba5b4c2f8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 13 May 2023 21:49:58 +0200 Subject: [PATCH 5/9] Allow newly uplifted invalid_from_utf8 lint --- library/alloc/tests/str.rs | 2 ++ tests/ui/process/process-panic-after-fork.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index c1dbbde08b6b9..0ba5d088f6174 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), allow(invalid_from_utf8))] + use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index da2683121735f..7c2fc296bb028 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -11,6 +11,8 @@ #![feature(never_type)] #![feature(panic_always_abort)] +#![allow(invalid_from_utf8)] + extern crate libc; use std::alloc::{GlobalAlloc, Layout}; From 9495095fe68b737254a20e39b3c744ca41e66d6f Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 7 May 2023 03:00:41 -0700 Subject: [PATCH 6/9] Add a distinct `OperandValue::ZeroSized` variant for ZSTs These tend to have special handling in a bunch of places anyway, so the variant helps remember that. And I think it's easier to grok than non-Scalar Aggregates sometimes being `Immediates` (like I got wrong and caused 109992). As a minor bonus, it means we don't need to generate poison LLVM values for them to pass around in `OperandValue::Immediate`s. --- compiler/rustc_codegen_gcc/src/builder.rs | 2 +- compiler/rustc_codegen_gcc/src/type_of.rs | 3 +- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/type_of.rs | 3 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 13 ++- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 3 + compiler/rustc_codegen_ssa/src/mir/mod.rs | 13 ++- compiler/rustc_codegen_ssa/src/mir/operand.rs | 47 +++++----- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 90 ++++++++++--------- tests/codegen/intrinsics/transmute.rs | 75 +++++++++++++++- 11 files changed, 167 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 869344ce92d7d..f9ea0f004564b 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -758,7 +758,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { - return OperandRef::new_zst(self, place.layout); + return OperandRef::zero_sized(place.layout); } fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) { diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 5df8c1a209db2..30a3fe67b8543 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -159,8 +159,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.abi { Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) => false, - Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), + Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4d0bcd53d1562..5968e70b1ccce 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -486,7 +486,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { - return OperandRef::new_zst(self, place.layout); + return OperandRef::zero_sized(place.layout); } #[instrument(level = "trace", skip(bx))] diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e264ce78f0d67..a493c9c0548e9 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -198,8 +198,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) => false, - Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), + Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 15c7847155d2f..242d209b68425 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -295,7 +295,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let (base, info) = match bx.load_operand(src).val { OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)), OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None), - OperandValue::Ref(..) => bug!(), + OperandValue::Ref(..) | OperandValue::ZeroSized => bug!(), }; OperandValue::Pair(base, info).store(bx, dst); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3f0b64b1103d6..e0cb26d3ba866 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1,5 +1,5 @@ use super::operand::OperandRef; -use super::operand::OperandValue::{Immediate, Pair, Ref}; +use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; use super::place::PlaceRef; use super::{CachedLlbb, FunctionCx, LocalRef}; @@ -427,6 +427,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert_eq!(align, op.layout.align.abi, "return place is unaligned!"); llval } + ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), }; let ty = bx.cast_backend_type(cast_ty); let addr = bx.pointercast(llslot, bx.type_ptr_to(ty)); @@ -1386,6 +1387,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (llval, align, true) } } + ZeroSized => match arg.mode { + PassMode::Indirect { .. } => { + // Though `extern "Rust"` doesn't pass ZSTs, some ABIs pass + // a pointer for `repr(C)` structs even when empty, so get + // one from an `alloca` (which can be left uninitialized). + let scratch = PlaceRef::alloca(bx, arg.layout); + (scratch.llval, scratch.align, true) + } + _ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"), + }, }; if by_ref && !arg.is_indirect() { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index bba2800fb0545..4f79c6a3d823c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -352,6 +352,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.set_var_name(a, &(name.clone() + ".0")); bx.set_var_name(b, &(name.clone() + ".1")); } + OperandValue::ZeroSized => { + // These never have a value to talk about + } }, LocalRef::PendingOperand => {} } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 51393a5d774dc..6617a343d4091 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -129,16 +129,13 @@ enum LocalRef<'tcx, V> { PendingOperand, } -impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { - fn new_operand>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - ) -> LocalRef<'tcx, V> { +impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> { + fn new_operand(layout: TyAndLayout<'tcx>) -> LocalRef<'tcx, V> { if layout.is_zst() { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - LocalRef::Operand(OperandRef::new_zst(bx, layout)) + LocalRef::Operand(OperandRef::zero_sized(layout)) } else { LocalRef::PendingOperand } @@ -249,7 +246,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } else { debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(&mut start_bx, layout) + LocalRef::new_operand(layout) } }; @@ -355,7 +352,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let local = |op| LocalRef::Operand(op); match arg.mode { PassMode::Ignore => { - return local(OperandRef::new_zst(bx, arg.layout)); + return local(OperandRef::zero_sized(arg.layout)); } PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2301c3ef13e21..98f7efd13e48b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -45,6 +45,14 @@ pub enum OperandValue { /// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`] /// with `immediate: true`. Pair(V, V), + /// A value taking no bytes, and which therefore needs no LLVM value at all. + /// + /// If you ever need a `V` to pass to something, get a fresh poison value + /// from [`ConstMethods::const_poison`]. + /// + /// An `OperandValue` *must* be this variant for any type for which + /// `is_zst` on its `Layout` returns `true`. + ZeroSized, } /// An `OperandRef` is an "SSA" reference to a Rust value, along with @@ -71,15 +79,9 @@ impl fmt::Debug for OperandRef<'_, V> { } impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { - pub fn new_zst>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - ) -> OperandRef<'tcx, V> { + pub fn zero_sized(layout: TyAndLayout<'tcx>) -> OperandRef<'tcx, V> { assert!(layout.is_zst()); - OperandRef { - val: OperandValue::Immediate(bx.const_poison(bx.immediate_backend_type(layout))), - layout, - } + OperandRef { val: OperandValue::ZeroSized, layout } } pub fn from_const>( @@ -97,7 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } - ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout), + ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { data, start, end } => { let Abi::ScalarPair(a_scalar, _) = layout.abi else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); @@ -147,6 +149,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandValue::Immediate(llptr) => (llptr, None), OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self), + OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self), }; let layout = cx.layout_of(projected_ty); PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi } @@ -204,9 +207,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let mut val = match (self.val, self.layout.abi) { // If the field is ZST, it has no data. - _ if field.is_zst() => { - return OperandRef::new_zst(bx, field); - } + _ if field.is_zst() => OperandValue::ZeroSized, // Newtype of a scalar, scalar pair or vector. (OperandValue::Immediate(_) | OperandValue::Pair(..), _) @@ -237,6 +238,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { }; match (&mut val, field.abi) { + (OperandValue::ZeroSized, _) => {} ( OperandValue::Immediate(llval), Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. }, @@ -290,8 +292,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { impl<'a, 'tcx, V: CodegenObject> OperandValue { /// Returns an `OperandValue` that's generally UB to use in any way. /// - /// Depending on the `layout`, returns an `Immediate` or `Pair` containing - /// poison value(s), or a `Ref` containing a poison pointer. + /// Depending on the `layout`, returns `ZeroSized` for ZSTs, an `Immediate` or + /// `Pair` containing poison value(s), or a `Ref` containing a poison pointer. /// /// Supports sized types only. pub fn poison>( @@ -299,7 +301,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { layout: TyAndLayout<'tcx>, ) -> OperandValue { assert!(layout.is_sized()); - if bx.cx().is_backend_immediate(layout) { + if layout.is_zst() { + OperandValue::ZeroSized + } else if bx.cx().is_backend_immediate(layout) { let ibty = bx.cx().immediate_backend_type(layout); OperandValue::Immediate(bx.const_poison(ibty)) } else if bx.cx().is_backend_scalar_pair(layout) { @@ -352,12 +356,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { flags: MemFlags, ) { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); - // Avoid generating stores of zero-sized values, because the only way to have a zero-sized - // value is through `undef`, and store itself is useless. - if dest.layout.is_zst() { - return; - } match self { + OperandValue::ZeroSized => { + // Avoid generating stores of zero-sized values, because the only way to have a zero-sized + // value is through `undef`/`poison`, and the store itself is useless. + } OperandValue::Ref(r, None, source_align) => { if flags.contains(MemFlags::NONTEMPORAL) { // HACK(nox): This is inefficient but there is no nontemporal memcpy. @@ -458,7 +461,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checks in `codegen_consume` and `extract_field`. let elem = o.layout.field(bx.cx(), 0); if elem.is_zst() { - o = OperandRef::new_zst(bx, elem); + o = OperandRef::zero_sized(elem); } else { return None; } @@ -492,7 +495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // ZSTs don't require any actual memory access. if layout.is_zst() { - return OperandRef::new_zst(bx, layout); + return OperandRef::zero_sized(layout); } if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6e7065713b817..c67eb4b0e3347 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -70,6 +70,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Ref(_, Some(_), _) => { bug!("unsized coercion on an unsized rvalue"); } + OperandValue::ZeroSized => { + bug!("unsized coercion on a ZST rvalue"); + } } } @@ -165,11 +168,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } match src.val { - OperandValue::Ref(..) => { + OperandValue::Ref(..) | OperandValue::ZeroSized => { span_bug!( self.mir.span, "Operand path should have handled transmute \ - from `Ref` {src:?} to place {dst:?}" + from {src:?} to place {dst:?}" ); } OperandValue::Immediate(..) | OperandValue::Pair(..) => { @@ -220,31 +223,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fake_place = PlaceRef::new_sized_aligned(cast_ptr, cast, align); Some(bx.load_operand(fake_place).val) } + OperandValue::ZeroSized => { + let OperandValueKind::ZeroSized = operand_kind else { + bug!("Found {operand_kind:?} for operand {operand:?}"); + }; + if let OperandValueKind::ZeroSized = cast_kind { + Some(OperandValue::ZeroSized) + } else { + None + } + } OperandValue::Immediate(imm) => { let OperandValueKind::Immediate(in_scalar) = operand_kind else { bug!("Found {operand_kind:?} for operand {operand:?}"); }; - if let OperandValueKind::Immediate(out_scalar) = cast_kind { - match (in_scalar, out_scalar) { - (ScalarOrZst::Zst, ScalarOrZst::Zst) => { - Some(OperandRef::new_zst(bx, cast).val) - } - (ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar)) - if in_scalar.size(self.cx) == out_scalar.size(self.cx) => - { - let operand_bty = bx.backend_type(operand.layout); - let cast_bty = bx.backend_type(cast); - Some(OperandValue::Immediate(self.transmute_immediate( - bx, - imm, - in_scalar, - operand_bty, - out_scalar, - cast_bty, - ))) - } - _ => None, - } + if let OperandValueKind::Immediate(out_scalar) = cast_kind + && in_scalar.size(self.cx) == out_scalar.size(self.cx) + { + let operand_bty = bx.backend_type(operand.layout); + let cast_bty = bx.backend_type(cast); + Some(OperandValue::Immediate(self.transmute_immediate( + bx, + imm, + in_scalar, + operand_bty, + out_scalar, + cast_bty, + ))) } else { None } @@ -457,6 +462,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Ref(..) => { bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand); } + OperandValue::ZeroSized => { + bug!("zero-sized operand {:?} in `codegen_rvalue_operand`", operand); + } }; let (lldata, llextra) = base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra); @@ -490,6 +498,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Ref(_, _, _) => todo!(), OperandValue::Immediate(v) => (v, None), OperandValue::Pair(v, l) => (v, Some(l)), + OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"), }; let (lldata, llextra) = base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); @@ -713,7 +722,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // According to `rvalue_creates_operand`, only ZST // aggregate rvalues are allowed to be operands. let ty = rvalue.ty(self.mir, self.cx.tcx()); - OperandRef::new_zst(bx, self.cx.layout_of(self.monomorphize(ty))) + OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty))) } mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { let operand = self.codegen_operand(bx, operand); @@ -931,6 +940,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Can always load from a pointer as needed (OperandValueKind::Ref, _) => true, + // ZST-to-ZST is the easiest thing ever + (OperandValueKind::ZeroSized, OperandValueKind::ZeroSized) => true, + + // But if only one of them is a ZST the sizes can't match + (OperandValueKind::ZeroSized, _) | (_, OperandValueKind::ZeroSized) => false, + // Need to generate an `alloc` to get a pointer from an immediate (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, @@ -974,12 +989,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Gets which variant of [`OperandValue`] is expected for a particular type. fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind { - if self.cx.is_backend_immediate(layout) { + if layout.is_zst() { + OperandValueKind::ZeroSized + } else if self.cx.is_backend_immediate(layout) { debug_assert!(!self.cx.is_backend_scalar_pair(layout)); OperandValueKind::Immediate(match layout.abi { - abi::Abi::Scalar(s) => ScalarOrZst::Scalar(s), - abi::Abi::Vector { element, .. } => ScalarOrZst::Scalar(element), - _ if layout.is_zst() => ScalarOrZst::Zst, + abi::Abi::Scalar(s) => s, + abi::Abi::Vector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { @@ -1002,21 +1018,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[derive(Debug, Copy, Clone)] enum OperandValueKind { Ref, - Immediate(ScalarOrZst), + Immediate(abi::Scalar), Pair(abi::Scalar, abi::Scalar), -} - -#[derive(Debug, Copy, Clone)] -enum ScalarOrZst { - Zst, - Scalar(abi::Scalar), -} - -impl ScalarOrZst { - pub fn size(self, cx: &impl abi::HasDataLayout) -> abi::Size { - match self { - ScalarOrZst::Zst => abi::Size::ZERO, - ScalarOrZst::Scalar(s) => s.size(cx), - } - } + ZeroSized, } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 664e697c2a5d2..fe42494000e17 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -14,10 +14,10 @@ use std::intrinsics::{transmute, transmute_unchecked}; // Some of these need custom MIR to not get removed by MIR optimizations. use std::intrinsics::mir::*; -enum Never {} +pub enum ZstNever {} #[repr(align(2))] -pub struct BigNever(Never, u16, Never); +pub struct BigNever(ZstNever, u16, ZstNever); #[repr(align(8))] pub struct Scalar64(i64); @@ -56,11 +56,13 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { transmute_unchecked(x) } -// CHECK-LABEL: @check_to_uninhabited( +// CHECK-LABEL: @check_to_empty_array( #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] -pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { +pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { + // CHECK-NOT: trap // CHECK: call void @llvm.trap + // CHECK-NOT: trap mir!{ { RET = CastTransmute(x); @@ -69,6 +71,37 @@ pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { } } +// CHECK-LABEL: @check_from_empty_array( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { + // CHECK-NOT: trap + // CHECK: call void @llvm.trap + // CHECK-NOT: trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_to_uninhabited(x: u16) { + // CHECK-NOT: trap + // CHECK: call void @llvm.trap + // CHECK-NOT: trap + mir!{ + let temp: BigNever; + { + temp = CastTransmute(x); + Return() + } + } +} + // CHECK-LABEL: @check_from_uninhabited( #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] @@ -366,6 +399,40 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { } } +// CHECK-LABEL: @check_unit_to_never( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_unit_to_never(x: ()) { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK-NOT: trap + // CHECK: call void @llvm.trap + // CHECK-NOT: trap + mir!{ + let temp: ZstNever; + { + temp = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_unit_from_never( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_unit_from_never(x: ZstNever) -> () { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK: start + // CHECK-NEXT: ret void + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + // CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1) #[no_mangle] pub unsafe fn check_maybe_uninit_pair( From f333932ba8b473c2ed85752cbdb3b58a11acf421 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 May 2023 15:59:45 +0200 Subject: [PATCH 7/9] Update browser-ui-test version to 0.16.5 --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 806935b827ff5..3ccca1e8b89bc 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.4 \ No newline at end of file +0.16.5 \ No newline at end of file From 17e3d1cd4a25744e68bdf2c9792adcc580c015b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 May 2023 16:03:56 +0200 Subject: [PATCH 8/9] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/target.goml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 0c514fc686420..c5e7f813dd194 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -25,11 +25,11 @@ call-function: ("check-style", { }) call-function: ("check-style", { "theme": "dark", - "background": "rgb(73, 74, 61)", - "border": "rgb(187, 116, 16)", + "background": "#494a3d", + "border": "#bb7410", }) call-function: ("check-style", { "theme": "light", - "background": "rgb(253, 255, 211)", - "border": "rgb(173, 124, 55)", + "background": "#fdffd3", + "border": "#ad7c37", }) From 000cd9b5fb9aad0c4fc3e3172387aac79d50a1d3 Mon Sep 17 00:00:00 2001 From: reez12g Date: Tue, 30 May 2023 13:56:57 +0900 Subject: [PATCH 9/9] fix comment on Allocator trait --- library/core/src/alloc/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ff390322d552d..452bc482cc1a4 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,8 +94,9 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// * Memory blocks returned from an allocator must point to valid memory and retain their validity -/// until the instance and all of its copies and clones are dropped, +/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to +/// valid memory and retain their validity while they are [*currently allocated*] and at +/// least one of the instance and all of its clones has not been dropped. /// /// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this /// allocator. A copied or cloned allocator must behave like the same allocator, and