diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a3d72..684877cae7677 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + #[inline(always)] + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + + #[inline(always)] + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799fa95..9b9919fcc2a3d 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -436,24 +436,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type AllocExtra = (); type FrameExtra = (); - #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - #[inline(always)] fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { // We do not support `force_int`. false } - #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - #[inline(always)] fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f6717721fb5a..f1b1855c3ec74 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's + // still correct to not use `ctfe_mode`: that mode is for validation of the final constant + // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking + // recurse through references which, for now, we don't want here, either. self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 61d953cd6f1cc..753e2f07c042e 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -273,40 +273,58 @@ pub trait Emitter { DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), }; - let bundle = match self.fluent_bundle() { - Some(bundle) if bundle.has_message(&identifier) => bundle, - _ => self.fallback_fluent_bundle(), - }; + let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> { + let message = bundle.get_message(&identifier)?; + let value = match attr { + Some(attr) => message.get_attribute(attr)?.value(), + None => message.value()?, + }; + debug!(?message, ?value); - let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle"); - let value = match attr { - Some(attr) => { - if let Some(attr) = message.get_attribute(attr) { - attr.value() - } else { - panic!("missing attribute `{attr}` in fluent message `{identifier}`") - } - } - None => { - if let Some(value) = message.value() { - value - } else { - panic!("missing value in fluent message `{identifier}`") - } - } + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(&args), &mut errs); + debug!(?translated, ?errs); + Some((translated, errs)) }; - let mut err = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut err); - trace!(?translated, ?err); - debug_assert!( - err.is_empty(), - "identifier: {:?}, args: {:?}, errors: {:?}", - identifier, - args, - err - ); - translated + self.fluent_bundle() + .and_then(|bundle| translate_with_bundle(bundle)) + // If `translate_with_bundle` returns `None` with the primary bundle, this is likely + // just that the primary bundle doesn't contain the message being translated, so + // proceed to the fallback bundle. + // + // However, when errors are produced from translation, then that means the translation + // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided). + // + // In debug builds, assert so that compiler devs can spot the broken translation and + // fix it.. + .inspect(|(_, errs)| { + debug_assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + }) + // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so + // just hide it and try with the fallback bundle. + .filter(|(_, errs)| errs.is_empty()) + .or_else(|| translate_with_bundle(self.fallback_fluent_bundle())) + .map(|(translated, errs)| { + // Always bail out for errors with the fallback bundle. + assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + translated + }) + .expect("failed to find message in primary or fallback fluent bundles") } /// Formats the substitutions of the primary_span diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 15c1858023de7..f83e972efd56e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,9 +6,10 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] +#![feature(adt_const_params)] #![feature(let_else)] #![feature(never_type)] -#![feature(adt_const_params)] +#![feature(result_option_inspect)] #![feature(rustc_attrs)] #![allow(incomplete_features)] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 98016659a05f7..1c087b93b4965 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; + #[inline(always)] + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, _instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 72c23776d3399..197c038489835 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -68,7 +68,12 @@ impl<'a> Parser<'a> { if !self.maybe_consume_incorrect_semicolon(&items) { let msg = &format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected item"); + let label = if self.is_kw_followed_by_ident(kw::Let) { + "consider using `const` or `static` instead of `let` for global variables" + } else { + "expected item" + }; + err.span_label(self.token.span, label); return Err(err); } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c208de7..0032dd7d113f8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1310,6 +1310,8 @@ options! { "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 758f1ef97664f..1e6cb53f3eeae 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -44,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{ }; use rustc_trait_selection::traits::wf::object_region_bounds; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; use std::slice; @@ -368,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.intern_substs(&[]), arg_count); } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec, inferred_params: Vec, infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - } } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -500,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); - tcx.ty_error().into() - } else { - // This is a default type parameter. - let substs = substs.unwrap(); - if substs.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { - // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error().into(); - } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) - .into() + let substs = substs.unwrap(); + if substs.iter().any(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.references_error(), + _ => false, + }) { + // Avoid ICE #86756 when type error recovery goes awry. + return tcx.ty_error().into(); } + self.astconv + .normalize_ty( + self.span, + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), + ) + .into() } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() + self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() @@ -564,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, span, generic_args, - missing_type_params: vec![], inferred_params: vec![], infer_args, - is_object, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -579,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - debug!( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", generics, self_ty, substs @@ -1490,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { + debug!(?ty); + if ty == dummy_self { + let param = &generics.params[index]; + missing_type_params.push(param.name); + tcx.ty_error().into() + } else if ty.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + tcx.ty_error().into() + } else { + arg + } + } else { + arg + } + }) + .collect(); + let substs = tcx.intern_substs(&substs[..]); + + let span = i.bottom().1; + let empty_generic_args = trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_kind(def_id).descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), ); + err.emit(); } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { if b.projection_ty.self_ty() != dummy_self { diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 887246c600144..6756eecd0e0f8 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -74,7 +74,7 @@ use crate::ptr; /// { /// return null_mut(); /// }; -/// (self.arena.get() as *mut u8).add(allocated) +/// self.arena.get().cast::().add(allocated) /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 372141e0933f5..7ec565edb3483 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -119,6 +119,10 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// + /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying + /// destination encounters some error preventing it from accepting more text; it should + /// generally be propagated rather than handled, at least when implementing formatting traits. + /// /// # Examples /// /// ``` diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index c0f609a01b5c8..c25b159c533a1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1267,20 +1267,21 @@ impl *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7])); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 7059d0008c4c4..fff06b458c7c1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1545,20 +1545,23 @@ impl *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let mut x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr(); /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// *u16_ptr = 0; + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index f1e659309674c..f43b780ec9a90 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(slice.len()) as *const T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803ecdb..d874f08317f61 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x const fn unaligned_ptr() -> *const u16 { // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } + unsafe { DATA.as_ptr().byte_add(1) } } #[test] @@ -67,7 +67,7 @@ fn write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); } two_aligned @@ -91,7 +91,7 @@ fn mut_ptr_write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); } two_aligned diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db94368f6e0cc..df9b1073a0994 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_pointer_byte_offsets)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] @@ -74,6 +75,7 @@ #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(result_into_ok_or_err)] +#![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index ea24fedd0eb3d..66fa1efbf103f 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -115,7 +115,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) }; + let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); diff --git a/library/std/src/sys/unsupported/alloc.rs b/library/std/src/sys/unsupported/alloc.rs index 8d5d0a2f5ccd1..d715ae45401e6 100644 --- a/library/std/src/sys/unsupported/alloc.rs +++ b/library/std/src/sys/unsupported/alloc.rs @@ -1,15 +1,16 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr::null_mut; #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] @@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 { - 0 as *mut u8 + null_mut() } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 44c8a50fd860a..479669647c128 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut; use crate::str; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::mutex; use crate::sys_common::thread; use crate::sys_common::thread_info; use crate::sys_common::thread_parker::Parker; @@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // It is UB to attempt to acquire this mutex reentrantly! - static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); - static mut COUNTER: u64 = 1; - - unsafe { - let guard = GUARD.lock(); - - // If we somehow use up all our bits, panic so that we're not - // covering up subtle bugs of IDs being reused. - if COUNTER == u64::MAX { - drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. - panic!("failed to generate unique thread ID: bitspace exhausted"); - } - - let id = COUNTER; - COUNTER += 1; + #[cold] + fn exhausted() -> ! { + panic!("failed to generate unique thread ID: bitspace exhausted") + } - ThreadId(NonZeroU64::new(id).unwrap()) + cfg_if::cfg_if! { + if #[cfg(target_has_atomic = "64")] { + use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + + static COUNTER: AtomicU64 = AtomicU64::new(0); + + let mut last = COUNTER.load(Relaxed); + loop { + let Some(id) = last.checked_add(1) else { + exhausted(); + }; + + match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()), + Err(id) => last = id, + } + } + } else { + use crate::sys_common::mutex::StaticMutex; + + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: StaticMutex = StaticMutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + let guard = GUARD.lock(); + + let Some(id) = COUNTER.checked_add(1) else { + drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. + exhausted(); + }; + + COUNTER = id; + drop(guard); + ThreadId(NonZeroU64::new(id).unwrap()) + } + } } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 5a6720a8dd956..27ccff9a2768f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -163,7 +163,6 @@ enum Class { // Keywords that do pointer/reference stuff. RefKeyWord, Self_(Span), - Op, Macro(Span), MacroNonTerminal, String, @@ -187,7 +186,6 @@ impl Class { Class::KeyWord => "kw", Class::RefKeyWord => "kw-2", Class::Self_(_) => "self", - Class::Op => "op", Class::Macro(_) => "macro", Class::MacroNonTerminal => "macro-nonterminal", Class::String => "string", @@ -212,7 +210,6 @@ impl Class { | Self::Attribute | Self::KeyWord | Self::RefKeyWord - | Self::Op | Self::MacroNonTerminal | Self::String | Self::Number @@ -516,7 +513,7 @@ impl<'a> Classifier<'a> { // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. TokenKind::Star => match self.tokens.peek() { - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }); @@ -532,15 +529,15 @@ impl<'a> Classifier<'a> { TokenKind::And => match self.tokens.peek() { Some((TokenKind::And, _)) => { self.next(); - sink(Highlight::Token { text: "&&", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&&", class: None }); return; } Some((TokenKind::Eq, _)) => { self.next(); - sink(Highlight::Token { text: "&=", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&=", class: None }); return; } - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }); @@ -553,7 +550,7 @@ impl<'a> Classifier<'a> { TokenKind::Eq => match lookahead { Some(TokenKind::Eq) => { self.next(); - sink(Highlight::Token { text: "==", class: Some(Class::Op) }); + sink(Highlight::Token { text: "==", class: None }); return; } Some(TokenKind::Gt) => { @@ -561,7 +558,7 @@ impl<'a> Classifier<'a> { sink(Highlight::Token { text: "=>", class: None }); return; } - _ => Class::Op, + _ => return no_highlight(sink), }, TokenKind::Minus if lookahead == Some(TokenKind::Gt) => { self.next(); @@ -578,7 +575,7 @@ impl<'a> Classifier<'a> { | TokenKind::Percent | TokenKind::Bang | TokenKind::Lt - | TokenKind::Gt => Class::Op, + | TokenKind::Gt => return no_highlight(sink), // Miscellaneous, no highlighting. TokenKind::Dot diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html index 45f567880c9d9..ae4dba116d637 100644 --- a/src/librustdoc/html/highlight/fixtures/decorations.html +++ b/src/librustdoc/html/highlight/fixtures/decorations.html @@ -1,2 +1,2 @@ -let x = 1; -let y = 2; \ No newline at end of file +let x = 1; +let y = 2; \ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html index abc2db1790c53..17f23278ec1f2 100644 --- a/src/librustdoc/html/highlight/fixtures/highlight.html +++ b/src/librustdoc/html/highlight/fixtures/highlight.html @@ -1,4 +1,4 @@ use crate::a::foo; use self::whatever; -let x = super::b::foo; -let y = Self::whatever; \ No newline at end of file +let x = super::b::foo; +let y = Self::whatever; \ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index b117a12e39f4a..ea797fd99d3f4 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -8,23 +8,23 @@ .lifetime { color: #B76514; } .question-mark { color: #ff9011; } -
#![crate_type = "lib"]
+
#![crate_type = "lib"]
 
 use std::path::{Path, PathBuf};
 
