diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 756a2226753f6..e8076ce77abcf 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -402,9 +402,13 @@ pub(crate) fn codegen_terminator_call<'tcx>( if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { - let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)); - fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + let caller_def = fx.instance.def_id(); + let e = CompilerBuiltinsCannotCall { + span: fx.tcx.def_span(caller_def), + caller: with_no_trimmed_paths!(fx.tcx.def_path_str(caller_def)), + callee: with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)), + }; + fx.tcx.dcx().emit_err(e); } else { fx.bcx.ins().trap(TrapCode::user(2).unwrap()); return; diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 3ddbe4aeeec5d..5e25de02a77f2 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1180,6 +1180,8 @@ pub(crate) struct ErrorCreatingRemarkDir { pub struct CompilerBuiltinsCannotCall { pub caller: String, pub callee: String, + #[primary_span] + pub span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1e52c6394635b..e2a9b540d3060 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -165,9 +165,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some(instance) = instance { if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) { if destination.is_some() { - let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())); - tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + let caller_def = fx.instance.def_id(); + let e = CompilerBuiltinsCannotCall { + span: tcx.def_span(caller_def), + caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)), + callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())), + }; + tcx.dcx().emit_err(e); } else { info!( "compiler_builtins call to diverging function {:?} replaced with abort", diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index ba28720afecdd..0758e5d045673 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,7 +3,7 @@ use std::iter; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::{UnwindTerminateReason, traversal}; +use rustc_middle::mir::{Local, UnwindTerminateReason, traversal}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; @@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let local_values = { let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals); - let mut allocate_local = |local| { + let mut allocate_local = |local: Local| { let decl = &mir.local_decls[local]; let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 1654867739f0d..b38b09d60ebf0 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -147,7 +147,7 @@ impl FromIterator<(K, V)> for SortedIndexMultiMap { where J: IntoIterator, { - let items = IndexVec::from_iter(iter); + let items = IndexVec::::from_iter(iter); let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect(); // `sort_by_key` is stable, so insertion order is preserved for duplicate items. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index 358bc389bd138..f6298adf2ebb7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -22,6 +22,12 @@ impl ExpectedIdx { } } +impl ProvidedIdx { + pub(crate) fn to_expected_idx(self) -> ExpectedIdx { + ExpectedIdx::from_u32(self.as_u32()) + } +} + // An issue that might be found in the compatibility matrix #[derive(Debug)] enum Issue { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 120a43576e814..edd740d8d8f24 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -775,7 +775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First, check if we just need to wrap some arguments in a tuple. if let Some((mismatch_idx, terr)) = - compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { + compatibility_diagonal.iter_enumerated().find_map(|(i, c)| { if let Compatibility::Incompatible(Some(terr)) = c { Some((i, *terr)) } else { @@ -787,24 +787,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Do we have as many extra provided arguments as the tuple's length? // If so, we might have just forgotten to wrap some args in a tuple. if let Some(ty::Tuple(tys)) = - formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) + formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind()) // If the tuple is unit, we're not actually wrapping any arguments. && !tys.is_empty() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() { // Wrap up the N provided arguments starting at this position in a tuple. - let provided_as_tuple = Ty::new_tup_from_iter( - tcx, - provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), - ); + let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..]; + let (provided_args_to_tuple, provided_args_after_tuple) = + provided_args_to_tuple.split_at(tys.len()); + let provided_as_tuple = + Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty)); let mut satisfied = true; // Check if the newly wrapped tuple + rest of the arguments are compatible. for ((_, expected_ty), provided_ty) in std::iter::zip( - formal_and_expected_inputs.iter().skip(mismatch_idx), - [provided_as_tuple].into_iter().chain( - provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), - ), + formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(), + [provided_as_tuple] + .into_iter() + .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)), ) { if !self.may_coerce(provided_ty, *expected_ty) { satisfied = false; @@ -816,10 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Take some care with spans, so we don't suggest wrapping a macro's // innards in parenthesis, for example. if satisfied - && let Some((_, lo)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) - && let Some((_, hi)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) + && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple { let mut err; if tys.len() == 1 { @@ -827,9 +825,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so don't do anything special here. err = self.err_ctxt().report_and_explain_type_error( mk_trace( - *lo, - formal_and_expected_inputs[mismatch_idx.into()], - provided_arg_tys[mismatch_idx.into()].0, + lo, + formal_and_expected_inputs[mismatch_idx.to_expected_idx()], + provided_arg_tys[mismatch_idx].0, ), self.param_env, terr, @@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_ty, call_expr, None, - Some(mismatch_idx), + Some(mismatch_idx.as_usize()), &matched_inputs, &formal_and_expected_inputs, is_method, @@ -2615,7 +2613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .resolve_vars_if_possible(formal_and_expected_inputs[idx].1) .sort_string(self.tcx); let label = if idxs_matched == params_with_generics.len() - 1 { format!( diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index b85160540d872..33f406e21137d 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -1,5 +1,7 @@ use std::fmt::Debug; use std::hash::Hash; +use std::ops; +use std::slice::SliceIndex; /// Represents some newtyped `usize` wrapper. /// @@ -43,3 +45,92 @@ impl Idx for u32 { self as usize } } + +/// Helper trait for indexing operations with a custom index type. +pub trait IntoSliceIdx { + type Output: SliceIndex; + fn into_slice_idx(self) -> Self::Output; +} + +impl IntoSliceIdx for I { + type Output = usize; + #[inline] + fn into_slice_idx(self) -> Self::Output { + self.index() + } +} + +impl IntoSliceIdx for ops::RangeFull { + type Output = ops::RangeFull; + #[inline] + fn into_slice_idx(self) -> Self::Output { + self + } +} + +impl IntoSliceIdx for ops::Range { + type Output = ops::Range; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::Range { start: self.start.index(), end: self.end.index() } + } +} + +impl IntoSliceIdx for ops::RangeFrom { + type Output = ops::RangeFrom; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::RangeFrom { start: self.start.index() } + } +} + +impl IntoSliceIdx for ops::RangeTo { + type Output = ops::RangeTo; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ..self.end.index() + } +} + +impl IntoSliceIdx for ops::RangeInclusive { + type Output = ops::RangeInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::RangeInclusive::new(self.start().index(), self.end().index()) + } +} + +impl IntoSliceIdx for ops::RangeToInclusive { + type Output = ops::RangeToInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ..=self.end.index() + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::Range { + type Output = core::range::Range; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::Range { start: self.start.index(), end: self.end.index() } + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::RangeFrom { + type Output = core::range::RangeFrom; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeFrom { start: self.start.index() } + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::RangeInclusive { + type Output = core::range::RangeInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } + } +} diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index cae55230b0679..3441a5f65c785 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,6 +2,7 @@ #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))] +#![cfg_attr(feature = "nightly", feature(new_range_api))] #![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))] #![warn(unreachable_pub)] // tidy-alphabetical-end @@ -14,7 +15,7 @@ mod idx; mod slice; mod vec; -pub use idx::Idx; +pub use idx::{Idx, IntoSliceIdx}; pub use rustc_index_macros::newtype_index; pub use slice::IndexSlice; #[doc(no_inline)] diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 4636f294f13bb..f17ea9e4b59ad 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -1,8 +1,9 @@ +use std::fmt; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; -use std::{fmt, slice}; +use std::slice::{self, SliceIndex}; -use crate::{Idx, IndexVec}; +use crate::{Idx, IndexVec, IntoSliceIdx}; /// A view into contiguous `T`s, indexed by `I` rather than by `usize`. /// @@ -97,13 +98,19 @@ impl IndexSlice { } #[inline] - pub fn get(&self, index: I) -> Option<&T> { - self.raw.get(index.index()) + pub fn get>( + &self, + index: R, + ) -> Option<&>::Output> { + self.raw.get(index.into_slice_idx()) } #[inline] - pub fn get_mut(&mut self, index: I) -> Option<&mut T> { - self.raw.get_mut(index.index()) + pub fn get_mut>( + &mut self, + index: R, + ) -> Option<&mut >::Output> { + self.raw.get_mut(index.into_slice_idx()) } /// Returns mutable references to two distinct elements, `a` and `b`. @@ -184,19 +191,19 @@ impl fmt::Debug for IndexSlice { } } -impl Index for IndexSlice { - type Output = T; +impl> Index for IndexSlice { + type Output = >::Output; #[inline] - fn index(&self, index: I) -> &T { - &self.raw[index.index()] + fn index(&self, index: R) -> &Self::Output { + &self.raw[index.into_slice_idx()] } } -impl IndexMut for IndexSlice { +impl> IndexMut for IndexSlice { #[inline] - fn index_mut(&mut self, index: I) -> &mut T { - &mut self.raw[index.index()] + fn index_mut(&mut self, index: R) -> &mut Self::Output { + &mut self.raw[index.into_slice_idx()] } } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index e454a88e847fd..03c4614af139b 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -160,7 +160,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// empty region. The `expansion` phase will grow this larger. fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> { LexicalRegionResolutions { - values: IndexVec::from_fn_n( + values: IndexVec::::from_fn_n( |vid| { let vid_universe = self.var_infos[vid].universe; VarValue::Empty(vid_universe) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cf90df1b198b8..ea0bb5feb1220 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -96,6 +96,17 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { } impl MirPhase { + pub fn name(&self) -> &'static str { + match *self { + MirPhase::Built => "built", + MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", + MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", + MirPhase::Runtime(RuntimePhase::Initial) => "runtime", + MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", + MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", + } + } + /// Gets the (dialect, phase) index of the current `MirPhase`. Both numbers /// are 1-indexed. pub fn index(&self) -> (usize, usize) { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 595a5e548b011..f05a798949b7e 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -25,6 +25,26 @@ impl Statement<'_> { } impl<'tcx> StatementKind<'tcx> { + /// Returns a simple string representation of a `StatementKind` variant, independent of any + /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). + pub const fn name(&self) -> &'static str { + match self { + StatementKind::Assign(..) => "Assign", + StatementKind::FakeRead(..) => "FakeRead", + StatementKind::SetDiscriminant { .. } => "SetDiscriminant", + StatementKind::Deinit(..) => "Deinit", + StatementKind::StorageLive(..) => "StorageLive", + StatementKind::StorageDead(..) => "StorageDead", + StatementKind::Retag(..) => "Retag", + StatementKind::PlaceMention(..) => "PlaceMention", + StatementKind::AscribeUserType(..) => "AscribeUserType", + StatementKind::Coverage(..) => "Coverage", + StatementKind::Intrinsic(..) => "Intrinsic", + StatementKind::ConstEvalCounter => "ConstEvalCounter", + StatementKind::Nop => "Nop", + StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", + } + } pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { match self { StatementKind::Assign(x) => Some(x), @@ -862,3 +882,40 @@ impl<'tcx> BinOp { }) } } + +impl From for RawPtrKind { + fn from(other: Mutability) -> Self { + match other { + Mutability::Mut => RawPtrKind::Mut, + Mutability::Not => RawPtrKind::Const, + } + } +} + +impl RawPtrKind { + pub fn is_fake(self) -> bool { + match self { + RawPtrKind::Mut | RawPtrKind::Const => false, + RawPtrKind::FakeForPtrMetadata => true, + } + } + + pub fn to_mutbl_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + + // We have no type corresponding to a fake borrow, so use + // `*const` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } + + pub fn ptr_str(self) -> &'static str { + match self { + RawPtrKind::Mut => "mut", + RawPtrKind::Const => "const", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } + } +} diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index af6f0e4c55183..4f86703e95376 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -97,19 +97,6 @@ pub enum MirPhase { Runtime(RuntimePhase), } -impl MirPhase { - pub fn name(&self) -> &'static str { - match *self { - MirPhase::Built => "built", - MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", - MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", - MirPhase::Runtime(RuntimePhase::Initial) => "runtime", - MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", - MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", - } - } -} - /// See [`MirPhase::Analysis`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] @@ -206,43 +193,6 @@ pub enum RawPtrKind { FakeForPtrMetadata, } -impl From for RawPtrKind { - fn from(other: Mutability) -> Self { - match other { - Mutability::Mut => RawPtrKind::Mut, - Mutability::Not => RawPtrKind::Const, - } - } -} - -impl RawPtrKind { - pub fn is_fake(self) -> bool { - match self { - RawPtrKind::Mut | RawPtrKind::Const => false, - RawPtrKind::FakeForPtrMetadata => true, - } - } - - pub fn to_mutbl_lossy(self) -> Mutability { - match self { - RawPtrKind::Mut => Mutability::Mut, - RawPtrKind::Const => Mutability::Not, - - // We have no type corresponding to a fake borrow, so use - // `*const` as an approximation. - RawPtrKind::FakeForPtrMetadata => Mutability::Not, - } - } - - pub fn ptr_str(self) -> &'static str { - match self { - RawPtrKind::Mut => "mut", - RawPtrKind::Const => "const", - RawPtrKind::FakeForPtrMetadata => "const (fake)", - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] pub enum MutBorrowKind { @@ -515,29 +465,6 @@ pub enum StatementKind<'tcx> { }, } -impl StatementKind<'_> { - /// Returns a simple string representation of a `StatementKind` variant, independent of any - /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). - pub const fn name(&self) -> &'static str { - match self { - StatementKind::Assign(..) => "Assign", - StatementKind::FakeRead(..) => "FakeRead", - StatementKind::SetDiscriminant { .. } => "SetDiscriminant", - StatementKind::Deinit(..) => "Deinit", - StatementKind::StorageLive(..) => "StorageLive", - StatementKind::StorageDead(..) => "StorageDead", - StatementKind::Retag(..) => "Retag", - StatementKind::PlaceMention(..) => "PlaceMention", - StatementKind::AscribeUserType(..) => "AscribeUserType", - StatementKind::Coverage(..) => "Coverage", - StatementKind::Intrinsic(..) => "Intrinsic", - StatementKind::ConstEvalCounter => "ConstEvalCounter", - StatementKind::Nop => "Nop", - StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", - } - } -} - #[derive( Clone, TyEncodable, @@ -673,12 +600,6 @@ pub enum CallSource { Normal, } -impl CallSource { - pub fn from_hir_call(self) -> bool { - matches!(self, CallSource::Normal) - } -} - #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] #[derive(TypeFoldable, TypeVisitable)] /// The macro that an inline assembly block was created by @@ -689,15 +610,6 @@ pub enum InlineAsmMacro { NakedAsm, } -impl InlineAsmMacro { - pub const fn diverges(self, options: InlineAsmOptions) -> bool { - match self { - InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), - InlineAsmMacro::NakedAsm => true, - } - } -} - /////////////////////////////////////////////////////////////////////////// // Terminators @@ -999,30 +911,6 @@ pub enum BackwardIncompatibleDropReason { Edition2024, } -impl TerminatorKind<'_> { - /// Returns a simple string representation of a `TerminatorKind` variant, independent of any - /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). - pub const fn name(&self) -> &'static str { - match self { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::UnwindResume => "UnwindResume", - TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::TailCall { .. } => "TailCall", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::CoroutineDrop => "CoroutineDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } - } -} - #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { /// Possible values. For each value, the location to branch to is found in diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index fdfcb128778a7..b887370fd699a 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -2,12 +2,13 @@ use std::slice; +use rustc_ast::InlineAsmOptions; use rustc_data_structures::packed::Pu128; use rustc_hir::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use smallvec::{SmallVec, smallvec}; -use super::{TerminatorKind, *}; +use super::*; impl SwitchTargets { /// Creates switch targets from an iterator of values and target blocks. @@ -414,6 +415,28 @@ impl<'tcx> Terminator<'tcx> { } impl<'tcx> TerminatorKind<'tcx> { + /// Returns a simple string representation of a `TerminatorKind` variant, independent of any + /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). + pub const fn name(&self) -> &'static str { + match self { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::UnwindResume => "UnwindResume", + TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::TailCall { .. } => "TailCall", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::CoroutineDrop => "CoroutineDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } + } + #[inline] pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } @@ -698,3 +721,18 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + +impl InlineAsmMacro { + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + InlineAsmMacro::NakedAsm => true, + } + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8ed5a118093f3..dbbbdc606bbb4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -47,7 +47,7 @@ pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::{Movability, Mutability, *}; +pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index ee331713736e7..10b43390eb288 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use rustc_middle::mir::*; -use rustc_middle::thir::{self, *}; +use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::builder::Builder; @@ -134,7 +134,7 @@ impl<'tcx> MatchPairTree<'tcx> { PatKind::Constant { value } => TestCase::Constant { value }, PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, + ascription: Ascription { ref annotation, variance }, ref subpattern, .. } => { diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index d693f739180f4..2d04b62193585 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -71,8 +71,7 @@ pub(crate) fn check_pointers<'tcx, F>( // statements/blocks after. Iterating or visiting the MIR in order would require updating // our current location after every insertion. By iterating backwards, we dodge this issue: // The only Locations that an insertion changes have already been handled. - for block in (0..basic_blocks.len()).rev() { - let block = block.into(); + for block in basic_blocks.indices().rev() { for statement_index in (0..basic_blocks[block].statements.len()).rev() { let location = Location { block, statement_index }; let statement = &basic_blocks[block].statements[statement_index]; diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 039f346495be0..5568d42ab8f3c 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -50,7 +50,7 @@ fn make_node_flow_priority_list( // A "reloop" node has exactly one out-edge, which jumps back to the top // of an enclosing loop. Reloop nodes are typically visited more times // than loop-exit nodes, so try to avoid giving them physical counters. - let is_reloop_node = IndexVec::from_fn_n( + let is_reloop_node = IndexVec::::from_fn_n( |node| match graph.successors[node].as_slice() { &[succ] => graph.dominates(succ, node), _ => false, diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 09384defea86f..dcc7c5b91d76a 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -42,7 +42,7 @@ impl CoverageGraph { // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so // de-duplication is required. This is done without reordering the successors. - let successors = IndexVec::from_fn_n( + let successors = IndexVec::::from_fn_n( |bcb| { let mut seen_bcbs = FxHashSet::default(); let terminator = mir_body[bcbs[bcb].last_bb()].terminator(); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2f8a305019999..29521d4272010 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1259,7 +1259,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let layout = self.ecx.layout_of(lhs_ty).ok()?; - let as_bits = |value| { + let as_bits = |value: VnIndex| { let constant = self.evaluated[value].as_ref()?; if layout.backend_repr.is_scalar() { let scalar = self.ecx.read_scalar(constant).discard_err()?; diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index e5a368796ec93..65c0171c88d5b 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -46,19 +46,19 @@ pub use self::join::join; /// It also simplifies the HIR lowering of `.await`. #[lang = "ResumeTy"] #[doc(hidden)] -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] #[derive(Debug, Copy, Clone)] pub struct ResumeTy(NonNull>); -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] unsafe impl Send for ResumeTy {} -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] unsafe impl Sync for ResumeTy {} #[lang = "get_context"] #[doc(hidden)] -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] #[must_use] #[inline] pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 74221e2168751..7d99aaa173143 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1352,11 +1352,11 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1474,12 +1474,12 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2682273b7f185..405c71121caad 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1613,11 +1613,11 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1734,11 +1734,11 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index c8fcee5c140f5..8993e14fcd379 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -229,6 +229,27 @@ impl ControlFlow { } } +impl ControlFlow { + /// Extracts the value `T` that is wrapped by `ControlFlow`. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_into_value)] + /// use std::ops::ControlFlow; + /// + /// assert_eq!(ControlFlow::::Break(1024).into_value(), 1024); + /// assert_eq!(ControlFlow::::Continue(512).into_value(), 512); + /// ``` + #[unstable(feature = "control_flow_into_value", issue = "137461")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + pub const fn into_value(self) -> T { + match self { + ControlFlow::Continue(x) | ControlFlow::Break(x) => x, + } + } +} + /// These are used only as part of implementing the iterator adapters. /// They have mediocre names and non-obvious semantics, so aren't /// currently on a path to potential stabilization. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 471150cfd9671..d47af93c16017 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2928,10 +2928,17 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `T` panics. + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. /// /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the @@ -2954,7 +2961,8 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. /// /// # Examples /// @@ -2982,15 +2990,17 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the comparison function `compare` does not implement a [total order] the resulting order - /// of elements in the slice is unspecified. All original elements will remain in the slice and - /// any possible modifications via interior mutability are observed in the input. Same is true - /// if `compare` panics. + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and /// examples see the [`Ord`] documentation. /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// /// # Current implementation /// /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which @@ -3003,7 +3013,8 @@ impl [T] { /// /// # Panics /// - /// May panic if `compare` does not implement a [total order]. + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. /// /// # Examples /// @@ -3034,10 +3045,16 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. /// /// # Current implementation /// @@ -3051,7 +3068,8 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. /// /// # Examples /// diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 392704e7509ac..bbf19d2b444f9 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -512,5 +512,169 @@ macro_rules! int_module { assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); } } + + // test_unbounded_sh* constants + const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS; + const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3; + const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2; + + const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1; + const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3; + const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1; + const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1; + + test_runtime_and_compiletime! { + fn test_unbounded_shl() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // -1 + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 1), (-1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 3), (-1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 5), (-1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + + fn test_unbounded_shr() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // -1 + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 1), (-1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 3), (-1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 5), (-1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + } }; } diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index c085ba5a249af..d09eb97b17e06 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -351,5 +351,169 @@ macro_rules! uint_module { assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); } } + + // test_unbounded_sh* constants + const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS; + const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3; + const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2; + + const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1; + const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3; + const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1; + const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1; + + test_runtime_and_compiletime! { + fn test_unbounded_shl() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // !0 + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 1), (!0 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 3), (!0 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 5), (!0 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + + fn test_unbounded_shr() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // !0 + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 1), (!0 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 3), (!0 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 5), (!0 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + } }; } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 0ddce30cf8e44..dce5a429cb0d4 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,4 +1,4 @@ -use super::api::{self, WinError}; +use super::api::{self, WinError, set_file_information_by_handle}; use super::{IoResult, to_u16s}; use crate::alloc::{alloc, handle_alloc_error}; use crate::borrow::Cow; @@ -319,31 +319,17 @@ impl File { && creation == c::OPEN_ALWAYS && api::get_last_error() == WinError::ALREADY_EXISTS { - unsafe { - // This first tries `FileAllocationInfo` but falls back to - // `FileEndOfFileInfo` in order to support WINE. - // If WINE gains support for FileAllocationInfo, we should - // remove the fallback. - let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; - let result = c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileAllocationInfo, - (&raw const alloc).cast::(), - mem::size_of::() as u32, - ); - if result == 0 { + // This first tries `FileAllocationInfo` but falls back to + // `FileEndOfFileInfo` in order to support WINE. + // If WINE gains support for FileAllocationInfo, we should + // remove the fallback. + let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; + set_file_information_by_handle(handle.as_raw_handle(), &alloc) + .or_else(|_| { let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; - let result = c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileEndOfFileInfo, - (&raw const eof).cast::(), - mem::size_of::() as u32, - ); - if result == 0 { - return Err(io::Error::last_os_error()); - } - } - } + set_file_information_by_handle(handle.as_raw_handle(), &eof) + }) + .io_result()?; } Ok(File { handle: Handle::from_inner(handle) }) } else { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4f5f8f92264c1..0ea4d8f1e3914 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -41,6 +41,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --font-family: "Source Serif 4", NanumBarunGothic, serif; --font-family-code: "Source Code Pro", monospace; --line-number-padding: 4px; + --line-number-right-margin: 20px; /* scraped examples icons (34x33px) */ --prev-arrow-image: url('data:image/svg+xml, .example-line-numbers, -.rustdoc .scraped-example .src-line-numbers, -.rustdoc .scraped-example .src-line-numbers > pre { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.rustdoc .example-wrap > .example-line-numbers + pre, -.rustdoc .scraped-example .rust { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - .rustdoc .scraped-example { position: relative; } @@ -908,45 +893,31 @@ both the code example and the line numbers, so we need to remove the radius in t overflow: auto; } -.rustdoc .example-wrap pre.example-line-numbers, -.rustdoc .example-wrap .src-line-numbers { - min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */ - flex-grow: 0; - text-align: right; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - padding: 14px 8px; - padding-right: 2px; - color: var(--src-line-numbers-span-color); -} - -.example-wrap.digits-1 [data-nosnippet] { +.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] { width: calc(1ch + var(--line-number-padding) * 2); } -.example-wrap.digits-2 [data-nosnippet] { +.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] { width: calc(2ch + var(--line-number-padding) * 2); } -.example-wrap.digits-3 [data-nosnippet] { +.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] { width: calc(3ch + var(--line-number-padding) * 2); } -.example-wrap.digits-4 [data-nosnippet] { +.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] { width: calc(4ch + var(--line-number-padding) * 2); } -.example-wrap.digits-5 [data-nosnippet] { +.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] { width: calc(5ch + var(--line-number-padding) * 2); } -.example-wrap.digits-6 [data-nosnippet] { +.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] { width: calc(6ch + var(--line-number-padding) * 2); } -.example-wrap.digits-7 [data-nosnippet] { +.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] { width: calc(7ch + var(--line-number-padding) * 2); } -.example-wrap.digits-8 [data-nosnippet] { +.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] { width: calc(8ch + var(--line-number-padding) * 2); } -.example-wrap.digits-9 [data-nosnippet] { +.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] { width: calc(9ch + var(--line-number-padding) * 2); } @@ -954,12 +925,12 @@ both the code example and the line numbers, so we need to remove the radius in t color: var(--src-line-numbers-span-color); text-align: right; display: inline-block; - margin-right: 20px; + margin-right: var(--line-number-right-margin); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; - padding: 0 4px; + padding: 0 var(--line-number-padding); } .example-wrap [data-nosnippet]:target { border-right: none; @@ -967,6 +938,60 @@ both the code example and the line numbers, so we need to remove the radius in t .example-wrap .line-highlighted[data-nosnippet] { background-color: var(--src-line-number-highlighted-background-color); } +:root.word-wrap-source-code .example-wrap [data-nosnippet] { + position: absolute; + left: 0; +} +.word-wrap-source-code .example-wrap pre > code { + position: relative; + word-break: break-all; +} +:root.word-wrap-source-code .example-wrap pre > code { + display: block; + white-space: pre-wrap; +} +:root.word-wrap-source-code .example-wrap pre > code * { + word-break: break-all; +} +:root.word-wrap-source-code .example-wrap.digits-1 pre > code { + padding-left: calc( + 1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-2 pre > code { + padding-left: calc( + 2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-3 pre > code { + padding-left: calc( + 3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-4 pre > code { + padding-left: calc( + 4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-5 pre > code { + padding-left: calc( + 5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-6 pre > code { + padding-left: calc( + 6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-7 pre > code { + padding-left: calc( + 7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-8 pre > code { + padding-left: calc( + 8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-9 pre > code { + padding-left: calc( + 9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +.example-wrap.hide-lines [data-nosnippet] { + display: none; +} .search-loading { text-align: center; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index e46cc1897e9e0..edfcc1291b976 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1112,35 +1112,32 @@ function preLoadCss(cssUrl) { // @ts-expect-error window.rustdoc_add_line_numbers_to_examples = () => { - if (document.querySelector(".rustdoc.src")) { - // We are in the source code page, nothing to be done here! - return; + // @ts-expect-error + function generateLine(nb) { + return `${nb}`; } + onEachLazy(document.querySelectorAll( - ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)", - ), x => { - const parent = x.parentNode; - const line_numbers = parent.querySelectorAll(".example-line-numbers"); - if (line_numbers.length > 0) { + ".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code", + ), code => { + if (hasClass(code.parentElement.parentElement, "hide-lines")) { + removeClass(code.parentElement.parentElement, "hide-lines"); return; } - const count = x.textContent.split("\n").length; - const elems = []; - for (let i = 0; i < count; ++i) { - elems.push(i + 1); - } - const node = document.createElement("pre"); - addClass(node, "example-line-numbers"); - node.innerHTML = elems.join("\n"); - parent.insertBefore(node, x); + const lines = code.innerHTML.split("\n"); + const digits = (lines.length + "").length; + // @ts-expect-error + code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n"); + addClass(code.parentElement.parentElement, `digits-${digits}`); }); }; // @ts-expect-error window.rustdoc_remove_line_numbers_from_examples = () => { - onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => { - x.parentNode.removeChild(x); - }); + onEachLazy( + document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"), + x => addClass(x, "hide-lines"), + ); }; if (getSettingValue("line-numbers") === "true") { diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index bf33e0f17e5fe..5f1bbd27328cb 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -59,6 +59,14 @@ } else { removeClass(document.documentElement, "sans-serif"); } + break; + case "word-wrap-source-code": + if (value === true) { + addClass(document.documentElement, "word-wrap-source-code"); + } else { + removeClass(document.documentElement, "word-wrap-source-code"); + } + break; } } @@ -246,6 +254,11 @@ "js_name": "sans-serif-fonts", "default": false, }, + { + "name": "Word wrap source code", + "js_name": "word-wrap-source-code", + "default": false, + }, ]; // Then we build the DOM. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 3042373fb096f..425b915b5f94e 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -286,6 +286,9 @@ if (getSettingValue("hide-modnav") === "true") { if (getSettingValue("sans-serif-fonts") === "true") { addClass(document.documentElement, "sans-serif"); } +if (getSettingValue("word-wrap-source-code") === "true") { + addClass(document.documentElement, "word-wrap-source-code"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { diff --git a/tests/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs index 8b416306ba66e..d9e69764be28e 100644 --- a/tests/codegen/issues/str-to-string-128690.rs +++ b/tests/codegen/issues/str-to-string-128690.rs @@ -2,25 +2,27 @@ #![crate_type = "lib"] //! Make sure str::to_string is specialized not to use fmt machinery. +//! +//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`. // CHECK-LABEL: define {{(dso_local )?}}void @one_ref #[no_mangle] pub fn one_ref(input: &str) -> String { - // CHECK-NOT: {{(call|invoke).*}}fmt + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} input.to_string() } // CHECK-LABEL: define {{(dso_local )?}}void @two_ref #[no_mangle] pub fn two_ref(input: &&str) -> String { - // CHECK-NOT: {{(call|invoke).*}}fmt + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} input.to_string() } // CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref #[no_mangle] pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String { - // CHECK-NOT: {{(call|invoke).*}}fmt + // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} input.to_string() } @@ -31,6 +33,6 @@ pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String { // CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref #[no_mangle] pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String { - // CHECK: {{(call|invoke).*}}fmt + // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}} input.to_string() } diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index 032746a6bdf44..97273ceb195fa 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -21,7 +21,7 @@ assert-css: ( set-local-storage: {"rustdoc-line-numbers": "true"} reload: // We wait for the line numbers to be added into the DOM by the JS... -wait-for: "pre.example-line-numbers" +wait-for: ".digits-1 pre" // Otherwise, we can't check text color show-text: true @@ -35,30 +35,21 @@ define-function: ( call-function: ("switch-theme", {"theme": |theme|}) // If the test didn't fail, it means that it was found! assert-css: ( - "pre.example-line-numbers", + ".digits-1 pre [data-nosnippet]", { "color": |color|, - "margin": "0px", - "padding-top": "14px", - "padding-bottom": "14px", - "padding-left": "8px", - "padding-right": "2px", + "margin-top": "0px", + "margin-bottom": "0px", + "margin-left": "0px", + "margin-right": "20px", + "padding-top": "0px", + "padding-bottom": "0px", + "padding-left": "4px", + "padding-right": "4px", "text-align": "right", - // There should not be a radius on the right of the line numbers. - "border-top-left-radius": "6px", - "border-bottom-left-radius": "6px", - "border-top-right-radius": "0px", - "border-bottom-right-radius": "0px", }, ALL, ) - // There should not be a radius on the left of the line numbers. - assert-css: ("pre.example-line-numbers + .rust", { - "border-top-left-radius": "0px", - "border-bottom-left-radius": "0px", - "border-top-right-radius": "6px", - "border-bottom-right-radius": "6px", - }) }, ) call-function: ("check-colors", { @@ -74,9 +65,6 @@ call-function: ("check-colors", { "color": "#c67e2d", }) -// The first code block has two lines so let's check its `
` elements lists both of them.
-assert-text: ("pre.example-line-numbers", "1\n2")
-
 // Now, try changing the setting dynamically. We'll turn it off, using the settings menu,
 // and make sure it goes away.
 
@@ -87,42 +75,17 @@ assert-css: ("#settings", {"display": "block"})
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-false: "pre.example-line-numbers"
+wait-for: ".digits-1.hide-lines"
 assert-local-storage: {"rustdoc-line-numbers": "false" }
 
-// Check that the rounded corners are back.
-assert-css: (
-    ".example-wrap .rust",
-    {
-        "border-top-left-radius": "6px",
-        "border-bottom-left-radius": "6px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 // Finally, turn it on again.
 click: "input#line-numbers"
-wait-for: "pre.example-line-numbers"
+wait-for: ".digits-1:not(.hide-lines)"
 assert-local-storage: {"rustdoc-line-numbers": "true" }
-wait-for: "pre.example-line-numbers"
 
 // Same check with scraped examples line numbers.
 go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
 
-assert-css: (
-    ".scraped-example .rust",
-    {
-        // There should not be a radius on the left of the code.
-        "border-top-left-radius": "0px",
-        "border-bottom-left-radius": "0px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 define-function: (
     "check-padding",
     [path, padding_bottom],
@@ -203,17 +166,18 @@ assert-local-storage: {"rustdoc-line-numbers": "true" }
 assert: ".example-wrap > pre.language-txt"
 assert: ".example-wrap > pre.rust"
 assert-count: (".example-wrap", 2)
-assert-count: (".example-wrap > pre.example-line-numbers", 2)
+assert-count: (".example-wrap.digits-1", 2)
 
 click: "#settings-menu"
 wait-for: "#settings"
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 0)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 2)
 assert-local-storage-false: {"rustdoc-line-numbers": "true" }
 
 // Now turning off the setting.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 2)
+wait-for-count: (".example-wrap.digits-1", 2)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 0)
 assert-local-storage: {"rustdoc-line-numbers": "true" }
diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
new file mode 100644
index 0000000000000..cb2fd3052cdac
--- /dev/null
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -0,0 +1,47 @@
+// Checks that the interactions with the source code pages are working as expected.
+go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+show-text: true
+set-window-size: (1000, 1000)
+
+define-function: (
+    "click-code-wrapping",
+    [expected],
+    block {
+        click: "#word-wrap-source-code"
+        wait-for-local-storage: {"rustdoc-word-wrap-source-code": |expected|}
+    },
+)
+
+store-size: (".rust code", {"width": width, "height": height})
+click: "#settings-menu"
+wait-for: "#settings"
+call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".rust code", {"width": |width|, "height": |height|})
+store-size: (".rust code", {"width": new_width, "height": new_height})
+// The width should now be smaller than the window's and the height
+// should have increased.
+assert: |width| > |new_width| && |height| < |new_height|
+
+// Switching back to the original setting.
+call-function: ("click-code-wrapping", {"expected": "false"})
+assert-size: (".rust code", {"width": |width|, "height": |height|})
+
+// Now let's check in docs code examples.
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html"
+click: "#settings-menu"
+wait-for: "#settings"
+
+store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height})
+store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height})
+call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+
+store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height})
+store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height})
+
+assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height|
+assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height|
+
+call-function: ("click-code-wrapping", {"expected": "false"})
+wait-for-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index f9c20ab22b89d..31f6b7f09b7d0 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -615,6 +615,15 @@ pub mod private {
     }
 }
 
+/// ```
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it() {
+/// }
+/// ```
+///
+/// ```text
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it_v2() {
+/// }
+/// ```
 pub mod trait_bounds {
     pub trait OneBound: Sized {}
     pub trait TwoBounds: Sized + Copy {}