From 436e4fb647bca08bd5cb7eea6f8450bb56515c10 Mon Sep 17 00:00:00 2001 From: Flakebi Date: Thu, 2 Jan 2025 13:10:11 +0100 Subject: [PATCH 01/12] Cast global variables to default address space Pointers for variables all need to be in the same address space for correct compilation. Therefore ensure that even if a global variable is created in a different address space, it is casted to the default address space before its value is used. This is necessary for the amdgpu target and others where the default address space for global variables is not 0. For example `core` does not compile in debug mode when not casting the address space to the default one because it tries to emit the following (simplified) LLVM IR, containing a type mismatch: ```llvm @alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1 @alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspace(1) @alloc_0 }>, align 8 ; ^ here a struct containing a `ptr` is needed, but it is created using a `ptr addrspace(1)` ``` For this to compile, we need to insert a constant `addrspacecast` before we use a global variable: ```llvm @alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1 @alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspacecast (ptr addrspace(1) @alloc_0 to ptr) }>, align 8 ``` As vtables are global variables as well, they are also created with an `addrspacecast`. In the SSA backend, after a vtable global is created, metadata is added to it. To add metadata, we need the non-casted global variable. Therefore we strip away an addrspacecast if there is one, to get the underlying global. --- compiler/rustc_codegen_llvm/src/builder.rs | 4 +- compiler/rustc_codegen_llvm/src/common.rs | 7 +- compiler/rustc_codegen_llvm/src/consts.rs | 48 ++++++++---- .../src/debuginfo/metadata.rs | 15 ++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 77 +++++++++++++++++++ 5 files changed, 130 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ab0e43e60a4f5..1b99fea8d5154 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1225,7 +1225,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { fn get_static(&mut self, def_id: DefId) -> &'ll Value { // Forward to the `get_static` method of `CodegenCx` - self.cx().get_static(def_id) + let s = self.cx().get_static(def_id); + // Cast to default address space if statics are in a different addrspace + self.cx().const_pointercast(s, self.type_ptr()) } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index adfe8aeb5c539..bd792c02810c6 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -221,6 +221,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); } llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + let g = self.const_pointercast(g, self.type_ptr()); (s.to_owned(), g) }) .1; @@ -285,7 +286,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), + _ => self.static_addr_of_impl(init, alloc.align, None), }; if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() { @@ -311,7 +312,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc, /*static*/ false); - let value = self.static_addr_of(init, alloc.inner().align, None); + let value = self.static_addr_of_impl(init, alloc.inner().align, None); (value, AddressSpace::DATA) } GlobalAlloc::Static(def_id) => { @@ -323,7 +324,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let llval = unsafe { llvm::LLVMConstInBoundsGEP2( self.type_i8(), - self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)), + self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)), &self.const_usize(offset.bytes()), 1, ) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c7114480d8bdf..b88fd133e8e8a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -210,6 +210,10 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMConstBitCast(val, ty) } } + pub(crate) fn const_pointercast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { + unsafe { llvm::LLVMConstPointerCast(val, ty) } + } + pub(crate) fn static_addr_of_mut( &self, cv: &'ll Value, @@ -233,6 +237,31 @@ impl<'ll> CodegenCx<'ll, '_> { gv } + pub(crate) fn static_addr_of_impl( + &self, + cv: &'ll Value, + align: Align, + kind: Option<&str>, + ) -> &'ll Value { + if let Some(&gv) = self.const_globals.borrow().get(&cv) { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + let llalign = align.bytes() as u32; + if llalign > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, llalign); + } + } + return gv; + } + let gv = self.static_addr_of_mut(cv, align, kind); + unsafe { + llvm::LLVMSetGlobalConstant(gv, True); + } + self.const_globals.borrow_mut().insert(cv, gv); + gv + } + #[instrument(level = "debug", skip(self))] pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value { let instance = Instance::mono(self.tcx, def_id); @@ -506,23 +535,8 @@ impl<'ll> CodegenCx<'ll, '_> { impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { - if let Some(&gv) = self.const_globals.borrow().get(&cv) { - unsafe { - // Upgrade the alignment in cases where the same constant is used with different - // alignment requirements - let llalign = align.bytes() as u32; - if llalign > llvm::LLVMGetAlignment(gv) { - llvm::LLVMSetAlignment(gv, llalign); - } - } - return gv; - } - let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } - self.const_globals.borrow_mut().insert(cv, gv); - gv + let gv = self.static_addr_of_impl(cv, align, kind); + self.const_pointercast(gv, self.type_ptr()) } fn codegen_static(&self, def_id: DefId) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 40248a9009ae7..e4da540da5cd3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1500,6 +1500,18 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } +fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value { + // The vtable is a global variable, which may be behind an addrspacecast. + unsafe { + if let Some(c) = llvm::LLVMIsAConstantExpr(vtable) { + if llvm::LLVMGetConstOpcode(c) == llvm::Opcode::AddrSpaceCast { + return llvm::LLVMGetOperand(c, 0).unwrap(); + } + } + } + vtable +} + pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, @@ -1520,6 +1532,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let Some(trait_ref) = trait_ref else { return }; + let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); let trait_ref_self = cx.tcx.erase_regions(trait_ref_self); let trait_def_id = trait_ref_self.def_id(); @@ -1593,6 +1606,8 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( return; } + let vtable = find_vtable_behind_cast(vtable); + // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 472d4a3a72b3f..8ae9c1e501706 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -660,6 +660,79 @@ pub enum MemoryEffects { InaccessibleMemOnly, } +/// LLVMOpcode +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub enum Opcode { + Ret = 1, + Br = 2, + Switch = 3, + IndirectBr = 4, + Invoke = 5, + Unreachable = 7, + CallBr = 67, + FNeg = 66, + Add = 8, + FAdd = 9, + Sub = 10, + FSub = 11, + Mul = 12, + FMul = 13, + UDiv = 14, + SDiv = 15, + FDiv = 16, + URem = 17, + SRem = 18, + FRem = 19, + Shl = 20, + LShr = 21, + AShr = 22, + And = 23, + Or = 24, + Xor = 25, + Alloca = 26, + Load = 27, + Store = 28, + GetElementPtr = 29, + Trunc = 30, + ZExt = 31, + SExt = 32, + FPToUI = 33, + FPToSI = 34, + UIToFP = 35, + SIToFP = 36, + FPTrunc = 37, + FPExt = 38, + PtrToInt = 39, + IntToPtr = 40, + BitCast = 41, + AddrSpaceCast = 60, + ICmp = 42, + FCmp = 43, + PHI = 44, + Call = 45, + Select = 46, + UserOp1 = 47, + UserOp2 = 48, + VAArg = 49, + ExtractElement = 50, + InsertElement = 51, + ShuffleVector = 52, + ExtractValue = 53, + InsertValue = 54, + Freeze = 68, + Fence = 55, + AtomicCmpXchg = 56, + AtomicRMW = 57, + Resume = 58, + LandingPad = 59, + CleanupRet = 61, + CatchRet = 62, + CatchPad = 63, + CleanupPad = 64, + CatchSwitch = 65, +} + unsafe extern "C" { type Opaque; } @@ -975,7 +1048,10 @@ unsafe extern "C" { pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; + pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>; + pub fn LLVMGetConstOpcode(ConstantVal: &Value) -> Opcode; + pub fn LLVMIsAConstantExpr(Val: &Value) -> Option<&Value>; // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; @@ -1032,6 +1108,7 @@ unsafe extern "C" { // Operations on instructions pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>; pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock; + pub fn LLVMGetOperand(Val: &Value, Index: c_uint) -> Option<&Value>; // Operations on call sites pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint); From c1790b14bcd62df7bccdfa7d7fbe4533dfdcdc8c Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 14 Jan 2025 11:40:22 +0530 Subject: [PATCH 02/12] uefi: Implement path UEFI paths can be of 4 types: 1. Absolute Shell Path: Uses shell mappings 2. Absolute Device Path: this is what we want 3: Relative root: path relative to the current root. 4: Relative Absolute shell path can be identified with `:` and Absolute Device path can be identified with `/`. Relative root path will start with `\`. The algorithm is mostly taken from edk2 UEFI shell implementation and is somewhat simple. Check for the path type in order. For Absolute Shell path, use `EFI_SHELL->GetDevicePathFromMap` to get a BorrowedDevicePath for the volume. For Relative paths, we use the current working directory to construct the new path. BorrowedDevicePath abstraction is needed to interact with `EFI_SHELL->GetDevicePathFromMap` which returns a Device Path Protocol with the lifetime of UEFI shell. Absolute Shell paths cannot exist if UEFI shell is missing. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 50 ++++++++++- library/std/src/sys/path/mod.rs | 8 +- library/std/src/sys/path/uefi.rs | 105 ++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 library/std/src/sys/path/uefi.rs diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 7504a0f7ad7f5..dccc137d6f561 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -14,10 +14,12 @@ use r_efi::protocols::{device_path, device_path_to_text, shell}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; +use crate::marker::PhantomData; use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::os::uefi::{self}; +use crate::path::Path; use crate::ptr::NonNull; use crate::slice; use crate::sync::atomic::{AtomicPtr, Ordering}; @@ -278,6 +280,10 @@ impl OwnedDevicePath { pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { self.0.as_ptr() } + + pub(crate) const fn borrow<'a>(&'a self) -> BorrowedDevicePath<'a> { + BorrowedDevicePath::new(self.0) + } } impl Drop for OwnedDevicePath { @@ -293,13 +299,37 @@ impl Drop for OwnedDevicePath { impl crate::fmt::Debug for OwnedDevicePath { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - match device_path_to_text(self.0) { + match self.borrow().to_text() { Ok(p) => p.fmt(f), Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(), } } } +pub(crate) struct BorrowedDevicePath<'a> { + protocol: NonNull, + phantom: PhantomData<&'a r_efi::protocols::device_path::Protocol>, +} + +impl<'a> BorrowedDevicePath<'a> { + pub(crate) const fn new(protocol: NonNull) -> Self { + Self { protocol, phantom: PhantomData } + } + + pub(crate) fn to_text(&self) -> io::Result { + device_path_to_text(self.protocol) + } +} + +impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + match self.to_text() { + Ok(p) => p.fmt(f), + Err(_) => f.debug_struct("BorrowedDevicePath").finish_non_exhaustive(), + } + } +} + pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, @@ -452,3 +482,21 @@ pub(crate) fn open_shell() -> Option> { None } + +/// Get device path protocol associated with shell mapping. +/// +/// returns None in case no such mapping is exists +pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result> { + let shell = + open_shell().ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell not found"))?; + let mut path = os_string_to_raw(map.as_os_str()) + .ok_or(io::const_error!(io::ErrorKind::InvalidFilename, "Invalid UEFI shell mapping"))?; + + // The Device Path Protocol pointer returned by UEFI shell is owned by the shell and is not + // freed throughout it's lifetime. So it has a 'static lifetime. + let protocol = unsafe { ((*shell.as_ptr()).get_device_path_from_map)(path.as_mut_ptr()) }; + let protocol = NonNull::new(protocol) + .ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell mapping not found"))?; + + Ok(BorrowedDevicePath::new(protocol)) +} diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index 24a94ec782824..1fa4e80d6780c 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -5,12 +5,12 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::*; - } else if #[cfg(any( - target_os = "uefi", - target_os = "solid_asp3", - ))] { + } else if #[cfg(target_os = "solid_asp3")] { mod unsupported_backslash; pub use unsupported_backslash::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; } else { mod unix; pub use unix::*; diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs new file mode 100644 index 0000000000000..a3f4a3bfe1b67 --- /dev/null +++ b/library/std/src/sys/path/uefi.rs @@ -0,0 +1,105 @@ +#![forbid(unsafe_op_in_unsafe_fn)] +use crate::ffi::OsStr; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::{helpers, unsupported_err}; + +const FORWARD_SLASH: u8 = b'/'; +const COLON: u8 = b':'; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; + +/// UEFI paths can be of 4 types: +/// +/// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present. +/// It can be identified with `:`. +/// Eg: FS0:\abc\run.efi +/// +/// 2. Absolute Device Path: this is what we want +/// It can be identified with `/`. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +/// +/// 3: Relative root: path relative to the current volume. +/// It will start with `\`. +/// Eg: \abc\run.efi +/// +/// 4: Relative +/// Eg: run.efi +/// +/// The algorithm is mostly taken from edk2 UEFI shell implementation and is +/// somewhat simple. Check for the path type in order. +/// +/// The volume mapping in Absolute Shell Path (not the rest of the path) can be converted to Device +/// Path Protocol using `EFI_SHELL->GetDevicePathFromMap`. The rest of the path (Relative root +/// path), can just be appended to the remaining path. +/// +/// For Relative root, we get the current volume (either in Shell Mapping, or Device Path Protocol +/// form) and join it with the relative root path. We then recurse the function to resolve the Shell +/// Mapping if present. +/// +/// For Relative paths, we use the current working directory to construct +/// the new path and recurse the function to resolve the Shell mapping if present. +/// +/// Finally, at the end, we get the 2nd form, i.e. Absolute Device Path, which can be used in the +/// normal UEFI APIs such as file, process, etc. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +pub(crate) fn absolute(path: &Path) -> io::Result { + // Absolute Shell Path + if path.as_os_str().as_encoded_bytes().contains(&COLON) { + let mut path_components = path.components(); + // Since path is not empty, it has at least one Component + let prefix = path_components.next().unwrap(); + + let dev_path = helpers::get_device_path_from_map(prefix.as_ref())?; + let mut dev_path_text = dev_path.to_text().map_err(|_| unsupported_err())?; + + // UEFI Shell does not seem to end device path with `/` + if *dev_path_text.as_encoded_bytes().last().unwrap() != FORWARD_SLASH { + dev_path_text.push("/"); + } + + let mut ans = PathBuf::from(dev_path_text); + ans.push(path_components); + + return Ok(ans); + } + + // Absolute Device Path + if path.as_os_str().as_encoded_bytes().contains(&FORWARD_SLASH) { + return Ok(path.to_path_buf()); + } + + // cur_dir() always returns something + let cur_dir = crate::env::current_dir().unwrap(); + let mut path_components = path.components(); + + // Relative Root + if path_components.next().unwrap() == crate::path::Component::RootDir { + let mut ans = PathBuf::new(); + ans.push(cur_dir.components().next().unwrap()); + ans.push(path_components); + return absolute(&ans); + } + + absolute(&cur_dir.join(path)) +} + +pub(crate) fn is_absolute(path: &Path) -> bool { + let temp = path.as_os_str().as_encoded_bytes(); + temp.contains(&COLON) || temp.contains(&FORWARD_SLASH) +} From cc19dfa125e280545e6e599f1aaf27ffb0c55ffd Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 22 Jan 2025 00:20:54 +0100 Subject: [PATCH 03/12] Add `AsyncFn*` to core prelude --- library/core/src/prelude/common.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index e38ef1e147c76..8b116cecb5295 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[stable(feature = "async_closure", since = "1.85.0")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "core_prelude", since = "1.4.0")] From b06e840d9e8e27ac1f79be5e6d2778455146f665 Mon Sep 17 00:00:00 2001 From: Flakebi Date: Fri, 24 Jan 2025 00:37:05 +0100 Subject: [PATCH 04/12] Add comments about address spaces --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/common.rs | 2 ++ compiler/rustc_codegen_llvm/src/consts.rs | 13 +++++++++++++ .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 10 ++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 1b99fea8d5154..4d572dc56fb21 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1226,7 +1226,7 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { fn get_static(&mut self, def_id: DefId) -> &'ll Value { // Forward to the `get_static` method of `CodegenCx` let s = self.cx().get_static(def_id); - // Cast to default address space if statics are in a different addrspace + // Cast to default address space if globals are in a different addrspace self.cx().const_pointercast(s, self.type_ptr()) } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index bd792c02810c6..5031df06b05b0 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -221,6 +221,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); } llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); (s.to_owned(), g) }) @@ -324,6 +325,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let llval = unsafe { llvm::LLVMConstInBoundsGEP2( self.type_i8(), + // Cast to the required address space if necessary self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)), &self.const_usize(offset.bytes()), 1, diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index b88fd133e8e8a..771ebf2057f9a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -214,6 +214,10 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMConstPointerCast(val, ty) } } + /// Create a global variable. + /// + /// The returned global variable is a pointer in the default address space for globals. + /// Fails if a symbol with the given name already exists. pub(crate) fn static_addr_of_mut( &self, cv: &'ll Value, @@ -237,6 +241,9 @@ impl<'ll> CodegenCx<'ll, '_> { gv } + /// Create a global constant. + /// + /// The returned global variable is a pointer in the default address space for globals. pub(crate) fn static_addr_of_impl( &self, cv: &'ll Value, @@ -534,8 +541,14 @@ impl<'ll> CodegenCx<'ll, '_> { } impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { + /// Get a pointer to a global variable. + /// + /// The pointer will always be in the default address space. If global variables default to a + /// different address space, an addrspacecast is inserted. fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { let gv = self.static_addr_of_impl(cv, align, kind); + // static_addr_of_impl returns the bare global variable, which might not be in the default + // address space. Cast to the default address space if necessary. self.const_pointercast(gv, self.type_ptr()) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index e4da540da5cd3..b9e3a6975d658 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1500,6 +1500,14 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } +/// Get the global variable for the vtable. +/// +/// When using global variables, we may have created an addrspacecast to get a pointer to the +/// default address space if global variables are created in a different address space. +/// For modifying the vtable, we need the real global variable. This function accepts either a +/// global variable (which is simply returned), or an addrspacecast constant expression. +/// If the given value is an addrspacecast, the cast is removed and the global variable behind +/// the cast is returned. fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value { // The vtable is a global variable, which may be behind an addrspacecast. unsafe { @@ -1532,6 +1540,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let Some(trait_ref) = trait_ref else { return }; + // Unwrap potential addrspacecast let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); let trait_ref_self = cx.tcx.erase_regions(trait_ref_self); @@ -1606,6 +1615,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( return; } + // Unwrap potential addrspacecast let vtable = find_vtable_behind_cast(vtable); // When full debuginfo is enabled, we want to try and prevent vtables from being From b7916fb4b762d406a560c5e5f6e632033edd9c14 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Thu, 23 Jan 2025 21:25:26 -0500 Subject: [PATCH 05/12] tests: Skip const OOM tests on aarch64-unknown-linux-gnu Skip const OOM tests on AArch64 Linux through explicit annotations instead of inside opt-dist. Intended to avoid confusion in cases like #135952. Prerequisite for https://github.com/rust-lang/rust/pull/135960. --- src/tools/opt-dist/src/main.rs | 12 +----------- tests/ui/consts/large_const_alloc.rs | 2 ++ tests/ui/consts/large_const_alloc.stderr | 4 ++-- .../promoted_running_out_of_memory_issue-130687.rs | 2 ++ ...romoted_running_out_of_memory_issue-130687.stderr | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 04de3493ea29c..565721a909344 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -148,16 +148,6 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> let is_aarch64 = target_triple.starts_with("aarch64"); - let skip_tests = if is_aarch64 { - vec![ - // Those tests fail only inside of Docker on aarch64, as of December 2024 - "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(), - "tests/ui/consts/large_const_alloc.rs".to_string(), - ] - } else { - vec![] - }; - let checkout_dir = Utf8PathBuf::from("/checkout"); let env = EnvironmentBuilder::default() .host_tuple(target_triple) @@ -169,7 +159,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec)> .shared_llvm(true) // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024. .use_bolt(!is_aarch64) - .skipped_tests(skip_tests) + .skipped_tests(vec![]) .build()?; (env, shared.build_args) diff --git a/tests/ui/consts/large_const_alloc.rs b/tests/ui/consts/large_const_alloc.rs index 61a22216ae526..14edc1bb69610 100644 --- a/tests/ui/consts/large_const_alloc.rs +++ b/tests/ui/consts/large_const_alloc.rs @@ -1,5 +1,7 @@ //@ only-64bit // on 32bit and 16bit platforms it is plausible that the maximum allocation size will succeed +// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger +//@ ignore-aarch64-unknown-linux-gnu const FOO: () = { // 128 TiB, unlikely anyone has that much RAM diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr index 25d660f1217f4..fa7d5977a9567 100644 --- a/tests/ui/consts/large_const_alloc.stderr +++ b/tests/ui/consts/large_const_alloc.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/large_const_alloc.rs:6:13 + --> $DIR/large_const_alloc.rs:8:13 | LL | let x = [0_u8; (1 << 47) - 1]; | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler error[E0080]: could not evaluate static initializer - --> $DIR/large_const_alloc.rs:11:13 + --> $DIR/large_const_alloc.rs:13:13 | LL | let x = [0_u8; (1 << 47) - 1]; | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs index b923a768cbfe5..53618e2e86acd 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -3,6 +3,8 @@ // Needs the max type size to be much bigger than the RAM people typically have. //@ only-64bit +// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger +//@ ignore-aarch64-unknown-linux-gnu pub struct Data([u8; (1 << 47) - 1]); const _: &'static Data = &Data([0; (1 << 47) - 1]); diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr index f5d767efceb76..aac805dbd8c79 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32 + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:10:32 | LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); | ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler From 869bc2fded5e8b9332001da5a1ea252ca5f4f9ad Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 28 Jan 2025 00:51:33 +0300 Subject: [PATCH 06/12] override build profile for bootstrap tests Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 3 +++ src/bootstrap/src/core/builder/cargo.rs | 28 +++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0d3ab6ad97d31..505a6ef3e3481 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -86,6 +86,7 @@ impl Step for CrateBootstrap { SourceType::InTree, &[], ); + let crate_name = path.rsplit_once('/').unwrap().1; run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder); } @@ -3099,6 +3100,8 @@ impl Step for Bootstrap { &[], ); + cargo.release_build(false); + cargo .rustflag("-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 6b792108784d9..4059aa6bcd28d 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -88,12 +88,14 @@ impl HostFlags { #[derive(Debug)] pub struct Cargo { command: BootstrapCommand, + args: Vec, compiler: Compiler, target: TargetSelection, rustflags: Rustflags, rustdocflags: Rustflags, hostflags: HostFlags, allow_features: String, + release_build: bool, } impl Cargo { @@ -121,6 +123,10 @@ impl Cargo { cargo } + pub fn release_build(&mut self, release_build: bool) { + self.release_build = release_build; + } + pub fn compiler(&self) -> Compiler { self.compiler } @@ -153,7 +159,7 @@ impl Cargo { } pub fn arg(&mut self, arg: impl AsRef) -> &mut Cargo { - self.command.arg(arg.as_ref()); + self.args.push(arg.as_ref().into()); self } @@ -335,6 +341,12 @@ impl Cargo { impl From for BootstrapCommand { fn from(mut cargo: Cargo) -> BootstrapCommand { + if cargo.release_build { + cargo.args.insert(0, "--release".into()); + } + + cargo.command.args(cargo.args); + let rustflags = &cargo.rustflags.0; if !rustflags.is_empty() { cargo.command.env("RUSTFLAGS", rustflags); @@ -353,6 +365,7 @@ impl From for BootstrapCommand { if !cargo.allow_features.is_empty() { cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features); } + cargo.command } } @@ -422,13 +435,6 @@ impl Builder<'_> { assert_eq!(target, compiler.host); } - if self.config.rust_optimize.is_release() && - // cargo bench/install do not accept `--release` and miri doesn't want it - !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest) - { - cargo.arg("--release"); - } - // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); cargo.env_remove("MFLAGS"); @@ -1214,14 +1220,20 @@ impl Builder<'_> { rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); } + let release_build = self.config.rust_optimize.is_release() && + // cargo bench/install do not accept `--release` and miri doesn't want it + !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest); + Cargo { command: cargo, + args: vec![], compiler, target, rustflags, rustdocflags, hostflags, allow_features, + release_build, } } } From e4db6d7825cc22991f2c73623c39c457e86a1600 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 27 Jan 2025 13:55:21 -0800 Subject: [PATCH 07/12] Add release notes for 1.84.1 --- RELEASES.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 2da6ed3f10060..e0175db7ec881 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,18 @@ +Version 1.84.1 (2025-01-30) +========================== + + + +- [Fix ICE 132920 in duplicate-crate diagnostics.](https://github.com/rust-lang/rust/pull/133304/) +- [Fix errors for overlapping impls in incremental rebuilds.](https://github.com/rust-lang/rust/pull/133828/) +- [Fix slow compilation related to the next-generation trait solver.](https://github.com/rust-lang/rust/pull/135618/) +- [Fix debuginfo when LLVM's location discriminator value limit is exceeded.](https://github.com/rust-lang/rust/pull/135643/) +- Fixes for building Rust from source: + - [Only try to distribute `llvm-objcopy` if llvm tools are enabled.](https://github.com/rust-lang/rust/pull/134240/) + - [Add Profile Override for Non-Git Sources.](https://github.com/rust-lang/rust/pull/135433/) + - [Resolve symlinks of LLVM tool binaries before copying them.](https://github.com/rust-lang/rust/pull/135585/) + - [Make it possible to use ci-rustc on tarball sources.](https://github.com/rust-lang/rust/pull/135722/) + Version 1.84.0 (2025-01-09) ========================== From b320e1741c738363184c87657f972a739d704908 Mon Sep 17 00:00:00 2001 From: Sky Date: Wed, 29 Jan 2025 20:23:59 -0500 Subject: [PATCH 08/12] Remove minor future footgun in `impl Debug for MaybeUninit` No longer breaks if `MaybeUninit` moves modules (technically it could break if `MaybeUninit` were renamed but realistically that will never happen) --- library/core/src/mem/maybe_uninit.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ac5307a671d20..0d8c3ef906bf0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -276,10 +276,9 @@ impl Clone for MaybeUninit { impl fmt::Debug for MaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>"). - // This needs to be adjusted if `MaybeUninit` moves modules. let full_name = type_name::(); - let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1; - f.pad(short_name) + let prefix_len = full_name.find("MaybeUninit").unwrap(); + f.pad(&full_name[prefix_len..]) } } From fb1ad2fe02dc7d13b6a088b535bd8c293a8085be Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 30 Jan 2025 11:42:19 +0100 Subject: [PATCH 09/12] Improve documentation for file locking Add notes to each method stating that locks get dropped on close. Clarify the return values of the try methods: they're only defined if the lock is held via a *different* file handle/descriptor. That goes along with the documentation that calling them while holding a lock via the *same* file handle/descriptor may deadlock. Document the behavior of unlock if no lock is held. --- library/std/src/fs.rs | 57 ++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 1f8aac48a9a8b..a5b0111adfb4a 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -629,9 +629,9 @@ impl File { /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then an exclusive lock is held. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -639,6 +639,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, @@ -671,19 +674,22 @@ impl File { self.inner.lock() } - /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired. + /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired. /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then a shared lock is held. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, @@ -716,14 +722,18 @@ impl File { self.inner.lock_shared() } - /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked. + /// Try to acquire an exclusive advisory lock on the file. + /// + /// Returns `Ok(false)` if a different lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive + /// lock. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -731,6 +741,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and @@ -764,20 +777,25 @@ impl File { self.inner.try_lock() } - /// Acquire a shared advisory lock on the file. - /// Returns `Ok(false)` if the file is exclusively locked. + /// Try to acquire a shared (non-exclusive) advisory lock on the file. + /// + /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// However, if this method returns `Ok(true)`, then it has acquired a shared lock. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and @@ -813,7 +831,12 @@ impl File { /// Release all locks on the file. /// - /// All remaining locks are released when the file handle, and all clones of it, are dropped. + /// All locks are released when the file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed. This method allows releasing locks without + /// closing the file. + /// + /// If no lock is currently held via this file descriptor/handle, this method may return an + /// error, or may return successfully without taking any action. /// /// # Platform-specific behavior /// From 10fc0b159ee6e5281bf38f65680082961dd7bec3 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 27 Jan 2025 04:30:00 +0100 Subject: [PATCH 10/12] introduce `ty::Value` Co-authored-by: FedericoBruzzone --- .../src/intrinsics/simd.rs | 7 +-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- .../src/debuginfo/type_names.rs | 16 +++--- .../rustc_codegen_ssa/src/mir/constant.rs | 2 +- .../src/check_consts/qualifs.rs | 2 +- compiler/rustc_const_eval/src/lib.rs | 9 +++- compiler/rustc_infer/src/infer/freshen.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 22 ++++---- compiler/rustc_middle/src/mir/pretty.rs | 4 +- compiler/rustc_middle/src/query/keys.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 +-- compiler/rustc_middle/src/ty/consts.rs | 38 ++++---------- .../rustc_middle/src/ty/consts/valtree.rs | 51 ++++++++++++++++--- compiler/rustc_middle/src/ty/context.rs | 26 ++++++---- compiler/rustc_middle/src/ty/flags.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 51 +++++++++---------- .../rustc_middle/src/ty/structural_impls.rs | 18 +++---- compiler/rustc_middle/src/ty/walk.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 2 +- .../src/canonicalizer.rs | 2 +- .../rustc_next_trait_solver/src/solve/mod.rs | 6 +-- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 22 ++++---- compiler/rustc_smir/src/rustc_smir/context.rs | 5 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 23 +++------ compiler/rustc_symbol_mangling/src/legacy.rs | 7 +-- compiler/rustc_symbol_mangling/src/v0.rs | 7 +-- .../src/solve/fulfill.rs | 2 +- .../src/traits/const_evaluatable.rs | 2 +- .../src/traits/fulfill.rs | 2 +- .../src/traits/select/mod.rs | 2 +- compiler/rustc_transmute/src/lib.rs | 8 +-- compiler/rustc_ty_utils/src/consts.rs | 6 +-- compiler/rustc_ty_utils/src/layout.rs | 19 +++---- compiler/rustc_type_ir/src/const_kind.rs | 4 +- compiler/rustc_type_ir/src/fast_reject.rs | 4 +- compiler/rustc_type_ir/src/inherent.rs | 5 ++ compiler/rustc_type_ir/src/interner.rs | 3 +- compiler/rustc_type_ir/src/relate.rs | 4 +- src/librustdoc/clean/utils.rs | 6 +-- .../clippy_lints/src/large_const_arrays.rs | 5 +- .../clippy_lints/src/large_stack_arrays.rs | 5 +- src/tools/miri/src/intrinsics/simd.rs | 2 +- 44 files changed, 214 insertions(+), 205 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 6d71b8e8abab4..d682efd19aaa5 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -129,12 +129,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - let idx = generic_args[2] - .expect_const() - .try_to_valtree() - .expect("expected monomorphic const in codegen") - .0 - .unwrap_branch(); + let idx = generic_args[2].expect_const().to_value().valtree.unwrap_branch(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index eab4a9f30c9dc..43d6ccfcb4a28 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1329,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_shuffle_generic { - let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); + let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch(); let n = idx.len() as u64; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 869798d8be194..d766ae37e5b34 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -673,25 +673,23 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - ty::ConstKind::Value(ty, valtree) => { - match ty.kind() { + ty::ConstKind::Value(cv) => { + match cv.ty.kind() { ty::Int(ity) => { - // FIXME: directly extract the bits from a valtree instead of evaluating an - // already evaluated `Const` in order to get the bits. - let bits = ct + let bits = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { - let val = ct + let val = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); write!(output, "{val}") } ty::Bool => { - let val = ct.try_to_bool().expect("expected monomorphic const in codegen"); + let val = cv.try_to_bool().expect("expected monomorphic const in codegen"); write!(output, "{val}") } _ => { @@ -703,9 +701,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S // avoiding collisions and will make the emitted type names shorter. let hash_short = tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); - hcx.while_hashing_spans(false, |hcx| { - (ty, valtree).hash_stable(hcx, &mut hasher) - }); + hcx.while_hashing_spans(false, |hcx| cv.hash_stable(hcx, &mut hasher)); hasher.finish::() }); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 7676e1e171aac..eafc551501c13 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to // old-style simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)), + rustc_type_ir::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index e244b50a4b5d9..5d368b600a024 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -345,7 +345,7 @@ where Const::Ty(_, ct) if matches!( ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _) + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) ) => { None diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index b5adf06b30018..ecf9745b77945 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -46,8 +46,13 @@ pub fn provide(providers: &mut Providers) { }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; - providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree) + providers.valtree_to_const_val = |tcx, cv| { + const_eval::valtree_to_const_value( + tcx, + ty::TypingEnv::fully_monomorphized(), + cv.ty, + cv.valtree, + ) }; providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 28eac5b7496dd..74c8b463fc899 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { } ty::ConstKind::Param(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) | ty::ConstKind::Error(_) => ct.super_fold_with(self), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 283ebdfa236be..515c9c3409856 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1055,7 +1055,7 @@ impl<'tcx> InferCtxt<'tcx> { | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => ct, } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 66d97fda43332..923160cc0cc85 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -250,7 +250,7 @@ impl<'tcx> Const<'tcx> { // Dont use the outer ty as on invalid code we can wind up with them not being the same. // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`. - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, _ => *ty, } } @@ -264,7 +264,7 @@ impl<'tcx> Const<'tcx> { pub fn is_required_const(&self) -> bool { match self { Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(_, _) => false, // already a value, cannot error + ty::ConstKind::Value(_) => false, // already a value, cannot error _ => true, }, Const::Val(..) => false, // already a value, cannot error @@ -276,11 +276,11 @@ impl<'tcx> Const<'tcx> { pub fn try_to_scalar(self) -> Option { match self { Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { + ty::ConstKind::Value(cv) if cv.ty.is_primitive() => { // A valtree of a type where leaves directly represent the scalar const value. // Just checking whether it is a leaf is insufficient as e.g. references are leafs // but the leaf value is the value they point to, not the reference itself! - Some(valtree.unwrap_leaf().into()) + Some(cv.valtree.unwrap_leaf().into()) } _ => None, }, @@ -295,9 +295,7 @@ impl<'tcx> Const<'tcx> { match self { Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x), Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { - Some(valtree.unwrap_leaf()) - } + ty::ConstKind::Value(cv) if cv.ty.is_primitive() => Some(cv.valtree.unwrap_leaf()), _ => None, }, _ => None, @@ -328,7 +326,7 @@ impl<'tcx> Const<'tcx> { } match c.kind() { - ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))), + ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)), ConstKind::Expr(_) => { bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") } @@ -353,13 +351,13 @@ impl<'tcx> Const<'tcx> { typing_env: ty::TypingEnv<'tcx>, ) -> Option { if let Const::Ty(_, c) = self - && let ty::ConstKind::Value(ty, val) = c.kind() - && ty.is_primitive() + && let ty::ConstKind::Value(cv) = c.kind() + && cv.ty.is_primitive() { // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that // are valtree leaves, and *not* on references. (References should return the // pointer here, which valtrees don't represent.) - Some(val.unwrap_leaf().into()) + Some(cv.valtree.unwrap_leaf().into()) } else { self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar() } @@ -473,7 +471,7 @@ impl<'tcx> Const<'tcx> { // A valtree may be a reference. Valtree references correspond to a // different allocation each time they are evaluated. Valtrees for primitive // types are fine though. - ty::ConstKind::Value(ty, _) => ty.is_primitive(), + ty::ConstKind::Value(cv) => cv.ty.is_primitive(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false, // This can happen if evaluation of a constant failed. The result does not matter // much since compilation is doomed. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 3b4fba97e60b9..a318bacb866d1 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1441,7 +1441,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) } - ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)), + ty::ConstKind::Value(cv) => { + format!("ty::Valtree({})", fmt_valtree(&cv.valtree)) + } // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`. ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index e243425c0b7ba..f7090fa69e2ed 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -550,7 +550,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { } } -impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { +impl<'tcx> Key for ty::Value<'tcx> { type Cache = DefaultCache; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d83bc19a6a2f5..560e3bf3adeb2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1256,9 +1256,9 @@ rustc_queries! { desc { "evaluating type-level constant" } } - /// Converts a type level constant value into `ConstValue` - query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> mir::ConstValue<'tcx> { - desc { "converting type-level constant value to mir constant value"} + /// Converts a type-level constant value into a MIR constant value. + query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue<'tcx> { + desc { "converting type-level constant value to MIR constant value"} } /// Destructures array, ADT or tuple constants into the constants diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 310552764224e..6875532e28aaa 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -110,8 +110,8 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Value(ty, val)) + pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree })) } #[inline] @@ -214,47 +214,31 @@ impl<'tcx> Const<'tcx> { Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize) } - /// Panics if self.kind != ty::ConstKind::Value - pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) { + /// Panics if `self.kind != ty::ConstKind::Value`. + pub fn to_value(self) -> ty::Value<'tcx> { match self.kind() { - ty::ConstKind::Value(ty, valtree) => (valtree, ty), + ty::ConstKind::Value(cv) => cv, _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), } } - /// Attempts to convert to a `ValTree` - pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> { + /// Attempts to convert to a value. + pub fn try_to_value(self) -> Option> { match self.kind() { - ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)), + ty::ConstKind::Value(cv) => Some(cv), _ => None, } } #[inline] pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> { - let (valtree, ty) = self.try_to_valtree()?; - Some((valtree.try_to_scalar()?, ty)) - } - - pub fn try_to_bool(self) -> Option { - self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok() + let cv = self.try_to_value()?; + Some((cv.valtree.try_to_scalar()?, cv.ty)) } #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { - self.try_to_valtree()?.0.try_to_target_usize(tcx) - } - - /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of - /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it - /// contains const generic parameters or pointers). - #[inline] - pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { - let (scalar, ty) = self.try_to_scalar()?; - let scalar = scalar.try_to_scalar_int().ok()?; - let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(ty); - let size = tcx.layout_of(input).ok()?.size; - Some(scalar.to_bits(size)) + self.try_to_value()?.try_to_target_usize(tcx) } pub fn is_ct_infer(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 9f9bf41c3355a..425b68a951c61 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,11 +1,9 @@ -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::ScalarInt; use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq)] -#[derive(HashStable)] /// This datastructure is used to represent the value of constants used in the type system. /// /// We explicitly choose a different datastructure from the way values are processed within @@ -18,6 +16,8 @@ use crate::ty::{self, Ty, TyCtxt}; /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(HashStable, TyEncodable, TyDecodable)] pub enum ValTree<'tcx> { /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values @@ -79,10 +79,6 @@ impl<'tcx> ValTree<'tcx> { } } - pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { - self.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) - } - /// Get the values inside the ValTree as a slice of bytes. This only works for /// constants with types &str, &[u8], or [u8; _]. pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { @@ -107,3 +103,44 @@ impl<'tcx> ValTree<'tcx> { ) } } + +/// A type-level constant value. +/// +/// Represents a typed, fully evaluated constant. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] +pub struct Value<'tcx> { + pub ty: Ty<'tcx>, + pub valtree: ValTree<'tcx>, +} + +impl<'tcx> Value<'tcx> { + /// Attempts to extract the raw bits from the constant. + /// + /// Fails if the value can't be represented as bits (e.g. because it is an aggregate). + #[inline] + pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { + let scalar = self.valtree.try_to_scalar_int()?; + let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); + let size = tcx.layout_of(input).ok()?.size; + Some(scalar.to_bits(size)) + } + + pub fn try_to_bool(self) -> Option { + self.valtree.try_to_scalar_int()?.try_to_bool().ok() + } + + pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { + self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) + } +} + +impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { + fn ty(self) -> Ty<'tcx> { + self.ty + } + + fn valtree(self) -> ValTree<'tcx> { + self.valtree + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0c22c056dab5f..69f6fc0ad8a66 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -142,10 +142,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; - type ValueConst = ty::ValTree<'tcx>; + type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; - type Region = Region<'tcx>; + type ValTree = ty::ValTree<'tcx>; + type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; @@ -1118,15 +1119,18 @@ impl<'tcx> CommonConsts<'tcx> { }; CommonConsts { - unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())), - true_: mk_const(ty::ConstKind::Value( - types.bool, - ty::ValTree::Leaf(ty::ScalarInt::TRUE), - )), - false_: mk_const(ty::ConstKind::Value( - types.bool, - ty::ValTree::Leaf(ty::ScalarInt::FALSE), - )), + unit: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.unit, + valtree: ty::ValTree::zst(), + })), + true_: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.bool, + valtree: ty::ValTree::Leaf(ty::ScalarInt::TRUE), + })), + false_: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.bool, + valtree: ty::ValTree::Leaf(ty::ScalarInt::FALSE), + })), } } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0af57f636aaab..ec0498b168c01 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -381,7 +381,7 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - ty::ConstKind::Value(ty, _) => self.add_ty(ty), + ty::ConstKind::Value(cv) => self.add_ty(cv.ty), ty::ConstKind::Expr(e) => self.add_args(e.args()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8cd632790a8ae..88eea6101b5fc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,7 +60,7 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 027a4315b4bf3..19a39b3a29ea9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1484,8 +1484,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { _ => write!(self, "_")?, }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), - ty::ConstKind::Value(ty, value) => { - return self.pretty_print_const_valtree(value, ty, print_ty); + ty::ConstKind::Value(cv) => { + return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1637,33 +1637,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { - if let ty::Array(elem, len) = inner.kind() { - if let ty::Uint(ty::UintTy::U8) = elem.kind() { - if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() { - match self.tcx().try_get_global_alloc(prov.alloc_id()) { - Some(GlobalAlloc::Memory(alloc)) => { - let len = int.to_bits(self.tcx().data_layout.pointer_size); - let range = - AllocRange { start: offset, size: Size::from_bytes(len) }; - if let Ok(byte_str) = - alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) - { - p!(pretty_print_byte_str(byte_str)) - } else { - p!("") - } - } - // FIXME: for statics, vtables, and functions, we could in principle print more detail. - Some(GlobalAlloc::Static(def_id)) => { - p!(write("", def_id)) - } - Some(GlobalAlloc::Function { .. }) => p!(""), - Some(GlobalAlloc::VTable(..)) => p!(""), - None => p!(""), + if let ty::Array(elem, len) = inner.kind() + && let ty::Uint(ty::UintTy::U8) = elem.kind() + && let ty::ConstKind::Value(cv) = len.kind() + && let ty::ValTree::Leaf(int) = cv.valtree + { + match self.tcx().try_get_global_alloc(prov.alloc_id()) { + Some(GlobalAlloc::Memory(alloc)) => { + let len = int.to_bits(self.tcx().data_layout.pointer_size); + let range = AllocRange { start: offset, size: Size::from_bytes(len) }; + if let Ok(byte_str) = + alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) + { + p!(pretty_print_byte_str(byte_str)) + } else { + p!("") } - return Ok(()); } + // FIXME: for statics, vtables, and functions, we could in principle print more detail. + Some(GlobalAlloc::Static(def_id)) => { + p!(write("", def_id)) + } + Some(GlobalAlloc::Function { .. }) => p!(""), + Some(GlobalAlloc::VTable(..)) => p!(""), + None => p!(""), } + return Ok(()); } } ty::FnPtr(..) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 68cb56f35837d..9e9de4fb06443 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -162,16 +162,15 @@ impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If this is a value, we spend some effort to make it look nice. - if let ConstKind::Value(_, _) = self.kind() { + if let ConstKind::Value(_) = self.kind() { return ty::tls::with(move |tcx| { - // Somehow trying to lift the valtree results in lifetime errors, so we lift the - // entire constant. + // ValTrees aren't interned, so we lift the entire constant. let lifted = tcx.lift(*self).unwrap(); - let ConstKind::Value(ty, valtree) = lifted.kind() else { + let ConstKind::Value(cv) = lifted.kind() else { bug!("we checked that this is a valtree") }; let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?; + cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) }); } @@ -589,9 +588,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ConstKind::Value(t, v) => { - ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?) - } + ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; @@ -610,10 +607,7 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ConstKind::Value(t, v) => { - try_visit!(t.visit_with(visitor)); - v.visit_with(visitor) - } + ConstKind::Value(v) => v.visit_with(visitor), ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 2dcba8c2f82c4..3e8a3d1a28923 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -206,7 +206,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Bound(..) | ty::ConstKind::Error(_) => {} - ty::ConstKind::Value(ty, _) => stack.push(ty.into()), + ty::ConstKind::Value(cv) => stack.push(cv.ty.into()), ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), ty::ConstKind::Unevaluated(ct) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 3853b95f78b4c..c490e3885d4d0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), - ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty), + ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty), _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c), } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 62a7c84bc2807..7eeed721d5a0f 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -522,7 +522,7 @@ impl, I: Interner> TypeFolder for Canonicaliz // FIXME: See comment above -- we could fold the region separately or something. ty::ConstKind::Bound(_, _) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 8d1194ee53980..1fa35b60304cf 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -160,9 +160,7 @@ where ty::ConstKind::Infer(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_, _) - | ty::ConstKind::Error(_) => { + ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // We can freely ICE here as: @@ -199,7 +197,7 @@ where unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") } ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty(), ty::ConstKind::Placeholder(placeholder) => { self.cx().find_const_ty_from_env(goal.param_env, placeholder) } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 09648e28df471..5f0c1afdf6420 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -103,7 +103,7 @@ fn encode_args<'tcx>( /// ). fn encode_const<'tcx>( tcx: TyCtxt<'tcx>, - c: Const<'tcx>, + ct: Const<'tcx>, ct_ty: Ty<'tcx>, dict: &mut FxHashMap, usize>, options: EncodeTyOptions, @@ -111,7 +111,7 @@ fn encode_const<'tcx>( // L[n][]E as literal argument let mut s = String::from('L'); - match c.kind() { + match ct.kind() { // Const parameters ty::ConstKind::Param(..) => { // LE as literal argument @@ -121,18 +121,18 @@ fn encode_const<'tcx>( } // Literal arguments - ty::ConstKind::Value(ct_ty, ..) => { + ty::ConstKind::Value(cv) => { // L[n]E as literal argument // Element type - s.push_str(&encode_ty(tcx, ct_ty, dict, options)); + s.push_str(&encode_ty(tcx, cv.ty, dict, options)); // The only allowed types of const values are bool, u8, u16, u32, // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The // bool value false is encoded as 0 and true as 1. - match ct_ty.kind() { + match cv.ty.kind() { ty::Int(ity) => { - let bits = c + let bits = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; @@ -142,30 +142,30 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } ty::Uint(_) => { - let val = c + let val = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } ty::Bool => { - let val = c.try_to_bool().expect("expected monomorphic const in cfi"); + let val = cv.try_to_bool().expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } _ => { - bug!("encode_const: unexpected type `{:?}`", ct_ty); + bug!("encode_const: unexpected type `{:?}`", cv.ty); } } } _ => { - bug!("encode_const: unexpected kind `{:?}`", c.kind()); + bug!("encode_const: unexpected kind `{:?}`", ct.kind()); } } // Close the "L..E" pair s.push('E'); - compress(dict, DictKey::Const(c), &mut s); + compress(dict, DictKey::Const(ct), &mut s); s } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 31c7e6c3eb446..8d4e55dc036dd 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -450,8 +450,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let ty = ty::Ty::new_static_str(tcx); let bytes = value.as_bytes(); - let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes); - let val = tcx.valtree_to_const_val((ty, val_tree)); + let valtree = ty::ValTree::from_raw_bytes(tcx, bytes); + let cv = ty::Value { ty, valtree }; + let val = tcx.valtree_to_const_val(cv); mir::Const::from_value(val, ty).stable(&mut tables) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index ff452eea23d2b..a2d95f0f693aa 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -418,23 +418,16 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::TyConst; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let kind = match self.kind() { - ty::ConstKind::Value(ty, val) => { - let val = match val { - ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), - ty::ValTree::Branch(branch) => { - ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) - } - }; - - let ty = tables.tcx.lift(ty).unwrap(); - let const_val = tables.tcx.valtree_to_const_val((ty, val)); + let ct = tables.tcx.lift(*self).unwrap(); + let kind = match ct.kind() { + ty::ConstKind::Value(cv) => { + let const_val = tables.tcx.valtree_to_const_val(cv); if matches!(const_val, mir::ConstValue::ZeroSized) { - stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables)) + stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables)) } else { stable_mir::ty::TyConstKind::Value( - ty.stable(tables), - alloc::new_allocation(ty, const_val, tables), + cv.ty.stable(tables), + alloc::new_allocation(cv.ty, const_val, tables), ) } } @@ -449,7 +442,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { ty::ConstKind::Placeholder(_) => unimplemented!(), ty::ConstKind::Expr(_) => unimplemented!(), }; - let id = tables.intern_ty_const(tables.tcx.lift(*self).unwrap()); + let id = tables.intern_ty_const(ct); stable_mir::ty::TyConst::new(kind, id) } } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 879f3fac21fb4..8ae35572d012d 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -274,14 +274,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // only print integers match ct.kind() { - ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => { + ty::ConstKind::Value(cv) if cv.ty.is_integral() => { // The `pretty_print_const` formatting depends on -Zverbose-internals // flag, so we cannot reuse it here. - let signed = matches!(ty.kind(), ty::Int(_)); + let scalar = cv.valtree.unwrap_leaf(); + let signed = matches!(cv.ty.kind(), ty::Int(_)); write!( self, "{:#?}", - ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral()) + ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral()) )?; } _ => self.write_str("_")?, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4ddf530a00d4a..5b3272feecdbb 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -590,8 +590,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // We only mangle a typed value if the const can be evaluated. - let (ct_ty, valtree) = match ct.kind() { - ty::ConstKind::Value(ty, val) => (ty, val), + let cv = match ct.kind() { + ty::ConstKind::Value(cv) => cv, // Should only be encountered within the identity-substituted // impl header of an item nested within an impl item. @@ -619,13 +619,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { return Ok(()); } + let ty::Value { ty: ct_ty, valtree } = cv; let start = self.out.len(); match ct_ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { ct_ty.print(self)?; - let mut bits = ct + let mut bits = cv .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected const to be monomorphic"); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 2b7da4bc5ff07..c8ae977b5ad60 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -264,7 +264,7 @@ fn fulfillment_error_for_no_solution<'tcx>( infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, kind => span_bug!( obligation.cause.span, "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}" diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 446f9eaa348c0..bdee6ca2afe54 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -35,7 +35,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => return Ok(()), ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 7529ee128f5e4..f2d2dd2f3ce59 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -479,7 +479,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::ConstKind::Error(_) => { return ProcessResult::Changed(PendingPredicateObligations::new()); } - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, ty::ConstKind::Unevaluated(uv) => { infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6b6e0b32385c4..99ce1fd9fb480 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -962,7 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(EvaluatedToAmbig); } ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, ty::ConstKind::Unevaluated(uv) => { self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index ad86813c87e29..a50cc8f593251 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -128,16 +128,16 @@ mod rustc { pub fn from_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - c: Const<'tcx>, + ct: Const<'tcx>, ) -> Option { use rustc_middle::ty::ScalarInt; use rustc_span::sym; - let Some((cv, ty)) = c.try_to_valtree() else { + let Some(cv) = ct.try_to_value() else { return None; }; - let adt_def = ty.ty_adt_def()?; + let adt_def = cv.ty.ty_adt_def()?; assert_eq!( tcx.require_lang_item(LangItem::TransmuteOpts, None), @@ -147,7 +147,7 @@ mod rustc { ); let variant = adt_def.non_enum_variant(); - let fields = match cv { + let fields = match cv.valtree { ValTree::Branch(branch) => branch, _ => { return Some(Self { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 51a7c976f600c..931c36137ee5f 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -22,16 +22,16 @@ fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, const_: ty::Const<'tcx>, ) -> ty::DestructuredConst<'tcx> { - let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else { + let ty::ConstKind::Value(cv) = const_.kind() else { bug!("cannot destructure constant {:?}", const_) }; - let branches = match valtree { + let branches = match cv.valtree { ty::ValTree::Branch(b) => b, _ => bug!("cannot destructure constant {:?}", const_), }; - let (fields, variant) = match ct_ty.kind() { + let (fields, variant) = match cv.ty.kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice let field_consts = branches diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index a04c753611831..2f258b23f2df4 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -144,13 +144,13 @@ fn univariant_uninterned<'tcx>( cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err)) } -fn validate_const_with_value<'tcx>( +fn extract_const_value<'tcx>( const_: ty::Const<'tcx>, ty: Ty<'tcx>, cx: &LayoutCx<'tcx>, -) -> Result, &'tcx LayoutError<'tcx>> { +) -> Result, &'tcx LayoutError<'tcx>> { match const_.kind() { - ty::ConstKind::Value(..) => Ok(const_), + ty::ConstKind::Value(cv) => Ok(cv), ty::ConstKind::Error(guar) => { return Err(error(cx, LayoutError::ReferencesError(guar))); } @@ -209,13 +209,12 @@ fn layout_of_uncached<'tcx>( &mut layout.backend_repr { if let Some(start) = start { - scalar.valid_range_mut().start = - validate_const_with_value(start, ty, cx)? - .try_to_bits(tcx, cx.typing_env) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + scalar.valid_range_mut().start = extract_const_value(start, ty, cx)? + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; } if let Some(end) = end { - let mut end = validate_const_with_value(end, ty, cx)? + let mut end = extract_const_value(end, ty, cx)? .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; if !include_end { @@ -348,9 +347,7 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, count) => { - let count = validate_const_with_value(count, ty, cx)? - .to_valtree() - .0 + let count = extract_const_value(count, ty, cx)? .try_to_target_usize(tcx) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 03dfe547cedd4..aafc0907ae156 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -31,7 +31,7 @@ pub enum ConstKind { Unevaluated(ty::UnevaluatedConst), /// Used to hold computed value. - Value(I::Ty, I::ValueConst), + Value(I::ValueConst), /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. @@ -52,7 +52,7 @@ impl fmt::Debug for ConstKind { Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var), Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => write!(f, "{uv:?}"), - Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"), + Value(val) => write!(f, "{val:?}"), Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{expr:?}"), } diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 9b3ff14d507ac..9955e92b55a5c 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -483,8 +483,8 @@ impl match rhs.kind() { - ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val, + ty::ConstKind::Value(lhs_val) => match rhs.kind() { + ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(), _ => false, }, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 872cf6680185b..4e6d645e6fae2 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -286,6 +286,11 @@ pub trait Const>: } } +pub trait ValueConst>: Copy + Debug + Hash + Eq { + fn ty(self) -> I::Ty; + fn valtree(self) -> I::ValTree; +} + pub trait ExprConst>: Copy + Debug + Hash + Eq + Relate { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0c3b0758f0f95..a6c72da0c564a 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -112,8 +112,9 @@ pub trait Interner: type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; - type ValueConst: Copy + Debug + Hash + Eq; + type ValueConst: ValueConst; type ExprConst: ExprConst; + type ValTree: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e628b66d2f086..5b696ee5ed400 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -606,7 +606,9 @@ pub fn structurally_relate_consts>( true } (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { + a_val.valtree() == b_val.valtree() + } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 77040aeb94d77..0b4fd9c22589c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -344,10 +344,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { s } // array lengths are obviously usize - ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) - if *ty.kind() == ty::Uint(ty::UintTy::Usize) => - { - scalar.to_string() + ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => { + cv.valtree.unwrap_leaf().to_string() } _ => n.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 623b6b4fcc145..cabf10b7e0ea9 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -56,9 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx - .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree() - && let element_count = element_count.to_target_usize(cx.tcx) + && let Some(element_count) = cx.tcx + .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 46d7df6995a9e..6f5c5d6b3ea3f 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -8,7 +8,7 @@ use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, ConstKind}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; @@ -81,8 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { && let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && let element_count = element_count.to_target_usize(cx.tcx) + && let Some(element_count) = cst.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { matches!( diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 54bdd3f02c2c2..63a61dcd14878 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -640,7 +640,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (dest, dest_len) = this.project_to_simd(dest)?; let index = - generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); + generic_args[2].expect_const().to_value().valtree.unwrap_branch(); let index_len = index.len(); assert_eq!(left_len, right_len); From 0055fb92db2fcfb8c74d1bf9063f14f65d5dcce0 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 27 Jan 2025 11:16:19 +0000 Subject: [PATCH 11/12] check the types in `ty::Value` to value conversion and remove `ty::Const::try_to_scalar` because it becomes redundant --- compiler/rustc_middle/src/ty/consts.rs | 7 --- .../rustc_middle/src/ty/consts/valtree.rs | 12 +++++- .../cfi/typeid/itanium_cxx_abi/transform.rs | 10 ++++- .../src/error_reporting/infer/mod.rs | 10 ++--- tests/crashes/131102.rs | 4 -- tests/ui/consts/bad-array-size-in-type-err.rs | 11 +++++ .../consts/bad-array-size-in-type-err.stderr | 43 ++++++++++++++++++- 7 files changed, 75 insertions(+), 22 deletions(-) delete mode 100644 tests/crashes/131102.rs diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 6875532e28aaa..4ad5d8443b2f6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -5,7 +5,6 @@ use rustc_error_messages::MultiSpan; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; -use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; mod int; @@ -230,12 +229,6 @@ impl<'tcx> Const<'tcx> { } } - #[inline] - pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> { - let cv = self.try_to_value()?; - Some((cv.valtree.try_to_scalar()?, cv.ty)) - } - #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { self.try_to_value()?.try_to_target_usize(tcx) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 425b68a951c61..d914b7576dc49 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -117,9 +117,13 @@ pub struct Value<'tcx> { impl<'tcx> Value<'tcx> { /// Attempts to extract the raw bits from the constant. /// - /// Fails if the value can't be represented as bits (e.g. because it is an aggregate). + /// Fails if the value can't be represented as bits (e.g. because it is a reference + /// or an aggregate). #[inline] pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { + let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { + return None; + }; let scalar = self.valtree.try_to_scalar_int()?; let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); let size = tcx.layout_of(input).ok()?.size; @@ -127,10 +131,16 @@ impl<'tcx> Value<'tcx> { } pub fn try_to_bool(self) -> Option { + if !self.ty.is_bool() { + return None; + } self.valtree.try_to_scalar_int()?.try_to_bool().ok() } pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { + if !self.ty.is_usize() { + return None; + } self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 9c6186d688284..b711c238d594b 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -51,8 +51,7 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { // Transforms a ty:Ty for being encoded and used in the substitution dictionary. fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.kind() { - ty::Array(..) - | ty::Closure(..) + ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) @@ -67,6 +66,13 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { | ty::Tuple(..) | ty::UnsafeBinder(_) => t.super_fold_with(self), + // Don't transform the type of the array length and keep it as `usize`. + // This is required for `try_to_target_usize` to work correctly. + &ty::Array(inner, len) => { + let inner = self.fold_ty(inner); + Ty::new_array_with_const_len(self.tcx, inner, len) + } + ty::Bool => { if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { // Note: on all platforms that Rust's currently supports, its size and alignment diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9eacd377361a7..117b6a7642575 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2023,14 +2023,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => None, }; if let Some(tykind) = tykind - && let hir::TyKind::Array(_, length) = tykind - && let Some((scalar, ty)) = sz.found.try_to_scalar() - && ty == self.tcx.types.usize + && let hir::TyKind::Array(_, length_arg) = tykind + && let Some(length_val) = sz.found.try_to_target_usize(self.tcx) { - let span = length.span(); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { - span, - length: scalar.to_target_usize(&self.tcx).unwrap(), + span: length_arg.span(), + length: length_val, }) } else { None diff --git a/tests/crashes/131102.rs b/tests/crashes/131102.rs deleted file mode 100644 index 12b35f8d1b2ac..0000000000000 --- a/tests/crashes/131102.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #131102 -pub struct Blorb([String; N]); -pub struct Wrap(Blorb<0>); -pub const fn i(_: Wrap) {} diff --git a/tests/ui/consts/bad-array-size-in-type-err.rs b/tests/ui/consts/bad-array-size-in-type-err.rs index cb02ad3205db6..0490a9d3620ee 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.rs +++ b/tests/ui/consts/bad-array-size-in-type-err.rs @@ -8,3 +8,14 @@ fn main() { //~^ ERROR mismatched types //~| ERROR the constant `2` is not of type `usize` } + +fn iter(val: BadArraySize::<2>) { + for _ in val.arr {} + //~^ ERROR the constant `2` is not of type `usize` + //~| ERROR `[i32; 2]` is not an iterator +} + +// issue #131102 +pub struct Blorb([String; N]); //~ ERROR the constant `N` is not of type `usize` +pub struct Wrap(Blorb<0>); +pub const fn i(_: Wrap) {} //~ ERROR destructor of `Wrap` cannot be evaluated at compile-time diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr index c3ff216432eeb..84e16f8d931ea 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.stderr +++ b/tests/ui/consts/bad-array-size-in-type-err.stderr @@ -6,6 +6,14 @@ LL | arr: [i32; N], | = note: the length of array `[i32; N]` must be type `usize` +error: the constant `N` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:19:32 + | +LL | pub struct Blorb([String; N]); + | ^^^^^^^^^^^ expected `usize`, found `u16` + | + = note: the length of array `[String; N]` must be type `usize` + error[E0308]: mismatched types --> $DIR/bad-array-size-in-type-err.rs:7:38 | @@ -20,6 +28,37 @@ LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] }; | = note: the length of array `[i32; 2]` must be type `usize` -error: aborting due to 3 previous errors +error: the constant `2` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ expected `usize`, found `u8` + | + = note: the length of array `[i32; 2]` must be type `usize` + +error[E0277]: `[i32; 2]` is not an iterator + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ `[i32; 2]` is not an iterator; try calling `.into_iter()` or `.iter()` + | + = help: the trait `IntoIterator` is not implemented for `[i32; 2]` + = help: the following other types implement trait `IntoIterator`: + &[T; N] + &[T] + &mut [T; N] + &mut [T] + [T; N] + +error[E0493]: destructor of `Wrap` cannot be evaluated at compile-time + --> $DIR/bad-array-size-in-type-err.rs:21:16 + | +LL | pub const fn i(_: Wrap) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308, E0493. +For more information about an error, try `rustc --explain E0277`. From ca3ff832e34cc32d93c9e940d8f6d3e4034203fa Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Thu, 30 Jan 2025 17:22:45 +0100 Subject: [PATCH 12/12] add comments --- compiler/rustc_const_eval/src/const_eval/valtrees.rs | 3 ++- compiler/rustc_middle/src/ty/consts.rs | 6 ++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 4ff8aa9a3b418..4d625f76aba2a 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -272,7 +272,8 @@ pub(crate) fn eval_to_valtree<'tcx>( /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. -// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function +// FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function +// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 4ad5d8443b2f6..d77fb1cc91e82 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -222,6 +222,8 @@ impl<'tcx> Const<'tcx> { } /// Attempts to convert to a value. + /// + /// Note that this does not evaluate the constant. pub fn try_to_value(self) -> Option> { match self.kind() { ty::ConstKind::Value(cv) => Some(cv), @@ -229,6 +231,10 @@ impl<'tcx> Const<'tcx> { } } + /// Convenience method to extract the value of a usize constant, + /// useful to get the length of an array type. + /// + /// Note that this does not evaluate the constant. #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { self.try_to_value()?.try_to_target_usize(tcx) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 19a39b3a29ea9..018fcc66aeed4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1785,6 +1785,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } + // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. fn pretty_print_const_valtree( &mut self, valtree: ty::ValTree<'tcx>, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index c490e3885d4d0..cc6d69710e4c2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -214,6 +214,7 @@ impl<'tcx> ConstToPat<'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). + // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(self), level = "debug")] fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { let span = self.span;