-#[cfg(target_os = "linux")]
+#[cfg(target_os = "linux")]
 fn main() -> () {
-    let foo = true && false || true;
-    let _: *const () = 0;
-    let _ = &foo;
-    let _ = &&foo;
-    let _ = *foo;
+    let foo = true && false || true;
+    let _: *const () = 0;
+    let _ = &foo;
+    let _ = &&foo;
+    let _ = *foo;
     mac!(foo, &mut bar);
-    assert!(self.length < N && index <= self.length);
+    assert!(self.length < N && index <= self.length);
     ::std::env::var("gateau").is_ok();
     #[rustfmt::skip]
-    let s:std::path::PathBuf = std::path::PathBuf::new();
-    let mut s = String::new();
+    let s:std::path::PathBuf = std::path::PathBuf::new();
+    let mut s = String::new();
 
     match &s {
         ref mut x => {}
diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html
index c0acf31a05d08..ac8bd28f6c362 100644
--- a/src/librustdoc/html/highlight/fixtures/union.html
+++ b/src/librustdoc/html/highlight/fixtures/union.html
@@ -4,5 +4,5 @@
 }
 
 fn main() {
-    let union = 0;
+    let union = 0;
 }
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 39a4dae3348c1..b8218867a8bc8 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -238,7 +238,7 @@ details.rustdoc-toggle > summary::before {
 pre.rust .number, pre.rust .string { color: #b8cc52; }
 pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
 pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .op, pre.rust .lifetime { color: #ff7733; }
+pre.rust .lifetime { color: #ff7733; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
 pre.rust .question-mark {
 	color: #ff9011;
@@ -250,7 +250,7 @@ pre.rust .self {
 pre.rust .attribute {
 	color: #e6e1cf;
 }
-pre.rust .attribute .ident, pre.rust .attribute .op {
+pre.rust .attribute .ident {
 	color: #e6e1cf;
 }
 
diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile
index bfff75e7acb08..20e86c7f9a072 100644
--- a/src/test/run-make/translation/Makefile
+++ b/src/test/run-make/translation/Makefile
@@ -9,16 +9,29 @@ FAKEROOT=$(TMPDIR)/fakeroot
 
 all: normal custom sysroot
 
-normal: basic-translation.rs
+# Check that the test works normally, using the built-in fallback bundle.
+normal: test.rs
 	$(RUSTC) $< 2>&1 | grep "struct literal body without path"
 
-custom: basic-translation.rs basic-translation.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message"
+# Check that a primary bundle can be loaded and will be preferentially used
+# where possible.
+custom: test.rs working.ftl
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | grep "this is a test message"
+
+# Check that a primary bundle with a broken message (e.g. a interpolated
+# variable is missing) will use the fallback bundle.
+missing: test.rs missing.ftl
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | grep "struct literal body without path"
+
+# Check that a primary bundle without the desired message will use the fallback
+# bundle.
+broken: test.rs broken.ftl
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | grep "struct literal body without path"
 
 # Check that a locale can be loaded from the sysroot given a language
 # identifier by making a local copy of the sysroot and adding the custom locale
 # to it.
-sysroot: basic-translation.rs basic-translation.ftl
+sysroot: test.rs working.ftl
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
 	rm -f $(FAKEROOT)/lib
@@ -31,7 +44,7 @@ sysroot: basic-translation.rs basic-translation.ftl
 	mkdir $(FAKEROOT)/lib/rustlib/src
 	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
 	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
-	ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
+	ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
 	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message"
 
 # Check that the compiler errors out when the sysroot requested cannot be
@@ -43,7 +56,7 @@ sysroot-missing:
 # Check that the compiler errors out when the sysroot requested cannot be
 # found. This test might start failing if there actually exists a Klingon
 # translation of rustc's error messages.
-sysroot-invalid: basic-translation.rs basic-translation.ftl
+sysroot-invalid: test.rs working.ftl
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
 	rm -f $(FAKEROOT)/lib
diff --git a/src/test/run-make/translation/broken.ftl b/src/test/run-make/translation/broken.ftl
new file mode 100644
index 0000000000000..1482dd2824aed
--- /dev/null
+++ b/src/test/run-make/translation/broken.ftl
@@ -0,0 +1,3 @@
+# `foo` isn't provided by this diagnostic so it is expected that the fallback message is used.
+parser-struct-literal-body-without-path = this is a {$foo} message
+    .suggestion = this is a test suggestion
diff --git a/src/test/run-make/translation/missing.ftl b/src/test/run-make/translation/missing.ftl
new file mode 100644
index 0000000000000..43076b1d6ae79
--- /dev/null
+++ b/src/test/run-make/translation/missing.ftl
@@ -0,0 +1,3 @@
+# `parser-struct-literal-body-without-path` isn't provided by this resource at all, so the
+# fallback should be used.
+foo = bar
diff --git a/src/test/run-make/translation/basic-translation.rs b/src/test/run-make/translation/test.rs
similarity index 100%
rename from src/test/run-make/translation/basic-translation.rs
rename to src/test/run-make/translation/test.rs
diff --git a/src/test/run-make/translation/basic-translation.ftl b/src/test/run-make/translation/working.ftl
similarity index 100%
rename from src/test/run-make/translation/basic-translation.ftl
rename to src/test/run-make/translation/working.ftl
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 6dc41231559c0..236469ce9797a 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -38,6 +38,7 @@
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
     -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
+    -Z                   extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate
diff --git a/src/test/rustdoc/macro_rules-matchers.rs b/src/test/rustdoc/macro_rules-matchers.rs
index efc3b21e6da99..131c53ec24bc4 100644
--- a/src/test/rustdoc/macro_rules-matchers.rs
+++ b/src/test/rustdoc/macro_rules-matchers.rs
@@ -6,16 +6,13 @@
 // @has 'foo/macro.todo.html'
 // @has - '//span[@class="macro"]' 'macro_rules!'
 // @has - '//span[@class="ident"]' 'todo'
-// Note: the only op is the `+`
-// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1
 
 // @has - '{ () => { ... }; ($('
 // @has - '//span[@class="macro-nonterminal"]' '$'
 // @has - '//span[@class="macro-nonterminal"]' 'arg'
 // @has - ':'
 // @has - '//span[@class="ident"]' 'tt'
-// @has - '),'
-// @has - '//span[@class="op"]' '+'
+// @has - ')+'
 // @has - ') => { ... }; }'
 pub use std::todo;
 
diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr
index 700923c1b3f58..2b88cf0b4411e 100644
--- a/src/test/ui/associated-types/issue-22560.stderr
+++ b/src/test/ui/associated-types/issue-22560.stderr
@@ -1,25 +1,3 @@
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:23
-   |
-LL | trait Sub {
-   | ------------------- type parameter `Rhs` must be specified for this
-...
-LL | type Test = dyn Add + Sub;
-   |                       ^^^ help: set the type parameter to the desired type: `Sub`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:17
-   |
-LL | trait Add {
-   | ------------------- type parameter `Rhs` must be specified for this
-...
-LL | type Test = dyn Add + Sub;
-   |                 ^^^ help: set the type parameter to the desired type: `Add`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/issue-22560.rs:9:23
    |
@@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub;
    |                 |
    |                 first non-auto trait
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit 
 
 error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
@@ -50,6 +28,28 @@ help: specify the associated types
 LL | type Test = dyn Add + Sub;
    |                 ~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~
 
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:17
+   |
+LL | trait Add {
+   | ------------------- type parameter `Rhs` must be specified for this
+...
+LL | type Test = dyn Add + Sub;
+   |                 ^^^ help: set the type parameter to the desired type: `Add`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:23
+   |
+LL | trait Sub {
+   | ------------------- type parameter `Rhs` must be specified for this
+...
+LL | type Test = dyn Add + Sub;
+   |                       ^^^ help: set the type parameter to the desired type: `Sub`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0191, E0225, E0393.
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
new file mode 100644
index 0000000000000..97c9e1505197f
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
@@ -0,0 +1,45 @@
+// revisions: no_flag with_flag
+// [no_flag] check-pass
+// [with_flag] compile-flags: -Zextra-const-ub-checks
+#![feature(const_ptr_read)]
+
+use std::mem::transmute;
+
+const INVALID_BOOL: () = unsafe {
+    let _x: bool = transmute(3u8);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const INVALID_PTR_IN_INT: () = unsafe {
+    let _x: usize = transmute(&3u8);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
+    let x: &[u8] = &[0; 32];
+    let _x: (usize, usize) = transmute(x);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const UNALIGNED_PTR: () = unsafe {
+    let _x: &u32 = transmute(&[0u8; 4]);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const UNALIGNED_READ: () = {
+    INNER; //[with_flag]~ERROR any use of this value will cause an error
+    //[with_flag]~| previously accepted
+    // There is an error here but its span is in the standard library so we cannot match it...
+    // so we have this in a *nested* const, such that the *outer* const fails to use it.
+    const INNER: () = unsafe {
+        let x = &[0u8; 4];
+        let ptr = x.as_ptr().cast::();
+        ptr.read();
+    };
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
new file mode 100644
index 0000000000000..1706db7ac43ca
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
@@ -0,0 +1,71 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:9:20
+   |
+LL |     let _x: bool = transmute(3u8);
+   |                    ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:15:21
+   |
+LL |     let _x: usize = transmute(&3u8);
+   |                     ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:22:30
+   |
+LL |     let _x: (usize, usize) = transmute(x);
+   |                              ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:28:20
+   |
+LL |     let _x: &u32 = transmute(&[0u8; 4]);
+   |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         accessing memory with alignment 1, but alignment 4 is required
+   |         inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { read(self) }
+   |                  ---------- inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/detect-extra-ub.rs:41:9
+   |
+LL |         ptr.read();
+   |         ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9
+
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:34:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:34:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 
+
diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
index b2edc1a1f66ca..6175b7df1107a 100644
--- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
+++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
@@ -3,7 +3,6 @@
 
 trait Foo> {
     //~^ ERROR cycle detected
-    //~| ERROR cycle detected
 }
 
 fn main() { }
diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
index d4976a0f9c9cd..9d715f4947146 100644
--- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
+++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
@@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module
    |
 LL | / trait Foo> {
 LL | |
-LL | |
-LL | | }
-LL | |
-LL | | fn main() { }
-   | |_____________^
-
-error[E0391]: cycle detected when computing type of `Foo::X`
-  --> $DIR/cycle-trait-default-type-trait.rs:4:23
-   |
-LL | trait Foo> {
-   |                       ^^^
-   |
-   = note: ...which immediately requires computing type of `Foo::X` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/cycle-trait-default-type-trait.rs:4:1
-   |
-LL | / trait Foo> {
-LL | |
-LL | |
 LL | | }
 LL | |
 LL | | fn main() { }
    | |_____________^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr
index 4909398bb848f..731615a6bd8d4 100644
--- a/src/test/ui/issues/issue-21950.stderr
+++ b/src/test/ui/issues/issue-21950.stderr
@@ -1,3 +1,12 @@
+error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
+  --> $DIR/issue-21950.rs:10:25
+   |
+LL |     type Output;
+   |     ----------- `Output` defined here
+...
+LL |     let x = &10 as &dyn Add;
+   |                         ^^^ help: specify the associated type: `Add`
+
 error[E0393]: the type parameter `Rhs` must be explicitly specified
   --> $DIR/issue-21950.rs:10:25
    |
@@ -9,15 +18,6 @@ LL |     let x = &10 as &dyn Add;
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
-error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
-  --> $DIR/issue-21950.rs:10:25
-   |
-LL |     type Output;
-   |     ----------- `Output` defined here
-...
-LL |     let x = &10 as &dyn Add;
-   |                         ^^^ help: specify the associated type: `Add`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0191, E0393.
diff --git a/src/test/ui/let-else/issue-94176.rs b/src/test/ui/let-else/issue-94176.rs
new file mode 100644
index 0000000000000..e35bbd8883062
--- /dev/null
+++ b/src/test/ui/let-else/issue-94176.rs
@@ -0,0 +1,10 @@
+// Issue #94176: wrong span for the error message of a mismatched type error,
+// if the function uses a `let else` construct.
+#![feature(let_else)]
+
+pub fn test(a: Option) -> Option { //~ ERROR mismatched types
+    let Some(_) = a else { return None; };
+    println!("Foo");
+}
+
+fn main() {}
diff --git a/src/test/ui/let-else/issue-94176.stderr b/src/test/ui/let-else/issue-94176.stderr
new file mode 100644
index 0000000000000..0cb97aceebfd5
--- /dev/null
+++ b/src/test/ui/let-else/issue-94176.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-94176.rs:5:32
+   |
+LL | pub fn test(a: Option) -> Option {
+   |        ----                    ^^^^^^^^^^^ expected enum `Option`, found `()`
+   |        |
+   |        implicitly returns `()` as its body has no tail or `return` expression
+   |
+   = note:   expected enum `Option`
+           found unit type `()`
+help: consider returning the local binding `a`
+   |
+LL ~     println!("Foo");
+LL +     a
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-then-diverge.rs b/src/test/ui/let-else/let-else-then-diverge.rs
new file mode 100644
index 0000000000000..49633d943beea
--- /dev/null
+++ b/src/test/ui/let-else/let-else-then-diverge.rs
@@ -0,0 +1,19 @@
+//
+// popped up in in #94012, where an alternative desugaring was
+// causing unreachable code errors
+
+#![feature(let_else)]
+#![deny(unused_variables)]
+#![deny(unreachable_code)]
+
+fn let_else_diverge() -> bool {
+    let Some(_) = Some("test") else {
+        let x = 5; //~ ERROR unused variable: `x`
+        return false;
+    };
+    return true;
+}
+
+fn main() {
+    let_else_diverge();
+}
diff --git a/src/test/ui/let-else/let-else-then-diverge.stderr b/src/test/ui/let-else/let-else-then-diverge.stderr
new file mode 100644
index 0000000000000..ceb61029d3863
--- /dev/null
+++ b/src/test/ui/let-else/let-else-then-diverge.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `x`
+  --> $DIR/let-else-then-diverge.rs:11:13
+   |
+LL |         let x = 5;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_x`
+   |
+note: the lint level is defined here
+  --> $DIR/let-else-then-diverge.rs:6:9
+   |
+LL | #![deny(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/suggest-const-for-global-var.rs b/src/test/ui/parser/suggest-const-for-global-var.rs
new file mode 100644
index 0000000000000..d6216cb7ac275
--- /dev/null
+++ b/src/test/ui/parser/suggest-const-for-global-var.rs
@@ -0,0 +1,6 @@
+let X: i32 = 12;
+//~^ ERROR expected item, found keyword `let`
+
+fn main() {
+    println!("{}", X);
+}
diff --git a/src/test/ui/parser/suggest-const-for-global-var.stderr b/src/test/ui/parser/suggest-const-for-global-var.stderr
new file mode 100644
index 0000000000000..94e44ec7f6ce1
--- /dev/null
+++ b/src/test/ui/parser/suggest-const-for-global-var.stderr
@@ -0,0 +1,8 @@
+error: expected item, found keyword `let`
+  --> $DIR/suggest-const-for-global-var.rs:1:1
+   |
+LL | let X: i32 = 12;
+   | ^^^ consider using `const` or `static` instead of `let` for global variables
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.rs b/src/test/ui/traits/alias/generic-default-in-dyn.rs
new file mode 100644
index 0000000000000..d44e1c2a97530
--- /dev/null
+++ b/src/test/ui/traits/alias/generic-default-in-dyn.rs
@@ -0,0 +1,10 @@
+trait SendEqAlias = PartialEq;
+//~^ ERROR trait aliases are experimental
+
+struct Foo(dyn SendEqAlias);
+//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+
+struct Bar(dyn SendEqAlias, T);
+//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.stderr b/src/test/ui/traits/alias/generic-default-in-dyn.stderr
new file mode 100644
index 0000000000000..76a068e864a3c
--- /dev/null
+++ b/src/test/ui/traits/alias/generic-default-in-dyn.stderr
@@ -0,0 +1,39 @@
+error[E0658]: trait aliases are experimental
+  --> $DIR/generic-default-in-dyn.rs:1:1
+   |
+LL | trait SendEqAlias = PartialEq;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #41517  for more information
+   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/generic-default-in-dyn.rs:4:19
+   |
+LL | struct Foo(dyn SendEqAlias);
+   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
+   |
+  ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub trait PartialEq {
+   | --------------------------------------- type parameter `Rhs` must be specified for this
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/generic-default-in-dyn.rs:7:19
+   |
+LL | struct Bar(dyn SendEqAlias, T);
+   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
+   |
+  ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub trait PartialEq {
+   | --------------------------------------- type parameter `Rhs` must be specified for this
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0393, E0658.
+For more information about an error, try `rustc --explain E0393`.
diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs
new file mode 100644
index 0000000000000..6b99431f5bbcf
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-generics.rs
@@ -0,0 +1,8 @@
+#![feature(trait_alias)]
+
+pub trait SelfInput = Fn(&mut Self);
+
+pub fn f(_f: &dyn SelfInput) {}
+//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038]
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr
new file mode 100644
index 0000000000000..a1056872ea641
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-generics.stderr
@@ -0,0 +1,11 @@
+error[E0038]: the trait alias `SelfInput` cannot be made into an object
+  --> $DIR/self-in-generics.rs:5:19
+   |
+LL | pub fn f(_f: &dyn SelfInput) {}
+   |                   ^^^^^^^^^
+   |
+   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/unspecified-self-in-trait-ref.rs b/src/test/ui/traits/unspecified-self-in-trait-ref.rs
similarity index 100%
rename from src/test/ui/unspecified-self-in-trait-ref.rs
rename to src/test/ui/traits/unspecified-self-in-trait-ref.rs
diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr
similarity index 100%
rename from src/test/ui/unspecified-self-in-trait-ref.stderr
rename to src/test/ui/traits/unspecified-self-in-trait-ref.stderr