diff --git a/Cargo.lock b/Cargo.lock index 6fc077871155e..77dcd056f8777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5700,6 +5700,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo_metadata 0.15.4", + "fluent-syntax", "ignore", "miropt-test-tools", "regex", diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 7d81e45d314d8..52164d6ef1648 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -78,7 +78,7 @@ ast_lowering_inline_asm_unsupported_target = ast_lowering_invalid_abi = invalid ABI: found `{$abi}` .label = invalid ABI - .note = invoke `{$command}` for a full list of supported calling conventions. + .note = invoke `{$command}` for a full list of supported calling conventions ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1a7e5bd70921b..1476fe285ef5c 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -341,8 +341,7 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in const_eval_unallowed_heap_allocations = allocations are not allowed in {const_eval_const_context}s .label = allocation not allowed in {const_eval_const_context}s - .teach_note = - The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + .teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9a26ac04b85a3..9d0c490822561 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -630,6 +630,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Gives raw, immutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { + let alloc = self.get_alloc_raw(id)?; + Ok(alloc.get_bytes_unchecked_raw()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc<'a>( &'a self, @@ -713,6 +720,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok((alloc, &mut self.machine)) } + /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw_mut( + &mut self, + id: AllocId, + ) -> InterpResult<'tcx, *mut u8> { + let alloc = self.get_alloc_raw_mut(id)?.0; + Ok(alloc.get_bytes_unchecked_raw_mut()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 8c740d87e9535..ca653e50aab76 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -194,7 +194,7 @@ hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outs .span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined - .label = impl for type defined outside of crate. + .label = impl for type defined outside of crate .note = define and implement a trait or new type instead hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core` @@ -544,7 +544,7 @@ hir_analysis_unrecognized_intrinsic_function = hir_analysis_unused_associated_type_bounds = unnecessary associated type bound for not object safe associated type - .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + .note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` .suggestion = remove this bound hir_analysis_unused_generic_parameter = diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 468673f05c118..fdedf2c2e6d38 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -75,7 +75,7 @@ lint_builtin_deprecated_attr_default_suggestion = remove this attribute lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} .msg_suggestion = {$msg} .default_suggestion = remove this attribute -lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. +lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -213,7 +213,7 @@ lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better pe lint_default_source = `forbid` lint level is the default for {$id} lint_deprecated_lint_name = - lint name `{$name}` is deprecated and may not have an effect in the future. + lint name `{$name}` is deprecated and may not have an effect in the future .suggestion = change it to .help = change it to {$replace} @@ -244,11 +244,11 @@ lint_duplicate_matcher_binding = duplicate matcher binding lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type - .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum lint_enum_intrinsics_mem_variant = the return value of `mem::variant_count` is unspecified when called with a non-enum type - .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 932603cd6b267..415399ed06c7f 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -248,13 +248,13 @@ metadata_rustc_lib_required = .help = try adding `extern crate rustc_driver;` at the top level of this crate metadata_stable_crate_id_collision = - found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values metadata_std_required = `std` is required by `{$current_crate}` because it does not declare `#![no_std]` metadata_symbol_conflicts_current = - the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments, so this will result in symbol conflicts between the two metadata_target_no_std_support = the `{$locator_triple}` target may not support the standard library diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2fc466c0e7e91..cac3bf948a0c1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -40,9 +40,16 @@ pub trait AllocBytes: Clone + fmt::Debug + Deref + DerefMut *mut u8; + + /// Gives direct access to the raw underlying storage. + /// + /// Crucially this pointer is compatible with: + /// - other pointers returned by this method, and + /// - references returned from `deref()`, as long as there was no write. + fn as_ptr(&self) -> *const u8; } /// Default `bytes` for `Allocation` is a `Box`. @@ -62,6 +69,11 @@ impl AllocBytes for Box<[u8]> { // Carefully avoiding any intermediate references. ptr::addr_of_mut!(**self).cast() } + + fn as_ptr(&self) -> *const u8 { + // Carefully avoiding any intermediate references. + ptr::addr_of!(**self).cast() + } } /// This type represents an Allocation in the Miri/CTFE core engine. @@ -490,19 +502,27 @@ impl Allocation self.provenance.clear(range, cx)?; assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check - // Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. + // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); let len = range.end().bytes_usize() - range.start.bytes_usize(); Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len)) } /// This gives direct mutable access to the entire buffer, just exposing their internal state - /// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if + /// without resetting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if /// `OFFSET_IS_ADDR` is true. pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 { assert!(Prov::OFFSET_IS_ADDR); self.bytes.as_mut_ptr() } + + /// This gives direct immutable access to the entire buffer, just exposing their internal state + /// without resetting anything. Directly exposes `AllocBytes::as_ptr`. Only works if + /// `OFFSET_IS_ADDR` is true. + pub fn get_bytes_unchecked_raw(&self) -> *const u8 { + assert!(Prov::OFFSET_IS_ADDR); + self.bytes.as_ptr() + } } /// Reading and writing. diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 1ee8777c27414..0c277811fdacf 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -103,7 +103,7 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior .label = dereference of raw pointer -mir_build_exceeds_mcdc_condition_limit = Number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}). MC/DC analysis will not count this expression. +mir_build_exceeds_mcdc_condition_limit = number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}), so MC/DC analysis will not count this expression mir_build_extern_static_requires_unsafe = use of extern static is unsafe and requires unsafe block diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 84dbd192723e1..84c71c4bed29b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -14,7 +14,7 @@ passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} passes_allow_incoherent_impl = - `rustc_allow_incoherent_impl` attribute should be applied to impl items. + `rustc_allow_incoherent_impl` attribute should be applied to impl items .label = the only currently supported targets are inherent methods passes_allow_internal_unstable = @@ -253,8 +253,8 @@ passes_doc_test_unknown_spotlight = .no_op_note = `doc(spotlight)` is now a no-op passes_duplicate_diagnostic_item_in_crate = - duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. - .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. + duplicate diagnostic item in crate `{$crate_name}`: `{$name}` + .note = the diagnostic item is first defined in crate `{$orig_crate_name}` passes_duplicate_feature_err = the feature `{$feature}` has already been declared @@ -263,27 +263,27 @@ passes_duplicate_lang_item = found duplicate lang item `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate = - duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate_depends = - duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} @@ -315,7 +315,7 @@ passes_ffi_pure_invalid_target = `#[ffi_pure]` may only be used on foreign functions passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported passes_ignored_attr = diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 358f25e233434..4b9c36ad39fb5 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -240,7 +240,7 @@ resolve_label_with_similar_name_reachable = resolve_lending_iterator_report_error = associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type - .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type resolve_lifetime_param_in_enum_discriminant = lifetime parameters may not be used in enum discriminant values diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b8dacc6968d30..b84280a3ccf3f 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -82,9 +82,9 @@ session_octal_float_literal_not_supported = octal float literal is not supported session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} -session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist -session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 9afd507ce113a..dde5e30c3d071 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -533,6 +533,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) } + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let sig = fn_ptr.internal(&mut *tables, tcx); + Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables)) + } + fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 3e138e3c2e04e..44dbf549c1a73 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -215,6 +215,9 @@ pub trait Context { /// Get an instance ABI. fn instance_abi(&self, def: InstanceDef) -> Result; + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; + /// Get the layout of a type. fn ty_layout(&self, ty: Ty) -> Result; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 35927237281a0..8c120a96e75b1 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -2,7 +2,7 @@ use super::{ mir::{Body, Mutability, Safety}, with, DefId, Error, Symbol, }; -use crate::abi::Layout; +use crate::abi::{FnAbi, Layout}; use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::mir::mono::StaticDef; @@ -996,6 +996,16 @@ pub struct AliasTerm { pub type PolyFnSig = Binder; +impl PolyFnSig { + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi` + /// instead, where the instance is an `InstanceKind::Virtual`. + pub fn fn_ptr_abi(self) -> Result { + with(|cx| cx.fn_ptr_abi(self)) + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct FnSig { pub inputs_and_output: Vec, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 6677534eafc6e..1833a7f477f00 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -424,29 +424,3 @@ pub mod __alloc_error_handler { } } } - -#[cfg(not(no_global_oom_handling))] -/// Specialize clones into pre-allocated, uninitialized memory. -/// Used by `Box::clone` and `Rc`/`Arc::make_mut`. -pub(crate) trait WriteCloneIntoRaw: Sized { - unsafe fn write_clone_into_raw(&self, target: *mut Self); -} - -#[cfg(not(no_global_oom_handling))] -impl WriteCloneIntoRaw for T { - #[inline] - default unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // Having allocated *first* may allow the optimizer to create - // the cloned value in-place, skipping the local and move. - unsafe { target.write(self.clone()) }; - } -} - -#[cfg(not(no_global_oom_handling))] -impl WriteCloneIntoRaw for T { - #[inline] - unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // We can always copy in-place, without ever involving a local value. - unsafe { target.copy_from_nonoverlapping(self, 1) }; - } -} diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 01a954ed75beb..1ec095a46f704 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -188,6 +188,8 @@ use core::any::Any; use core::async_iter::AsyncIterator; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::error::Error; use core::fmt; @@ -207,7 +209,7 @@ use core::slice; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; +use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; #[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; @@ -1346,7 +1348,7 @@ impl Clone for Box { // Pre-allocate memory to allow writing the cloned value directly. let mut boxed = Self::new_uninit_in(self.1.clone()); unsafe { - (**self).write_clone_into_raw(boxed.as_mut_ptr()); + (**self).clone_to_uninit(boxed.as_mut_ptr()); boxed.assume_init() } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 022a14b931a3c..0f759d64f669d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,6 +103,7 @@ #![feature(assert_matches)] #![feature(async_fn_traits)] #![feature(async_iterator)] +#![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2b7ab2f6e2590..3745ecb48c18e 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -249,6 +249,8 @@ use std::boxed::Box; use core::any::Any; use core::borrow; use core::cell::Cell; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -268,8 +270,6 @@ use core::slice::from_raw_parts_mut; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(no_global_oom_handling))] @@ -1749,7 +1749,8 @@ impl Rc { } } -impl Rc { +#[cfg(not(no_global_oom_handling))] +impl Rc { /// Makes a mutable reference into the given `Rc`. /// /// If there are other `Rc` pointers to the same allocation, then `make_mut` will @@ -1800,31 +1801,52 @@ impl Rc { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = size_of_val::(&**this); + if Rc::strong_count(this) != 1 { // Gotta clone the data, there are other Rcs. - // Pre-allocate memory to allow writing the cloned value directly. - let mut rc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = rc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(this_data_ref, this.alloc.clone()); + + // Initialize with clone of this. + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_rc() + }; + + // Replace `this` with newly constructed Rc. + *this = initialized_clone; } else if Rc::weak_count(this) != 0 { // Can just steal the data, all that's left is Weaks - let mut rc = Self::new_uninit_in(this.alloc.clone()); + + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); this.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) this.inner().dec_weak(); - ptr::write(this, rc.assume_init()); + // Replace `this` with newly constructed Rc that has the moved data. + ptr::write(this, in_progress.into_rc()); } } // This unsafety is ok because we're guaranteed that the pointer @@ -3686,3 +3708,67 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { } } } + +/// A unique owning pointer to a [`RcBox`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. +/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, +/// which `MaybeUninit` does not. +#[cfg(not(no_global_oom_handling))] +struct UniqueRcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueRcUninit { + /// Allocate a RcBox with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueRcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Rc::allocate_for_layout( + layout, + |layout_for_rcbox| alloc.allocate(layout_for_rcbox), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcBox), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Rc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Rc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_rc(mut self) -> Rc { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueRcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_rc() was called, which forgets us. + unsafe { + self.alloc + .take() + .unwrap() + .deallocate(self.ptr.cast(), rcbox_layout_for_value_layout(self.layout_for_value)); + } + } +} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 0f09be7721fa9..5e2e4beb94a2b 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -316,6 +316,24 @@ fn test_cowrc_clone_weak() { assert!(cow1_weak.upgrade().is_none()); } +/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice). +#[test] +fn test_cowrc_unsized() { + use std::rc::Rc; + + let mut data: Rc<[i32]> = Rc::new([10, 20, 30]); + + Rc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Rc::clone(&data); // Won't clone inner data + Rc::make_mut(&mut data)[1] += 1; // Clones inner data + Rc::make_mut(&mut data)[2] += 1; // Won't clone anything + Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} + #[test] fn test_show() { let foo = Rc::new(75); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index f9d884e0ea551..90672164cb932 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -10,6 +10,8 @@ use core::any::Any; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -30,8 +32,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; @@ -2150,7 +2150,8 @@ unsafe impl DerefPure for Arc {} #[unstable(feature = "receiver_trait", issue = "none")] impl Receiver for Arc {} -impl Arc { +#[cfg(not(no_global_oom_handling))] +impl Arc { /// Makes a mutable reference into the given `Arc`. /// /// If there are other `Arc` pointers to the same allocation, then `make_mut` will @@ -2201,10 +2202,11 @@ impl Arc { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = mem::size_of_val::(&**this); + // Note that we hold both a strong reference and a weak reference. // Thus, releasing our strong reference only will not, by itself, cause // the memory to be deallocated. @@ -2215,13 +2217,19 @@ impl Arc { // deallocated. if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { // Another strong pointer exists, so we must clone. - // Pre-allocate memory to allow writing the cloned value directly. - let mut arc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = arc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueArcUninit = + UniqueArcUninit::new(this_data_ref, this.alloc.clone()); + + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_arc() + }; + *this = initialized_clone; } else if this.inner().weak.load(Relaxed) != 1 { // Relaxed suffices in the above because this is fundamentally an // optimization: we are always racing with weak pointers being @@ -2240,11 +2248,22 @@ impl Arc { let _weak = Weak { ptr: this.ptr, alloc: this.alloc.clone() }; // Can just steal the data, all that's left is Weaks - let mut arc = Self::new_uninit_in(this.alloc.clone()); + // + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueArcUninit = + UniqueArcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); - ptr::write(this, arc.assume_init()); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); + + ptr::write(this, in_progress.into_arc()); } } else { // We were the sole reference of either kind; bump back up the @@ -3809,6 +3828,68 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } +/// A unique owning pointer to a [`ArcInner`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic. +#[cfg(not(no_global_oom_handling))] +struct UniqueArcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueArcUninit { + /// Allocate a ArcInner with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueArcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Arc::allocate_for_layout( + layout, + |layout_for_arcinner| alloc.allocate(layout_for_arcinner), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const ArcInner), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Arc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Arc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_arc(mut self) -> Arc { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueArcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_arc() was called, which forgets us. + unsafe { + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + arcinner_layout_for_value_layout(self.layout_for_value), + ); + } + } +} + #[stable(feature = "arc_error", since = "1.52.0")] impl core::error::Error for Arc { #[allow(deprecated, deprecated_in_future)] diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index d564a30b10394..c37a80dca95c8 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -209,3 +209,21 @@ fn weak_may_dangle() { // `val` dropped here while still borrowed // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` } + +/// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). +#[test] +fn make_mut_unsized() { + use alloc::sync::Arc; + + let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); + + Arc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Arc::clone(&data); // Won't clone inner data + Arc::make_mut(&mut data)[1] += 1; // Clones inner data + Arc::make_mut(&mut data)[2] += 1; // Won't clone anything + Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index d448c5338fc46..d7ce65f6c53a9 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -36,6 +36,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::mem::{self, MaybeUninit}; +use crate::ptr; + /// A common trait for the ability to explicitly duplicate an object. /// /// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while @@ -204,6 +207,189 @@ pub struct AssertParamIsCopy { _field: crate::marker::PhantomData, } +/// A generalization of [`Clone`] to dynamically-sized types stored in arbitrary containers. +/// +/// This trait is implemented for all types implementing [`Clone`], and also [slices](slice) of all +/// such types. You may also implement this trait to enable cloning trait objects and custom DSTs +/// (structures containing dynamically-sized fields). +/// +/// # Safety +/// +/// Implementations must ensure that when `.clone_to_uninit(dst)` returns normally rather than +/// panicking, it always leaves `*dst` initialized as a valid value of type `Self`. +/// +/// # See also +/// +/// * [`Clone::clone_from`] is a safe function which may be used instead when `Self` is a [`Sized`] +/// and the destination is already initialized; it may be able to reuse allocations owned by +/// the destination. +/// * [`ToOwned`], which allocates a new destination container. +/// +/// [`ToOwned`]: ../../std/borrow/trait.ToOwned.html +#[unstable(feature = "clone_to_uninit", issue = "126799")] +pub unsafe trait CloneToUninit { + /// Performs copy-assignment from `self` to `dst`. + /// + /// This is analogous to to `std::ptr::write(dst, self.clone())`, + /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). + /// + /// Before this function is called, `dst` may point to uninitialized memory. + /// After this function is called, `dst` will point to initialized memory; it will be + /// sound to create a `&Self` reference from the pointer. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `dst` must be [valid] for writes. + /// * `dst` must be properly aligned. + /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`. + /// + /// [valid]: ptr#safety + /// [pointer metadata]: crate::ptr::metadata() + /// + /// # Panics + /// + /// This function may panic. (For example, it might panic if memory allocation for a clone + /// of a value owned by `self` fails.) + /// If the call panics, then `*dst` should be treated as uninitialized memory; it must not be + /// read or dropped, because even if it was previously valid, it may have been partially + /// overwritten. + /// + /// The caller may also need to take care to deallocate the allocation pointed to by `dst`, + /// if applicable, to avoid a memory leak, and may need to take other precautions to ensure + /// soundness in the presence of unwinding. + /// + /// Implementors should avoid leaking values by, upon unwinding, dropping all component values + /// that might have already been created. (For example, if a `[Foo]` of length 3 is being + /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` + /// cloned should be dropped.) + unsafe fn clone_to_uninit(&self, dst: *mut Self); +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for T { + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::write(). + unsafe { + // We hope the optimizer will figure out to create the cloned value in-place, + // skipping ever storing it on the stack and the copy to the destination. + ptr::write(dst, self.clone()); + } + } +} + +// Specialized implementation for types that are [`Copy`], not just [`Clone`], +// and can therefore be copied bitwise. +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for T { + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self, dst, 1); + } + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The produced `&mut` is valid because: + // * The caller is obligated to provide a pointer which is valid for writes. + // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's + // initialization status. + let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit]) }; + + // Copy the elements + let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref); + for element_ref in self.iter() { + // If the clone() panics, `initializing` will take care of the cleanup. + initializing.push(element_ref.clone()); + } + // If we reach here, then the entire slice is initialized, and we've satisfied our + // responsibilities to the caller. Disarm the cleanup guard by forgetting it. + mem::forget(initializing); + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len); + } + } +} + +/// Ownership of a collection of values stored in a non-owned `[MaybeUninit]`, some of which +/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation. +/// Its responsibility is to provide cleanup on unwind by dropping the values that *are* +/// initialized, unless disarmed by forgetting. +/// +/// This is a helper for `impl CloneToUninit for [T]`. +struct InitializingSlice<'a, T> { + data: &'a mut [MaybeUninit], + /// Number of elements of `*self.data` that are initialized. + initialized_len: usize, +} + +impl<'a, T> InitializingSlice<'a, T> { + #[inline] + fn from_fully_uninit(data: &'a mut [MaybeUninit]) -> Self { + Self { data, initialized_len: 0 } + } + + /// Push a value onto the end of the initialized part of the slice. + /// + /// # Panics + /// + /// Panics if the slice is already fully initialized. + #[inline] + fn push(&mut self, value: T) { + MaybeUninit::write(&mut self.data[self.initialized_len], value); + self.initialized_len += 1; + } +} + +impl<'a, T> Drop for InitializingSlice<'a, T> { + #[cold] // will only be invoked on unwind + fn drop(&mut self) { + let initialized_slice = ptr::slice_from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(self.data), + self.initialized_len, + ); + // SAFETY: + // * the pointer is valid because it was made from a mutable reference + // * `initialized_len` counts the initialized elements as an invariant of this type, + // so each of the pointed-to elements is initialized and may be dropped. + unsafe { + ptr::drop_in_place::<[T]>(initialized_slice); + } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index 64193e1155890..225afc62a0dff 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,3 +1,7 @@ +use core::clone::CloneToUninit; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + #[test] #[allow(suspicious_double_ref_op)] fn test_borrowed_clone() { @@ -14,3 +18,63 @@ fn test_clone_from() { b.clone_from(&a); assert_eq!(*b, 5); } + +#[test] +fn test_clone_to_uninit_slice_success() { + // Using `String`s to exercise allocation and Drop of the individual elements; + // if something is aliased or double-freed, at least Miri will catch that. + let a: [String; 3] = ["a", "b", "c"].map(String::from); + + let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); + let b: [String; 3] = unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [String]); + storage.assume_init() + }; + + assert_eq!(a, b); +} + +#[test] +fn test_clone_to_uninit_slice_drops_on_panic() { + /// A static counter is OK to use as long as _this one test_ isn't run several times in + /// multiple threads. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + /// Counts how many instances are live, and panics if a fifth one is created + struct CountsDropsAndPanics {} + impl CountsDropsAndPanics { + fn new() -> Self { + COUNTER.fetch_add(1, Relaxed); + Self {} + } + } + impl Clone for CountsDropsAndPanics { + fn clone(&self) -> Self { + if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() } + } + } + impl Drop for CountsDropsAndPanics { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new()); + assert_eq!(COUNTER.load(Relaxed), 3); + + let panic_payload = std::panic::catch_unwind(|| { + let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); + // This should panic halfway through + unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [CountsDropsAndPanics]); + } + }) + .unwrap_err(); + assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic")); + + // Check for lack of leak, which is what this test is looking for + assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!"); + + // Might as well exercise the rest of the drops + drop(a); + assert_eq!(COUNTER.load(Relaxed), 0); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 6845a630dff39..3a2c98db0d50a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(cell_update)] +#![feature(clone_to_uninit)] #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] @@ -53,6 +54,7 @@ #![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_fill)] +#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 115ee69a5891b..6db25ff1a809e 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -112,7 +112,7 @@ def atomic_link(link: Path, target: Path): os.remove(tmp_file) -@dataclass(kw_only=True) +@dataclass class TestEnvironment: rust_build_dir: Path sdk_dir: Path diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 97841a05cdebf..8f691456a596d 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -108,4 +108,8 @@ impl AllocBytes for MiriAllocBytes { fn as_mut_ptr(&mut self) -> *mut u8 { self.ptr } + + fn as_ptr(&self) -> *const u8 { + self.ptr + } } diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 63963b0bd1ced..f39438bd9ace2 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -13,6 +13,7 @@ ignore = "0.4.18" semver = "1.0" termcolor = "1.1.3" rustc-hash = "1.1.0" +fluent-syntax = "0.11.1" [[bin]] name = "rust-tidy" diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs new file mode 100644 index 0000000000000..3a1fb6daf4854 --- /dev/null +++ b/src/tools/tidy/src/fluent_period.rs @@ -0,0 +1,84 @@ +//! Checks that no Fluent messages or attributes end in periods (except ellipses) + +use fluent_syntax::ast::{Entry, PatternElement}; + +use crate::walk::{filter_dirs, walk}; +use std::path::Path; + +fn filter_fluent(path: &Path) -> bool { + if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } +} + +/// Messages allowed to have `.` at their end. +/// +/// These should probably be reworked eventually. +const ALLOWLIST: &[&str] = &[ + "const_eval_long_running", + "const_eval_validation_failure_note", + "driver_impl_ice", + "incremental_corrupt_file", + "mir_build_pointer_pattern", +]; + +fn check_period(filename: &str, contents: &str, bad: &mut bool) { + if filename.contains("codegen") { + // FIXME: Too many codegen messages have periods right now... + return; + } + + let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents); + for entry in &parse.body { + if let Entry::Message(m) = entry { + if ALLOWLIST.contains(&m.id.name) { + continue; + } + + if let Some(pat) = &m.value { + if let Some(PatternElement::TextElement { value }) = pat.elements.last() { + // We don't care about ellipses. + if value.ends_with(".") && !value.ends_with("...") { + let ll = find_line(contents, *value); + let name = m.id.name; + tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period"); + } + } + } + + for attr in &m.attributes { + // Teach notes usually have long messages. + if attr.id.name == "teach_note" { + continue; + } + + if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() { + if value.ends_with(".") && !value.ends_with("...") { + let ll = find_line(contents, *value); + let name = attr.id.name; + tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period"); + } + } + } + } + } +} + +/// Evil cursed bad hack. Requires that `value` be a substr (in memory) of `contents`. +fn find_line(haystack: &str, needle: &str) -> usize { + for (ll, line) in haystack.lines().enumerate() { + if line.as_ptr() > needle.as_ptr() { + return ll; + } + } + + 1 +} + +pub fn check(path: &Path, bad: &mut bool) { + walk( + path, + |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), + &mut |ent, contents| { + check_period(ent.path().to_str().unwrap(), contents, bad); + }, + ); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index ae9d2b8b8dc87..ecd32727fa058 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -72,6 +72,7 @@ pub mod ext_tool_checks; pub mod extdeps; pub mod features; pub mod fluent_alphabetical; +pub mod fluent_period; mod fluent_used; pub(crate) mod iter_header; pub mod known_bug; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 1d2b2e4d03472..ec6fc1f07f11e 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -115,6 +115,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); check!(fluent_alphabetical, &compiler_path, bless); + check!(fluent_period, &compiler_path); check!(target_policy, &root_path); // Checks that only make sense for the std libs. diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 359dd4146baf5..7518ea902ecf5 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -54,6 +54,21 @@ fn test_stable_mir() -> ControlFlow<()> { let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); check_variadic(variadic_fn); + // Extract function pointers. + let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "fn_ptr_holder")).unwrap(); + let fn_ptr_holder_instance = Instance::try_from(fn_ptr_holder).unwrap(); + let body = fn_ptr_holder_instance.body().unwrap(); + let args = body.arg_locals(); + + // Test fn_abi of function pointer version. + let ptr_fn_abi = args[0].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap(); + assert_eq!(ptr_fn_abi, fn_abi); + + // Test variadic_fn of function pointer version. + let ptr_variadic_fn_abi = args[1].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap(); + assert!(ptr_variadic_fn_abi.c_variadic); + assert_eq!(ptr_variadic_fn_abi.args.len(), 1); + ControlFlow::Continue(()) } @@ -164,6 +179,14 @@ fn generate_input(path: &str) -> std::io::Result<()> { pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ 0 }} + + pub type ComplexFn = fn([u8; 0], char, NonZero) -> Result; + pub type VariadicFn = unsafe extern "C" fn(usize, ...) -> usize; + + pub fn fn_ptr_holder(complex_fn: ComplexFn, variadic_fn: VariadicFn) {{ + // We only care about the signature. + todo!() + }} "# )?; Ok(()) diff --git a/tests/ui/abi/abi-typo-unstable.stderr b/tests/ui/abi/abi-typo-unstable.stderr index d31cc2a896f72..9ba67ad7dbe4a 100644 --- a/tests/ui/abi/abi-typo-unstable.stderr +++ b/tests/ui/abi/abi-typo-unstable.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `rust-intrinsec` LL | extern "rust-intrinsec" fn rust_intrinsic() {} | ^^^^^^^^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr index 02082c13f91a7..e80411fda344e 100644 --- a/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr +++ b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr @@ -7,7 +7,7 @@ LL | extern "riscv-interrupt" fn isr() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively error[E0703]: invalid ABI: found `riscv-interrupt-u` @@ -19,7 +19,7 @@ LL | extern "riscv-interrupt-u" fn isr_U() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314 error: aborting due to 2 previous errors diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr index 02082c13f91a7..e80411fda344e 100644 --- a/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr +++ b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr @@ -7,7 +7,7 @@ LL | extern "riscv-interrupt" fn isr() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively error[E0703]: invalid ABI: found `riscv-interrupt-u` @@ -19,7 +19,7 @@ LL | extern "riscv-interrupt-u" fn isr_U() {} | invalid ABI | help: did you mean: `"riscv-interrupt-m"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314 error: aborting due to 2 previous errors diff --git a/tests/ui/codemap_tests/unicode.normal.stderr b/tests/ui/codemap_tests/unicode.normal.stderr index a6e22e1c38f9c..0f254e0246f41 100644 --- a/tests/ui/codemap_tests/unicode.normal.stderr +++ b/tests/ui/codemap_tests/unicode.normal.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0116.stderr b/tests/ui/error-codes/E0116.stderr index bf215435ba6a0..1ea5a57f46db1 100644 --- a/tests/ui/error-codes/E0116.stderr +++ b/tests/ui/error-codes/E0116.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/E0116.rs:1:1 | LL | impl Vec {} - | ^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/error-codes/E0519.stderr b/tests/ui/error-codes/E0519.stderr index 4fbd268134f20..a814277cafae2 100644 --- a/tests/ui/error-codes/E0519.stderr +++ b/tests/ui/error-codes/E0519.stderr @@ -1,4 +1,4 @@ -error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. +error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments, so this will result in symbol conflicts between the two --> $DIR/E0519.rs:8:1 | LL | extern crate crateresolve1; diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 30039267979fb..88732f75cb4e1 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -186,7 +186,7 @@ warning: unknown lint: `x5100` LL | #[deny(x5100)] impl S { } | ^^^^^ -warning: use of deprecated attribute `crate_id`: no longer used. +warning: use of deprecated attribute `crate_id`: no longer used --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1 | LL | #![crate_id = "10"] @@ -194,7 +194,7 @@ LL | #![crate_id = "10"] | = note: `#[warn(deprecated)]` on by default -warning: use of deprecated attribute `no_start`: no longer used. +warning: use of deprecated attribute `no_start`: no longer used --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:1 | LL | #![no_start] diff --git a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr index 6dc1680cf89f8..f8491697910c0 100644 --- a/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr +++ b/tests/ui/incoherent-inherent-impls/no-attr-empty-impl.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:4:1 | LL | impl extern_crate::StructWithAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -10,7 +10,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:7:1 | LL | impl extern_crate::StructNoAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -18,7 +18,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:10:1 | LL | impl extern_crate::EnumWithAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead @@ -26,7 +26,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/no-attr-empty-impl.rs:13:1 | LL | impl extern_crate::EnumNoAttr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr index 5df6aaf980414..15fa3f6ee115f 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr @@ -1,4 +1,4 @@ -warning: Number of conditions in decision (7) exceeds limit (6). MC/DC analysis will not count this expression. +warning: number of conditions in decision (7) exceeds limit (6), so MC/DC analysis will not count this expression --> $DIR/mcdc-condition-limit.rs:29:8 | LL | if a && b && c && d && e && f && g { diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs index de3770b5709d0..eb19ddec78fd5 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.rs +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -26,7 +26,7 @@ fn main() { fn main() { // 7 conditions is too many, so issue a diagnostic. let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - if a && b && c && d && e && f && g { //[bad]~ WARNING Number of conditions in decision + if a && b && c && d && e && f && g { //[bad]~ WARNING number of conditions in decision core::hint::black_box("hello"); } } diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr index c3784770d7926..9ceaef2f9b1aa 100644 --- a/tests/ui/lifetimes/no_lending_iterators.stderr +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -4,7 +4,7 @@ error: associated type `Iterator::Item` is declared without lifetime parameters, LL | type Item = &str; | ^ | -note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. +note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type --> $DIR/no_lending_iterators.rs:3:19 | LL | impl Iterator for Data { diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr index 7fe078068feef..ddc31905afbcf 100644 --- a/tests/ui/lint/lint-attr-everywhere-late.stderr +++ b/tests/ui/lint/lint-attr-everywhere-late.stderr @@ -154,7 +154,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | fn assoc_fn() { discriminant::(&123); } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:96:41 | LL | fn assoc_fn() { discriminant::(&123); } @@ -208,7 +208,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | let _ = discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:139:33 | LL | let _ = discriminant::(&123); @@ -237,7 +237,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:155:33 | LL | discriminant::(&123); @@ -254,7 +254,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:161:33 | LL | discriminant::(&123); @@ -283,7 +283,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:173:29 | LL | discriminant::(&123); @@ -300,7 +300,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:177:29 | LL | discriminant::(&123); @@ -317,7 +317,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant::(&123); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:182:25 | LL | discriminant::(&123); @@ -334,7 +334,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:184:61 | LL | [#[deny(enum_intrinsics_non_enums)] discriminant::(&123)]; @@ -351,7 +351,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:185:61 | LL | (#[deny(enum_intrinsics_non_enums)] discriminant::(&123),); @@ -368,7 +368,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:187:65 | LL | call(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); @@ -385,7 +385,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum --> $DIR/lint-attr-everywhere-late.rs:189:72 | LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); diff --git a/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr b/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr index 63ed2503cf39f..f9eeaebe21f43 100644 --- a/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr +++ b/tests/ui/lint/lint-enum-intrinsics-non-enums.stderr @@ -4,7 +4,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&()); | ^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:26:18 | LL | discriminant(&()); @@ -17,7 +17,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&&SomeEnum::B); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:29:18 | LL | discriminant(&&SomeEnum::B); @@ -29,7 +29,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:32:18 | LL | discriminant(&SomeStruct); @@ -41,7 +41,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&123u32); | ^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:35:18 | LL | discriminant(&123u32); @@ -53,7 +53,7 @@ error: the return value of `mem::discriminant` is unspecified when called with a LL | discriminant(&&123i8); | ^^^^^^^^^^^^^^^^^^^^^ | -note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum. +note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum --> $DIR/lint-enum-intrinsics-non-enums.rs:38:18 | LL | discriminant(&&123i8); @@ -65,7 +65,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<&str>(); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:49:5 @@ -73,7 +73,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<*const u8>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:52:5 @@ -81,7 +81,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<()>(); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum error: the return value of `mem::variant_count` is unspecified when called with a non-enum type --> $DIR/lint-enum-intrinsics-non-enums.rs:55:5 @@ -89,7 +89,7 @@ error: the return value of `mem::variant_count` is unspecified when called with LL | variant_count::<&SomeEnum>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum. + = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum error: aborting due to 9 previous errors diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr index f2bc8bd8400ce..7cd6175a5ad6a 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr @@ -4,7 +4,7 @@ warning: unnecessary associated type bound for not object safe associated type LL | fn foo(_: &dyn Foo) {} | ^^^^^^^^ help: remove this bound | - = note: this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` = note: `#[warn(unused_associated_type_bounds)]` on by default warning: 1 warning emitted diff --git a/tests/ui/parser/issues/issue-8537.stderr b/tests/ui/parser/issues/issue-8537.stderr index 0d636bd28a50b..b685464d8d4fb 100644 --- a/tests/ui/parser/issues/issue-8537.stderr +++ b/tests/ui/parser/issues/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/abi-typo.stderr b/tests/ui/suggestions/abi-typo.stderr index ea474e3212532..5195c43220b41 100644 --- a/tests/ui/suggestions/abi-typo.stderr +++ b/tests/ui/suggestions/abi-typo.stderr @@ -7,7 +7,7 @@ LL | extern "cdedl" fn cdedl() {} | invalid ABI | help: did you mean: `"cdecl"` | - = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions. + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: aborting due to 1 previous error diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.stderr b/tests/ui/tool-attributes/duplicate-diagnostic.stderr index 26bd6a82e3417..3cd438004c8e2 100644 --- a/tests/ui/tool-attributes/duplicate-diagnostic.stderr +++ b/tests/ui/tool-attributes/duplicate-diagnostic.stderr @@ -1,14 +1,14 @@ -error: duplicate diagnostic item in crate `p2`: `Foo`. +error: duplicate diagnostic item in crate `p2`: `Foo` | - = note: the diagnostic item is first defined in crate `p1`. + = note: the diagnostic item is first defined in crate `p1` -error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`. +error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo` --> $DIR/duplicate-diagnostic.rs:12:1 | LL | pub struct Foo {} | ^^^^^^^^^^^^^^ | - = note: the diagnostic item is first defined in crate `p2`. + = note: the diagnostic item is first defined in crate `p2` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trait-or-new-type-instead.stderr b/tests/ui/traits/trait-or-new-type-instead.stderr index 17ee939887864..5f5aa3ac56982 100644 --- a/tests/ui/traits/trait-or-new-type-instead.stderr +++ b/tests/ui/traits/trait-or-new-type-instead.stderr @@ -2,7 +2,7 @@ error[E0116]: cannot define inherent `impl` for a type outside of the crate wher --> $DIR/trait-or-new-type-instead.rs:1:1 | LL | impl Option { - | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate. + | ^^^^^^^^^^^^^^^^^ impl for type defined outside of crate | = note: define and implement a trait or new type instead