From 0f72faa2b84dda5a1d67d2a55126572867ca5b0d Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 3 Oct 2024 23:40:21 +0100 Subject: [PATCH 1/5] Generate correct symbols.o for sparc-unknown-none-elf Fixes #130172 --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8857fda1e9728..77a84cfc7b759 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -209,7 +209,15 @@ pub(crate) fn create_object_file(sess: &Session) -> Option (Architecture::PowerPc64, None), "riscv32" => (Architecture::Riscv32, None), "riscv64" => (Architecture::Riscv64, None), - "sparc" => (Architecture::Sparc32Plus, None), + "sparc" => { + if sess.target.options.cpu == "v9" { + // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode + (Architecture::Sparc32Plus, None) + } else { + // Target uses V7 or V8, aka EM_SPARC + (Architecture::Sparc, None) + } + } "sparc64" => (Architecture::Sparc64, None), "avr" => (Architecture::Avr, None), "msp430" => (Architecture::Msp430, None), From 19e287060de9a641d7000a5575bb943a9bfba318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Oct 2024 21:30:23 +0100 Subject: [PATCH 2/5] remove const-support for align_offset Operations like is_aligned would return actively wrong results at compile-time, i.e. calling it on the same pointer at compiletime and runtime could yield different results. That's no good. Instead of having hacks to make align_offset kind-of work in const-eval, just use const_eval_select in the few places where it makes sense, which also ensures those places are all aware they need to make sure the fallback behavior is consistent. --- compiler/rustc_const_eval/messages.ftl | 3 - .../src/const_eval/machine.rs | 88 +----- compiler/rustc_hir/src/lang_items.rs | 3 - compiler/rustc_span/src/symbol.rs | 1 - library/core/src/lib.rs | 2 - library/core/src/ptr/const_ptr.rs | 192 +------------ library/core/src/ptr/mod.rs | 10 +- library/core/src/ptr/mut_ptr.rs | 186 +------------ library/core/src/ptr/non_null.rs | 170 +----------- library/core/src/slice/ascii.rs | 153 ++++++----- library/core/src/slice/memchr.rs | 95 ++++--- library/core/src/str/converts.rs | 1 - library/core/src/str/validations.rs | 26 +- library/core/src/ub_checks.rs | 14 +- library/core/tests/lib.rs | 2 - library/core/tests/ptr.rs | 257 ------------------ 16 files changed, 183 insertions(+), 1020 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 3e4f83c8242e7..2bc5adb2dce60 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -1,9 +1,6 @@ const_eval_address_space_full = there are no more free addresses in the address space -const_eval_align_offset_invalid_align = - `align_offset` called with non-power-of-two align: {$target_align} - const_eval_alignment_check_failed = {$msg -> [AccessedPtr] accessing memory diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 5f0bc8539ee0b..5938e836a8b5c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -1,7 +1,6 @@ use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::Hash; -use std::ops::ControlFlow; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; @@ -9,7 +8,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Span; @@ -23,9 +22,9 @@ use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, - InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar, - StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, - throw_ub_custom, throw_unsup, throw_unsup_format, + InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar, compile_time_machine, + interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, + throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -227,8 +226,8 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[FnArg<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, + _dest: &MPlaceTy<'tcx>, + _ret: Option, ) -> InterpResult<'tcx, Option>> { let def_id = instance.def_id(); @@ -260,85 +259,10 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ); return interp_ok(Some(new_instance)); - } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { - let args = self.copy_fn_args(args); - // For align_offset, we replace the function call if the pointer has no address. - match self.align_offset(instance, &args, dest, ret)? { - ControlFlow::Continue(()) => return interp_ok(Some(instance)), - ControlFlow::Break(()) => return interp_ok(None), - } } interp_ok(Some(instance)) } - /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer - /// may not have an address. - /// - /// If `ptr` does have a known address, then we return `Continue(())` and the function call should - /// proceed as normal. - /// - /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most - /// `target_align`, then we call the function again with an dummy address relative to the - /// allocation. - /// - /// If `ptr` doesn't have an address and `target_align` is stricter than the underlying - /// allocation's alignment, then we return `usize::MAX` immediately. - fn align_offset( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, - ) -> InterpResult<'tcx, ControlFlow<()>> { - assert_eq!(args.len(), 2); - - let ptr = self.read_pointer(&args[0])?; - let target_align = self.read_scalar(&args[1])?.to_target_usize(self)?; - - if !target_align.is_power_of_two() { - throw_ub_custom!( - fluent::const_eval_align_offset_invalid_align, - target_align = target_align, - ); - } - - match self.ptr_try_get_alloc_id(ptr, 0) { - Ok((alloc_id, offset, _extra)) => { - let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id); - - if target_align <= alloc_align.bytes() { - // Extract the address relative to the allocation base that is definitely - // sufficiently aligned and call `align_offset` again. - let addr = ImmTy::from_uint(offset.bytes(), args[0].layout).into(); - let align = ImmTy::from_uint(target_align, args[1].layout).into(); - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - - // Push the stack frame with our own adjusted arguments. - self.init_stack_frame( - instance, - self.load_mir(instance.def, None)?, - fn_abi, - &[FnArg::Copy(addr), FnArg::Copy(align)], - /* with_caller_location = */ false, - dest, - StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable }, - )?; - interp_ok(ControlFlow::Break(())) - } else { - // Not alignable in const, return `usize::MAX`. - let usize_max = Scalar::from_target_usize(self.target_usize_max(), self); - self.write_scalar(usize_max, dest)?; - self.return_to_block(ret)?; - interp_ok(ControlFlow::Break(())) - } - } - Err(_addr) => { - // The pointer has an address, continue with function call. - interp_ok(ControlFlow::Continue(())) - } - } - } - /// See documentation on the `ptr_guaranteed_cmp` intrinsic. fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { interp_ok(match (a, b) { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7d81f977c22ef..c952d5f6d77cf 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -348,9 +348,6 @@ language_item_table! { MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; - /// Align offset for stride != 1; must not panic. - AlignOffset, sym::align_offset, align_offset_fn, Target::Fn, GenericRequirement::None; - Termination, sym::termination, termination, Target::Trait, GenericRequirement::None; Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 890c4fdafef89..fac2180d63b47 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -378,7 +378,6 @@ symbols! { aggregate_raw_ptr, alias, align, - align_offset, alignment, all, alloc, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index bbfe32027e8eb..686378fc5cf36 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -112,7 +112,6 @@ #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] -#![feature(const_align_offset)] #![feature(const_alloc_layout)] #![feature(const_arguments_as_str)] #![feature(const_black_box)] @@ -125,7 +124,6 @@ #![feature(const_nonnull_new)] #![feature(const_option_ext)] #![feature(const_pin_2)] -#![feature(const_pointer_is_aligned)] #![feature(const_ptr_is_null)] #![feature(const_ptr_sub_ptr)] #![feature(const_raw_ptr_comparison)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index f00984da5270a..a4e8e373e041e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1358,15 +1358,6 @@ impl *const T { /// beyond the allocation that the pointer points into. It is up to the caller to ensure that /// the returned offset is correct in all terms other than alignment. /// - /// When this is called during compile-time evaluation (which is unstable), the implementation - /// may return `usize::MAX` in cases where that can never happen at runtime. This is because the - /// actual alignment of pointers is not known yet during compile-time, so an offset with - /// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8; - /// N]` might be allocated at an odd or an even address, but at compile-time this is not yet - /// known, so the execution has to be correct for either choice. It is therefore impossible to - /// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual - /// for unstable APIs.) - /// /// # Panics /// /// The function panics if `align` is not a power-of-two. @@ -1395,8 +1386,7 @@ impl *const T { #[must_use] #[inline] #[stable(feature = "align_offset", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1431,94 +1421,10 @@ impl *const T { /// assert!(ptr.is_aligned()); /// assert!(!ptr.wrapping_byte_add(1).is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = 40 as *const AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1555,105 +1461,15 @@ impl *const T { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { panic!("is_aligned_to: align is not a power-of-two"); } - #[inline] - fn runtime_impl(ptr: *const (), align: usize) -> bool { - ptr.addr() & (align - 1) == 0 - } - - #[inline] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - const fn const_impl(ptr: *const (), align: usize) -> bool { - // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. - ptr.align_offset(align) == 0 - } - - // The cast to `()` is used to - // 1. deal with fat pointers; and - // 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset. - const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + self.addr() & (align - 1) == 0 } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 7c2205fdcd1c3..b98e2b5eac82a 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1852,9 +1852,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { /// /// Any questions go to @nagisa. #[allow(ptr_to_integer_transmute_in_consts)] -#[lang = "align_offset"] -#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] -pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usize { +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. use intrinsics::{ @@ -1915,11 +1913,7 @@ pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usiz let stride = mem::size_of::(); - // SAFETY: This is just an inlined `p.addr()` (which is not - // a `const fn` so we cannot call it). - // During const eval, we hook this function to ensure that the pointer never - // has provenance, making this sound. - let addr: usize = unsafe { mem::transmute(p) }; + let addr: usize = p.addr(); // SAFETY: `a` is a power-of-two, therefore non-zero. let a_minus_one = unsafe { unchecked_sub(a, 1) }; diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 60a2dcd1ee72a..0d94a7f491c21 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1,6 +1,5 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; -use crate::intrinsics::const_eval_select; use crate::mem::SizedTypeProperties; use crate::slice::{self, SliceIndex}; @@ -1636,8 +1635,7 @@ impl *mut T { #[must_use] #[inline] #[stable(feature = "align_offset", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1675,95 +1673,10 @@ impl *mut T { /// assert!(ptr.is_aligned()); /// assert!(!ptr.wrapping_byte_add(1).is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// // Also, note that mutable references are not allowed in the final value of constants. - /// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut(); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = 40 as *mut AlignedI32; - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = ptr.wrapping_add(1).cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1800,106 +1713,15 @@ impl *mut T { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// // Also, note that mutable references are not allowed in the final value of constants. - /// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut(); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *mut u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { panic!("is_aligned_to: align is not a power-of-two"); } - #[inline] - fn runtime_impl(ptr: *mut (), align: usize) -> bool { - ptr.addr() & (align - 1) == 0 - } - - #[inline] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - const fn const_impl(ptr: *mut (), align: usize) -> bool { - // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. - ptr.align_offset(align) == 0 - } - - // The cast to `()` is used to - // 1. deal with fat pointers; and - // 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset. - const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) + self.addr() & (align - 1) == 0 } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 44eeb052661b2..ad24e50aa15d5 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1192,8 +1192,7 @@ impl NonNull { #[inline] #[must_use] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] - pub const fn align_offset(self, align: usize) -> usize + pub fn align_offset(self, align: usize) -> usize where T: Sized, { @@ -1224,98 +1223,10 @@ impl NonNull { /// assert!(ptr.is_aligned()); /// assert!(!NonNull::new(ptr.as_ptr().wrapping_byte_add(1)).unwrap().is_aligned()); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// is never aligned if cast to a type with a stricter alignment than the reference's - /// underlying allocation. - /// - /// ``` - /// #![feature(const_nonnull_new)] - /// #![feature(const_pointer_is_aligned)] - /// use std::ptr::NonNull; - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let data = [AlignedI32(42), AlignedI32(42)]; - /// let ptr = NonNull::::new(&data[0] as *const _ as *mut _).unwrap(); - /// assert!(ptr.is_aligned()); - /// - /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = unsafe { ptr.add(1).cast::() }; - /// assert!(!ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.cast::().is_aligned(), - /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_nonnull_new)] - /// use std::ptr::NonNull; - /// - /// // On some platforms, the alignment of primitives is less than their size. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// #[repr(align(8))] - /// struct AlignedI64(i64); - /// - /// const _: () = { - /// let ptr = NonNull::new(40 as *mut AlignedI32).unwrap(); - /// assert!(ptr.is_aligned()); - /// - /// // For pointers with a known address, runtime and compiletime behavior are identical. - /// let ptr1 = ptr.cast::(); - /// let ptr2 = NonNull::new(ptr.as_ptr().wrapping_add(1)).unwrap().cast::(); - /// assert!(ptr1.is_aligned()); - /// assert!(!ptr2.is_aligned()); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[inline] #[must_use] #[stable(feature = "pointer_is_aligned", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned(self) -> bool + pub fn is_aligned(self) -> bool where T: Sized, { @@ -1352,85 +1263,10 @@ impl NonNull { /// /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned_to)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[inline] #[must_use] #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { + pub fn is_aligned_to(self, align: usize) -> bool { self.pointer.is_aligned_to(align) } } diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 21e0460072fb3..8dcd34929e18d 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -3,6 +3,7 @@ use core::ascii::EscapeDefault; use crate::fmt::{self, Write}; +use crate::intrinsics::const_eval_select; use crate::{ascii, iter, mem, ops}; #[cfg(not(test))] @@ -346,89 +347,93 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. #[inline] -#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion -#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior const fn is_ascii(s: &[u8]) -> bool { - const USIZE_SIZE: usize = mem::size_of::(); - - let len = s.len(); - let align_offset = s.as_ptr().align_offset(USIZE_SIZE); - - // If we wouldn't gain anything from the word-at-a-time implementation, fall - // back to a scalar loop. - // - // We also do this for architectures where `size_of::()` isn't - // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { - return is_ascii_simple(s); + // The runtime version behaves the same as the compiletime version, it's + // just more optimized. + return const_eval_select((s,), compiletime, runtime); + + const fn compiletime(s: &[u8]) -> bool { + is_ascii_simple(s) } - // We always read the first word unaligned, which means `align_offset` is - // 0, we'd read the same value again for the aligned read. - let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; + #[inline] + fn runtime(s: &[u8]) -> bool { + const USIZE_SIZE: usize = mem::size_of::(); + + let len = s.len(); + let align_offset = s.as_ptr().align_offset(USIZE_SIZE); + + // If we wouldn't gain anything from the word-at-a-time implementation, fall + // back to a scalar loop. + // + // We also do this for architectures where `size_of::()` isn't + // sufficient alignment for `usize`, because it's a weird edge case. + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + return is_ascii_simple(s); + } - let start = s.as_ptr(); - // SAFETY: We verify `len < USIZE_SIZE` above. - let first_word = unsafe { (start as *const usize).read_unaligned() }; + // We always read the first word unaligned, which means `align_offset` is + // 0, we'd read the same value again for the aligned read. + let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; - if contains_nonascii(first_word) { - return false; - } - // We checked this above, somewhat implicitly. Note that `offset_to_aligned` - // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked - // above. - debug_assert!(offset_to_aligned <= len); - - // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the - // middle chunk of the slice. - let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; - - // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. - let mut byte_pos = offset_to_aligned; - - // Paranoia check about alignment, since we're about to do a bunch of - // unaligned loads. In practice this should be impossible barring a bug in - // `align_offset` though. - // While this method is allowed to spuriously fail in CTFE, if it doesn't - // have alignment information it should have given a `usize::MAX` for - // `align_offset` earlier, sending things through the scalar path instead of - // this one, so this check should pass if it's reachable. - debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); - - // Read subsequent words until the last aligned word, excluding the last - // aligned word by itself to be done in tail check later, to ensure that - // tail is always one `usize` at most to extra branch `byte_pos == len`. - while byte_pos < len - USIZE_SIZE { - // Sanity check that the read is in bounds - debug_assert!(byte_pos + USIZE_SIZE <= len); - // And that our assumptions about `byte_pos` hold. - debug_assert!(matches!( - word_ptr.cast::().guaranteed_eq(start.wrapping_add(byte_pos)), - // These are from the same allocation, so will hopefully always be - // known to match even in CTFE, but if it refuses to compare them - // that's ok since it's just a debug check anyway. - None | Some(true), - )); - - // SAFETY: We know `word_ptr` is properly aligned (because of - // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end - let word = unsafe { word_ptr.read() }; - if contains_nonascii(word) { + let start = s.as_ptr(); + // SAFETY: We verify `len < USIZE_SIZE` above. + let first_word = unsafe { (start as *const usize).read_unaligned() }; + + if contains_nonascii(first_word) { return false; } + // We checked this above, somewhat implicitly. Note that `offset_to_aligned` + // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked + // above. + debug_assert!(offset_to_aligned <= len); + + // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the + // middle chunk of the slice. + let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; + + // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. + let mut byte_pos = offset_to_aligned; + + // Paranoia check about alignment, since we're about to do a bunch of + // unaligned loads. In practice this should be impossible barring a bug in + // `align_offset` though. + // While this method is allowed to spuriously fail in CTFE, if it doesn't + // have alignment information it should have given a `usize::MAX` for + // `align_offset` earlier, sending things through the scalar path instead of + // this one, so this check should pass if it's reachable. + debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); + + // Read subsequent words until the last aligned word, excluding the last + // aligned word by itself to be done in tail check later, to ensure that + // tail is always one `usize` at most to extra branch `byte_pos == len`. + while byte_pos < len - USIZE_SIZE { + // Sanity check that the read is in bounds + debug_assert!(byte_pos + USIZE_SIZE <= len); + // And that our assumptions about `byte_pos` hold. + debug_assert!(word_ptr.cast::() == start.wrapping_add(byte_pos)); + + // SAFETY: We know `word_ptr` is properly aligned (because of + // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end + let word = unsafe { word_ptr.read() }; + if contains_nonascii(word) { + return false; + } - byte_pos += USIZE_SIZE; - // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that - // after this `add`, `word_ptr` will be at most one-past-the-end. - word_ptr = unsafe { word_ptr.add(1) }; - } + byte_pos += USIZE_SIZE; + // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that + // after this `add`, `word_ptr` will be at most one-past-the-end. + word_ptr = unsafe { word_ptr.add(1) }; + } - // Sanity check to ensure there really is only one `usize` left. This should - // be guaranteed by our loop condition. - debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); + // Sanity check to ensure there really is only one `usize` left. This should + // be guaranteed by our loop condition. + debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); - // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. - let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; + // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. + let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; - !contains_nonascii(last_word) + !contains_nonascii(last_word) + } } diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 5760462326261..b7c4a1f6f08b1 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -1,6 +1,7 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +use crate::intrinsics::const_eval_select; use crate::mem; const LO_USIZE: usize = usize::repeat_u8(0x01); @@ -50,58 +51,66 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option { None } -#[rustc_allow_const_fn_unstable(const_cmp)] -#[rustc_allow_const_fn_unstable(const_align_offset)] +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_aligned(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned initial part, before the first word aligned address in text - // - body, scan by 2 words at a time - // - the last remaining part, < 2 word size - - // search up to an aligned boundary - let len = text.len(); - let ptr = text.as_ptr(); - let mut offset = ptr.align_offset(USIZE_BYTES); + // The runtime version behaves the same as the compiletime version, it's + // just more optimized. + return const_eval_select((x, text), compiletime, runtime); - if offset > 0 { - // FIXME(const-hack, fee1-dead): replace with min - offset = if offset < len { offset } else { len }; - // FIXME(const-hack, fee1-dead): replace with range slicing - // SAFETY: offset is within bounds - let slice = unsafe { super::from_raw_parts(text.as_ptr(), offset) }; - if let Some(index) = memchr_naive(x, slice) { - return Some(index); - } + const fn compiletime(x: u8, text: &[u8]) -> Option { + memchr_naive(x, text) } - // search the body of the text - let repeated_x = usize::repeat_u8(x); - while offset <= len - 2 * USIZE_BYTES { - // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes - // between the offset and the end of the slice. - unsafe { - let u = *(ptr.add(offset) as *const usize); - let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); + #[inline] + fn runtime(x: u8, text: &[u8]) -> Option { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned initial part, before the first word aligned address in text + // - body, scan by 2 words at a time + // - the last remaining part, < 2 word size + + // search up to an aligned boundary + let len = text.len(); + let ptr = text.as_ptr(); + let mut offset = ptr.align_offset(USIZE_BYTES); + + if offset > 0 { + offset = offset.min(len); + let slice = &text[..offset]; + if let Some(index) = memchr_naive(x, slice) { + return Some(index); + } + } - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; + // search the body of the text + let repeated_x = usize::repeat_u8(x); + while offset <= len - 2 * USIZE_BYTES { + // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes + // between the offset and the end of the slice. + unsafe { + let u = *(ptr.add(offset) as *const usize); + let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } } + offset += USIZE_BYTES * 2; } - offset += USIZE_BYTES * 2; - } - // Find the byte after the point the body loop stopped. - // FIXME(const-hack): Use `?` instead. - // FIXME(const-hack, fee1-dead): use range slicing - // SAFETY: offset is within bounds - let slice = unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) }; - if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None } + // Find the byte after the point the body loop stopped. + // FIXME(const-hack): Use `?` instead. + // FIXME(const-hack, fee1-dead): use range slicing + let slice = + // SAFETY: offset is within bounds + unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) }; + if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None } + } } /// Returns the last index matching the byte `x` in `text`. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 2bc1f1e49733f..c7bae42765f4e 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,7 +82,6 @@ use crate::{mem, ptr}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] -#[rustc_allow_const_fn_unstable(str_internals)] #[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index cca8ff74dda8b..6095b589e18c3 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -1,6 +1,7 @@ //! Operations related to UTF-8 validation. use super::Utf8Error; +use crate::intrinsics::const_eval_select; use crate::mem; /// Returns the initial codepoint accumulator for the first byte. @@ -122,15 +123,28 @@ const fn contains_nonascii(x: usize) -> bool { /// Walks through `v` checking that it's a valid UTF-8 sequence, /// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. #[inline(always)] -#[rustc_const_unstable(feature = "str_internals", issue = "none")] +#[rustc_allow_const_fn_unstable(const_eval_select)] // fallback impl has same behavior pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let mut index = 0; let len = v.len(); - let usize_bytes = mem::size_of::(); - let ascii_block_size = 2 * usize_bytes; + const USIZE_BYTES: usize = mem::size_of::(); + + let ascii_block_size = 2 * USIZE_BYTES; let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; - let align = v.as_ptr().align_offset(usize_bytes); + let align = { + const fn compiletime(_v: &[u8]) -> usize { + usize::MAX + } + + fn runtime(v: &[u8]) -> usize { + v.as_ptr().align_offset(USIZE_BYTES) + } + + // Below, we safely fall back to a slower codepath if the offset is `usize::MAX`, + // so the end-to-end behavior is the same at compiletime and runtime. + const_eval_select((v,), compiletime, runtime) + }; while index < len { let old_offset = index; @@ -209,11 +223,11 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { + if align != usize::MAX && align.wrapping_sub(index) % USIZE_BYTES == 0 { let ptr = v.as_ptr(); while index < blocks_end { // SAFETY: since `align - index` and `ascii_block_size` are - // multiples of `usize_bytes`, `block = ptr.add(index)` is + // multiples of `USIZE_BYTES`, `block = ptr.add(index)` is // always aligned with a `usize` so it's safe to dereference // both `block` and `block.add(1)`. unsafe { diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 91566439adeae..dd1454f401eaf 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -120,7 +120,19 @@ pub(crate) const fn check_language_ub() -> bool { #[inline] #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool { - ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + #[inline] + fn runtime(ptr: *const (), align: usize, is_zst: bool) -> bool { + ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) + } + + #[inline] + #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] + const fn comptime(ptr: *const (), _align: usize, is_zst: bool) -> bool { + is_zst || !ptr.is_null() + } + + // This is just for safety checks so we can const_eval_select. + const_eval_select((ptr, align, is_zst), comptime, runtime) } #[inline] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7346d9f231939..5f14baf96ae75 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(cell_update)] #![feature(clone_to_uninit)] #![feature(const_align_of_val_raw)] -#![feature(const_align_offset)] #![feature(const_black_box)] #![feature(const_eval_select)] #![feature(const_hash)] @@ -24,7 +23,6 @@ #![feature(const_nonnull_new)] #![feature(const_option_ext)] #![feature(const_pin_2)] -#![feature(const_pointer_is_aligned)] #![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 78d1b137e63f5..91f8c977d088a 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -359,22 +359,6 @@ fn align_offset_zst() { } } -#[test] -fn align_offset_zst_const() { - const { - // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at - // all, because no amount of elements will align the pointer. - let mut p = 1; - while p < 1024 { - assert!(ptr::without_provenance::<()>(p).align_offset(p) == 0); - if p != 1 { - assert!(ptr::without_provenance::<()>(p + 1).align_offset(p) == !0); - } - p = (p + 1).next_power_of_two(); - } - } -} - #[test] fn align_offset_stride_one() { // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to @@ -396,25 +380,6 @@ fn align_offset_stride_one() { } } -#[test] -fn align_offset_stride_one_const() { - const { - // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to - // number of bytes. - let mut align = 1; - while align < 1024 { - let mut ptr = 1; - while ptr < 2 * align { - let expected = ptr % align; - let offset = if expected == 0 { 0 } else { align - expected }; - assert!(ptr::without_provenance::(ptr).align_offset(align) == offset); - ptr += 1; - } - align = (align + 1).next_power_of_two(); - } - } -} - #[test] fn align_offset_various_strides() { unsafe fn test_stride(ptr: *const T, align: usize) -> bool { @@ -495,192 +460,6 @@ fn align_offset_various_strides() { assert!(!x); } -#[test] -fn align_offset_various_strides_const() { - const unsafe fn test_stride(ptr: *const T, numptr: usize, align: usize) { - let mut expected = usize::MAX; - // Naive but definitely correct way to find the *first* aligned element of stride::. - let mut el = 0; - while el < align { - if (numptr + el * ::std::mem::size_of::()) % align == 0 { - expected = el; - break; - } - el += 1; - } - let got = ptr.align_offset(align); - assert!(got == expected); - } - - const { - // For pointers of stride != 1, we verify the algorithm against the naivest possible - // implementation - let mut align = 1; - let limit = 32; - while align < limit { - let mut ptr = 1; - while ptr < 4 * align { - unsafe { - #[repr(packed)] - struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - struct A4(#[allow(dead_code)] u32); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A7( - #[allow(dead_code)] u32, - #[allow(dead_code)] u16, - #[allow(dead_code)] u8, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A9( - #[allow(dead_code)] u32, - #[allow(dead_code)] u32, - #[allow(dead_code)] u8, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - #[repr(packed)] - struct A10( - #[allow(dead_code)] u32, - #[allow(dead_code)] u32, - #[allow(dead_code)] u16, - ); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - - test_stride::(ptr::without_provenance::(ptr), ptr, align); - test_stride::(ptr::without_provenance::(ptr), ptr, align); - } - ptr += 1; - } - align = (align + 1).next_power_of_two(); - } - } -} - -#[test] -fn align_offset_with_provenance_const() { - const { - // On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4. - #[repr(align(4))] - struct AlignedI32(i32); - - let data = AlignedI32(42); - - // `stride % align == 0` (usual case) - - let ptr: *const i32 = &data.0; - assert!(ptr.align_offset(1) == 0); - assert!(ptr.align_offset(2) == 0); - assert!(ptr.align_offset(4) == 0); - assert!(ptr.align_offset(8) == usize::MAX); - assert!(ptr.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(1).align_offset(2) == usize::MAX); - assert!(ptr.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr.wrapping_byte_add(2).align_offset(4) == usize::MAX); - assert!(ptr.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr.wrapping_byte_add(3).align_offset(2) == usize::MAX); - - assert!(ptr.wrapping_add(42).align_offset(4) == 0); - assert!(ptr.wrapping_add(42).align_offset(8) == usize::MAX); - - let ptr1: *const i8 = ptr.cast(); - assert!(ptr1.align_offset(1) == 0); - assert!(ptr1.align_offset(2) == 0); - assert!(ptr1.align_offset(4) == 0); - assert!(ptr1.align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr1.wrapping_byte_add(1).align_offset(4) == 3); - assert!(ptr1.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr1.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr1.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr1.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr1.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr1.wrapping_byte_add(3).align_offset(4) == 1); - assert!(ptr1.wrapping_byte_add(3).align_offset(8) == usize::MAX); - - let ptr2: *const i16 = ptr.cast(); - assert!(ptr2.align_offset(1) == 0); - assert!(ptr2.align_offset(2) == 0); - assert!(ptr2.align_offset(4) == 0); - assert!(ptr2.align_offset(8) == usize::MAX); - assert!(ptr2.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(1).align_offset(2) == usize::MAX); - assert!(ptr2.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr2.wrapping_byte_add(2).align_offset(4) == 1); - assert!(ptr2.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr2.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr2.wrapping_byte_add(3).align_offset(2) == usize::MAX); - - let ptr3: *const i64 = ptr.cast(); - assert!(ptr3.align_offset(1) == 0); - assert!(ptr3.align_offset(2) == 0); - assert!(ptr3.align_offset(4) == 0); - assert!(ptr3.align_offset(8) == usize::MAX); - assert!(ptr3.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr3.wrapping_byte_add(1).align_offset(2) == usize::MAX); - - // `stride % align != 0` (edge case) - - let ptr4: *const [u8; 3] = ptr.cast(); - assert!(ptr4.align_offset(1) == 0); - assert!(ptr4.align_offset(2) == 0); - assert!(ptr4.align_offset(4) == 0); - assert!(ptr4.align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr4.wrapping_byte_add(1).align_offset(4) == 1); - assert!(ptr4.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr4.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr4.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr4.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr4.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr4.wrapping_byte_add(3).align_offset(4) == 3); - assert!(ptr4.wrapping_byte_add(3).align_offset(8) == usize::MAX); - - let ptr5: *const [u8; 5] = ptr.cast(); - assert!(ptr5.align_offset(1) == 0); - assert!(ptr5.align_offset(2) == 0); - assert!(ptr5.align_offset(4) == 0); - assert!(ptr5.align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(1).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(1).align_offset(2) == 1); - assert!(ptr5.wrapping_byte_add(1).align_offset(4) == 3); - assert!(ptr5.wrapping_byte_add(1).align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(2).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(2).align_offset(2) == 0); - assert!(ptr5.wrapping_byte_add(2).align_offset(4) == 2); - assert!(ptr5.wrapping_byte_add(2).align_offset(8) == usize::MAX); - assert!(ptr5.wrapping_byte_add(3).align_offset(1) == 0); - assert!(ptr5.wrapping_byte_add(3).align_offset(2) == 1); - assert!(ptr5.wrapping_byte_add(3).align_offset(4) == 1); - assert!(ptr5.wrapping_byte_add(3).align_offset(8) == usize::MAX); - } -} - #[test] fn align_offset_issue_103361() { #[cfg(target_pointer_width = "64")] @@ -693,23 +472,6 @@ fn align_offset_issue_103361() { let _ = ptr::without_provenance::(SIZE).align_offset(SIZE); } -#[test] -fn align_offset_issue_103361_const() { - #[cfg(target_pointer_width = "64")] - const SIZE: usize = 1 << 47; - #[cfg(target_pointer_width = "32")] - const SIZE: usize = 1 << 30; - #[cfg(target_pointer_width = "16")] - const SIZE: usize = 1 << 13; - struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); - - const { - assert!(ptr::without_provenance::(SIZE - 1).align_offset(SIZE) == SIZE - 1); - assert!(ptr::without_provenance::(SIZE).align_offset(SIZE) == 0); - assert!(ptr::without_provenance::(SIZE + 1).align_offset(SIZE) == 1); - } -} - #[test] fn is_aligned() { let data = 42; @@ -726,25 +488,6 @@ fn is_aligned() { assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); } -#[test] -fn is_aligned_const() { - const { - let data = 42; - let ptr: *const i32 = &data; - assert!(ptr.is_aligned()); - assert!(ptr.is_aligned_to(1)); - assert!(ptr.is_aligned_to(2)); - assert!(ptr.is_aligned_to(4)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - - // At comptime neither `ptr` nor `ptr+1` is aligned to 8. - assert!(!ptr.is_aligned_to(8)); - assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - } -} - #[test] fn offset_from() { let mut a = [0; 5]; From 9e6d2da83dcc7fe58c0352d61d20b42f09182c63 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:26:01 +0000 Subject: [PATCH 3/5] Reduce dependence on the target name The target name can be anything with custom target specs. Matching on fields inside the target spec is much more robust than matching on the target name. --- compiler/rustc_codegen_gcc/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 29 ++++++------------- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++--- compiler/rustc_codegen_ssa/src/back/linker.rs | 1 + compiler/rustc_codegen_ssa/src/back/write.rs | 4 +++ 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 660badb6a5018..07c7a54de1cec 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -146,7 +146,7 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { // Wasm statics with custom link sections get special treatment as they // go into custom sections of the wasm executable. - if self.tcx.sess.opts.target_triple.tuple().starts_with("wasm32") { + if self.tcx.sess.target.is_like_wasm { if let Some(_section) = attrs.link_section { unimplemented!(); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 647e9e13fbcb6..a65ae4df1e378 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -945,23 +945,10 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: asm } -fn target_is_apple(cgcx: &CodegenContext) -> bool { - let triple = cgcx.opts.target_triple.tuple(); - triple.contains("-ios") - || triple.contains("-darwin") - || triple.contains("-tvos") - || triple.contains("-watchos") - || triple.contains("-visionos") -} - -fn target_is_aix(cgcx: &CodegenContext) -> bool { - cgcx.opts.target_triple.tuple().contains("-aix") -} - pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> &'static CStr { - if target_is_apple(cgcx) { + if cgcx.target_is_like_osx { c"__LLVM,__bitcode" - } else if target_is_aix(cgcx) { + } else if cgcx.target_is_like_aix { c".ipa" } else { c".llvmbc" @@ -1028,10 +1015,12 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - let is_aix = target_is_aix(cgcx); - let is_apple = target_is_apple(cgcx); unsafe { - if is_apple || is_aix || cgcx.opts.target_triple.tuple().starts_with("wasm") { + if cgcx.target_is_like_osx + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { // We don't need custom section flags, create LLVM globals. let llconst = common::bytes_in_context(llcx, bitcode); let llglobal = llvm::LLVMAddGlobal( @@ -1052,9 +1041,9 @@ unsafe fn embed_bitcode( c"rustc.embedded.cmdline".as_ptr(), ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { + let section = if cgcx.target_is_like_osx { c"__LLVM,__cmdline" - } else if is_aix { + } else if cgcx.target_is_like_aix { c".info" } else { c".llvmcmd" diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 20920d16f3cea..39ff00baf6dc6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -85,11 +85,7 @@ pub fn link_binary( } if invalid_output_for_target(sess, crate_type) { - bug!( - "invalid output type `{:?}` for target os `{}`", - crate_type, - sess.opts.target_triple - ); + bug!("invalid output type `{:?}` for target `{}`", crate_type, sess.opts.target_triple); } sess.time("link_binary_check_files_are_writeable", || { @@ -996,6 +992,7 @@ fn link_natively( && (code < 1000 || code > 9999) { let is_vs_installed = windows_registry::find_vs_version().is_ok(); + // FIXME(cc-rs#1265) pass only target arch to find_tool() let has_linker = windows_registry::find_tool( sess.opts.target_triple.tuple(), "link.exe", diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3b4429535d434..4f3664a503d61 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -47,6 +47,7 @@ pub(crate) fn get_linker<'a>( self_contained: bool, target_cpu: &'a str, ) -> Box { + // FIXME(cc-rs#1265) pass only target arch to find_tool() let msvc_tool = windows_registry::find_tool(sess.opts.target_triple.tuple(), "link.exe"); // If our linker looks like a batch script on Windows then to execute this diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index d977cca247eea..a2285bf9204a4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -345,6 +345,8 @@ pub struct CodegenContext { pub is_pe_coff: bool, pub target_can_use_split_dwarf: bool, pub target_arch: String, + pub target_is_like_osx: bool, + pub target_is_like_aix: bool, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, @@ -1195,6 +1197,8 @@ fn start_executing_work( is_pe_coff: tcx.sess.target.is_like_windows, target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(), target_arch: tcx.sess.target.arch.to_string(), + target_is_like_osx: tcx.sess.target.is_like_osx, + target_is_like_aix: tcx.sess.target.is_like_aix, split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, From 775aad80fc4de54dbf3d029ce9aca4371ea48c09 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:31:32 +0000 Subject: [PATCH 4/5] Remove is_builtin target spec field It is unused. --- compiler/rustc_target/src/spec/mod.rs | 13 +------------ .../target-specs/definitely-not-builtin-target.json | 7 ------- tests/run-make/target-specs/rmake.rs | 5 ----- 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 tests/run-make/target-specs/definitely-not-builtin-target.json diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 06408e0b210fb..cef11fe1c9e80 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1595,11 +1595,10 @@ macro_rules! supported_targets { pub const TARGETS: &[&str] = &[$($tuple),+]; fn load_builtin(target: &str) -> Option { - let mut t = match target { + let t = match target { $( $tuple => targets::$module::target(), )+ _ => return None, }; - t.is_builtin = true; debug!("got builtin target: {:?}", t); Some(t) } @@ -2128,9 +2127,6 @@ type StaticCow = Cow<'static, T>; /// through `Deref` impls. #[derive(PartialEq, Clone, Debug)] pub struct TargetOptions { - /// Whether the target is built-in or loaded from a custom target specification. - pub is_builtin: bool, - /// Used as the `target_endian` `cfg` variable. Defaults to little endian. pub endian: Endian, /// Width of c_int type. Defaults to "32". @@ -2606,7 +2602,6 @@ impl Default for TargetOptions { /// incomplete, and if used for compilation, will certainly not work. fn default() -> TargetOptions { TargetOptions { - is_builtin: false, endian: Endian::Little, c_int_width: "32".into(), os: "none".into(), @@ -3349,7 +3344,6 @@ impl Target { } } - key!(is_builtin, bool); key!(c_int_width = "target-c-int-width"); key!(c_enum_min_bits, Option); // if None, matches c_int_width key!(os); @@ -3462,10 +3456,6 @@ impl Target { key!(entry_abi, Conv)?; key!(supports_xray, bool); - if base.is_builtin { - // This can cause unfortunate ICEs later down the line. - return Err("may not set is_builtin for targets not built-in".into()); - } base.update_from_cli(); // Each field should have been read using `Json::remove` so any keys remaining are unused. @@ -3635,7 +3625,6 @@ impl ToJson for Target { target_val!(arch); target_val!(data_layout); - target_option_val!(is_builtin); target_option_val!(endian, "target-endian"); target_option_val!(c_int_width, "target-c-int-width"); target_option_val!(os); diff --git a/tests/run-make/target-specs/definitely-not-builtin-target.json b/tests/run-make/target-specs/definitely-not-builtin-target.json deleted file mode 100644 index b36fa993d9783..0000000000000 --- a/tests/run-make/target-specs/definitely-not-builtin-target.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "arch": "x86_64", - "is-builtin": true, - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "llvm-target": "x86_64-unknown-unknown-gnu", - "target-pointer-width": "64" -} diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 499c6c2079a9d..79c888ab3406a 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -52,11 +52,6 @@ fn main() { .expected_file("test-platform.json") .actual_text("test-platform-2", test_platform_2) .run(); - rustc() - .input("foo.rs") - .target("definitely-not-builtin-target") - .run_fail() - .assert_stderr_contains("may not set is_builtin"); rustc() .input("foo.rs") .target("endianness-mismatch") From efaf9ab430125a960d5e1f010982ebac34800920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Sun, 3 Nov 2024 22:03:13 +0100 Subject: [PATCH 5/5] remove attribute ids from hir stats (they're simply not needed) --- compiler/rustc_passes/src/hir_stats.rs | 156 ++++++++++++------------- 1 file changed, 76 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 27714a0fdcca0..55fdbac8ad67a 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -3,7 +3,7 @@ // completely accurate (some things might be counted twice, others missed). use rustc_ast::visit::BoundKind; -use rustc_ast::{self as ast, AttrId, NodeId, visit as ast_visit}; +use rustc_ast::{self as ast, NodeId, visit as ast_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::{HirId, intravisit as hir_visit}; @@ -13,13 +13,6 @@ use rustc_middle::util::common::to_readable_str; use rustc_span::Span; use rustc_span::def_id::LocalDefId; -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -enum Id { - Node(HirId), - Attr(AttrId), - None, -} - struct NodeStats { count: usize, size: usize, @@ -62,7 +55,7 @@ impl Node { struct StatCollector<'k> { krate: Option>, nodes: FxHashMap<&'static str, Node>, - seen: FxHashSet, + seen: FxHashSet, } pub fn print_hir_stats(tcx: TyCtxt<'_>) { @@ -87,12 +80,18 @@ pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) { impl<'k> StatCollector<'k> { // Record a top-level node. - fn record(&mut self, label: &'static str, id: Id, val: &T) { + fn record(&mut self, label: &'static str, id: Option, val: &T) { self.record_inner(label, None, id, val); } // Record a two-level entry, with a top-level enum type and a variant. - fn record_variant(&mut self, label1: &'static str, label2: &'static str, id: Id, val: &T) { + fn record_variant( + &mut self, + label1: &'static str, + label2: &'static str, + id: Option, + val: &T, + ) { self.record_inner(label1, Some(label2), id, val); } @@ -100,10 +99,10 @@ impl<'k> StatCollector<'k> { &mut self, label1: &'static str, label2: Option<&'static str>, - id: Id, + id: Option, val: &T, ) { - if id != Id::None && !self.seen.insert(id) { + if id.is_some_and(|x| !self.seen.insert(x)) { return; } @@ -191,7 +190,7 @@ macro_rules! record_variants { impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_param(&mut self, param: &'v hir::Param<'v>) { - self.record("Param", Id::Node(param.hir_id), param); + self.record("Param", Some(param.hir_id), param); hir_visit::walk_param(self, param) } @@ -221,7 +220,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_item(&mut self, i: &'v hir::Item<'v>) { - record_variants!((self, i, i.kind, Id::Node(i.hir_id()), hir, Item, ItemKind), [ + record_variants!((self, i, i.kind, Some(i.hir_id()), hir, Item, ItemKind), [ ExternCrate, Use, Static, @@ -243,47 +242,46 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_body(&mut self, b: &hir::Body<'v>) { - self.record("Body", Id::None, b); + self.record("Body", None, b); hir_visit::walk_body(self, b); } fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) { - self.record("Mod", Id::None, m); + self.record("Mod", None, m); hir_visit::walk_mod(self, m, n) } fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { - record_variants!( - (self, i, i.kind, Id::Node(i.hir_id()), hir, ForeignItem, ForeignItemKind), - [Fn, Static, Type] - ); + record_variants!((self, i, i.kind, Some(i.hir_id()), hir, ForeignItem, ForeignItemKind), [ + Fn, Static, Type + ]); hir_visit::walk_foreign_item(self, i) } fn visit_local(&mut self, l: &'v hir::LetStmt<'v>) { - self.record("Local", Id::Node(l.hir_id), l); + self.record("Local", Some(l.hir_id), l); hir_visit::walk_local(self, l) } fn visit_block(&mut self, b: &'v hir::Block<'v>) { - self.record("Block", Id::Node(b.hir_id), b); + self.record("Block", Some(b.hir_id), b); hir_visit::walk_block(self, b) } fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { - record_variants!((self, s, s.kind, Id::Node(s.hir_id), hir, Stmt, StmtKind), [ + record_variants!((self, s, s.kind, Some(s.hir_id), hir, Stmt, StmtKind), [ Let, Item, Expr, Semi ]); hir_visit::walk_stmt(self, s) } fn visit_arm(&mut self, a: &'v hir::Arm<'v>) { - self.record("Arm", Id::Node(a.hir_id), a); + self.record("Arm", Some(a.hir_id), a); hir_visit::walk_arm(self, a) } fn visit_pat(&mut self, p: &'v hir::Pat<'v>) { - record_variants!((self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind), [ + record_variants!((self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind), [ Wild, Binding, Struct, @@ -304,12 +302,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_pat_field(&mut self, f: &'v hir::PatField<'v>) { - self.record("PatField", Id::Node(f.hir_id), f); + self.record("PatField", Some(f.hir_id), f); hir_visit::walk_pat_field(self, f) } fn visit_expr(&mut self, e: &'v hir::Expr<'v>) { - record_variants!((self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind), [ + record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [ ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err @@ -318,12 +316,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) { - self.record("ExprField", Id::Node(f.hir_id), f); + self.record("ExprField", Some(f.hir_id), f); hir_visit::walk_expr_field(self, f) } fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { - record_variants!((self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind), [ + record_variants!((self, t, t.kind, Some(t.hir_id), hir, Ty, TyKind), [ InferDelegation, Slice, Array, @@ -345,17 +343,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - self.record("GenericParam", Id::Node(p.hir_id), p); + self.record("GenericParam", Some(p.hir_id), p); hir_visit::walk_generic_param(self, p) } fn visit_generics(&mut self, g: &'v hir::Generics<'v>) { - self.record("Generics", Id::None, g); + self.record("Generics", None, g); hir_visit::walk_generics(self, g) } fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) { - record_variants!((self, p, p, Id::None, hir, WherePredicate, WherePredicate), [ + record_variants!((self, p, p, None, hir, WherePredicate, WherePredicate), [ BoundPredicate, RegionPredicate, EqPredicate @@ -371,66 +369,64 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { _: Span, id: LocalDefId, ) { - self.record("FnDecl", Id::None, fd); + self.record("FnDecl", None, fd); hir_visit::walk_fn(self, fk, fd, b, id) } fn visit_use(&mut self, p: &'v hir::UsePath<'v>, hir_id: HirId) { // This is `visit_use`, but the type is `Path` so record it that way. - self.record("Path", Id::None, p); + self.record("Path", None, p); hir_visit::walk_use(self, p, hir_id) } fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) { - record_variants!( - (self, ti, ti.kind, Id::Node(ti.hir_id()), hir, TraitItem, TraitItemKind), - [Const, Fn, Type] - ); + record_variants!((self, ti, ti.kind, Some(ti.hir_id()), hir, TraitItem, TraitItemKind), [ + Const, Fn, Type + ]); hir_visit::walk_trait_item(self, ti) } fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemRef) { - self.record("TraitItemRef", Id::Node(ti.id.hir_id()), ti); + self.record("TraitItemRef", Some(ti.id.hir_id()), ti); hir_visit::walk_trait_item_ref(self, ti) } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { - record_variants!( - (self, ii, ii.kind, Id::Node(ii.hir_id()), hir, ImplItem, ImplItemKind), - [Const, Fn, Type] - ); + record_variants!((self, ii, ii.kind, Some(ii.hir_id()), hir, ImplItem, ImplItemKind), [ + Const, Fn, Type + ]); hir_visit::walk_impl_item(self, ii) } fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemRef) { - self.record("ForeignItemRef", Id::Node(fi.id.hir_id()), fi); + self.record("ForeignItemRef", Some(fi.id.hir_id()), fi); hir_visit::walk_foreign_item_ref(self, fi) } fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemRef) { - self.record("ImplItemRef", Id::Node(ii.id.hir_id()), ii); + self.record("ImplItemRef", Some(ii.id.hir_id()), ii); hir_visit::walk_impl_item_ref(self, ii) } fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) { - record_variants!((self, b, b, Id::None, hir, GenericBound, GenericBound), [ + record_variants!((self, b, b, None, hir, GenericBound, GenericBound), [ Trait, Outlives, Use ]); hir_visit::walk_param_bound(self, b) } fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) { - self.record("FieldDef", Id::Node(s.hir_id), s); + self.record("FieldDef", Some(s.hir_id), s); hir_visit::walk_field_def(self, s) } fn visit_variant(&mut self, v: &'v hir::Variant<'v>) { - self.record("Variant", Id::None, v); + self.record("Variant", None, v); hir_visit::walk_variant(self, v) } fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) { - record_variants!((self, ga, ga, Id::Node(ga.hir_id()), hir, GenericArg, GenericArg), [ + record_variants!((self, ga, ga, Some(ga.hir_id()), hir, GenericArg, GenericArg), [ Lifetime, Type, Const, Infer ]); match ga { @@ -442,50 +438,50 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { - self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime); + self.record("Lifetime", Some(lifetime.hir_id), lifetime); hir_visit::walk_lifetime(self, lifetime) } fn visit_path(&mut self, path: &hir::Path<'v>, _id: HirId) { - self.record("Path", Id::None, path); + self.record("Path", None, path); hir_visit::walk_path(self, path) } fn visit_path_segment(&mut self, path_segment: &'v hir::PathSegment<'v>) { - self.record("PathSegment", Id::None, path_segment); + self.record("PathSegment", None, path_segment); hir_visit::walk_path_segment(self, path_segment) } fn visit_generic_args(&mut self, ga: &'v hir::GenericArgs<'v>) { - self.record("GenericArgs", Id::None, ga); + self.record("GenericArgs", None, ga); hir_visit::walk_generic_args(self, ga) } fn visit_assoc_item_constraint(&mut self, constraint: &'v hir::AssocItemConstraint<'v>) { - self.record("AssocItemConstraint", Id::Node(constraint.hir_id), constraint); + self.record("AssocItemConstraint", Some(constraint.hir_id), constraint); hir_visit::walk_assoc_item_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { - self.record("Attribute", Id::Attr(attr.id), attr); + self.record("Attribute", None, attr); } fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) { - self.record("InlineAsm", Id::None, asm); + self.record("InlineAsm", None, asm); hir_visit::walk_inline_asm(self, asm, id); } } impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { - record_variants!((self, i, i.kind, Id::None, ast, ForeignItem, ForeignItemKind), [ + record_variants!((self, i, i.kind, None, ast, ForeignItem, ForeignItemKind), [ Static, Fn, TyAlias, MacCall ]); ast_visit::walk_item(self, i) } fn visit_item(&mut self, i: &'v ast::Item) { - record_variants!((self, i, i.kind, Id::None, ast, Item, ItemKind), [ + record_variants!((self, i, i.kind, None, ast, Item, ItemKind), [ ExternCrate, Use, Static, @@ -510,34 +506,34 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_local(&mut self, l: &'v ast::Local) { - self.record("Local", Id::None, l); + self.record("Local", None, l); ast_visit::walk_local(self, l) } fn visit_block(&mut self, b: &'v ast::Block) { - self.record("Block", Id::None, b); + self.record("Block", None, b); ast_visit::walk_block(self, b) } fn visit_stmt(&mut self, s: &'v ast::Stmt) { - record_variants!((self, s, s.kind, Id::None, ast, Stmt, StmtKind), [ + record_variants!((self, s, s.kind, None, ast, Stmt, StmtKind), [ Let, Item, Expr, Semi, Empty, MacCall ]); ast_visit::walk_stmt(self, s) } fn visit_param(&mut self, p: &'v ast::Param) { - self.record("Param", Id::None, p); + self.record("Param", None, p); ast_visit::walk_param(self, p) } fn visit_arm(&mut self, a: &'v ast::Arm) { - self.record("Arm", Id::None, a); + self.record("Arm", None, a); ast_visit::walk_arm(self, a) } fn visit_pat(&mut self, p: &'v ast::Pat) { - record_variants!((self, p, p.kind, Id::None, ast, Pat, PatKind), [ + record_variants!((self, p, p.kind, None, ast, Pat, PatKind), [ Wild, Ident, Struct, @@ -563,7 +559,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_expr(&mut self, e: &'v ast::Expr) { #[rustfmt::skip] record_variants!( - (self, e, e.kind, Id::None, ast, Expr, ExprKind), + (self, e, e.kind, None, ast, Expr, ExprKind), [ Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, @@ -576,7 +572,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_ty(&mut self, t: &'v ast::Ty) { - record_variants!((self, t, t.kind, Id::None, ast, Ty, TyKind), [ + record_variants!((self, t, t.kind, None, ast, Ty, TyKind), [ Slice, Array, Ptr, @@ -603,12 +599,12 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_generic_param(&mut self, g: &'v ast::GenericParam) { - self.record("GenericParam", Id::None, g); + self.record("GenericParam", None, g); ast_visit::walk_generic_param(self, g) } fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) { - record_variants!((self, p, p, Id::None, ast, WherePredicate, WherePredicate), [ + record_variants!((self, p, p, None, ast, WherePredicate, WherePredicate), [ BoundPredicate, RegionPredicate, EqPredicate @@ -617,12 +613,12 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: Span, _: NodeId) { - self.record("FnDecl", Id::None, fk.decl()); + self.record("FnDecl", None, fk.decl()); ast_visit::walk_fn(self, fk) } fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { - record_variants!((self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind), [ + record_variants!((self, i, i.kind, None, ast, AssocItem, AssocItemKind), [ Const, Fn, Type, @@ -634,19 +630,19 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) { - record_variants!((self, b, b, Id::None, ast, GenericBound, GenericBound), [ + record_variants!((self, b, b, None, ast, GenericBound, GenericBound), [ Trait, Outlives, Use ]); ast_visit::walk_param_bound(self, b) } fn visit_field_def(&mut self, s: &'v ast::FieldDef) { - self.record("FieldDef", Id::None, s); + self.record("FieldDef", None, s); ast_visit::walk_field_def(self, s) } fn visit_variant(&mut self, v: &'v ast::Variant) { - self.record("Variant", Id::None, v); + self.record("Variant", None, v); ast_visit::walk_variant(self, v) } @@ -660,7 +656,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { // common than the former case, so we implement this visitor and tolerate // the double counting in the former case. fn visit_path_segment(&mut self, path_segment: &'v ast::PathSegment) { - self.record("PathSegment", Id::None, path_segment); + self.record("PathSegment", None, path_segment); ast_visit::walk_path_segment(self, path_segment) } @@ -669,7 +665,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { // common, so we implement `visit_generic_args` and tolerate the double // counting in the former case. fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) { - record_variants!((self, g, g, Id::None, ast, GenericArgs, GenericArgs), [ + record_variants!((self, g, g, None, ast, GenericArgs, GenericArgs), [ AngleBracketed, Parenthesized, ParenthesizedElided @@ -678,24 +674,24 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { - record_variants!((self, attr, attr.kind, Id::None, ast, Attribute, AttrKind), [ + record_variants!((self, attr, attr.kind, None, ast, Attribute, AttrKind), [ Normal, DocComment ]); ast_visit::walk_attribute(self, attr) } fn visit_expr_field(&mut self, f: &'v ast::ExprField) { - self.record("ExprField", Id::None, f); + self.record("ExprField", None, f); ast_visit::walk_expr_field(self, f) } fn visit_crate(&mut self, krate: &'v ast::Crate) { - self.record("Crate", Id::None, krate); + self.record("Crate", None, krate); ast_visit::walk_crate(self, krate) } fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) { - self.record("InlineAsm", Id::None, asm); + self.record("InlineAsm", None, asm); ast_visit::walk_inline_asm(self, asm) } }