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) ========================== 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/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d2de62b17f04d..2d007416263fa 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1325,7 +1325,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 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 b4e9b9f44f4ab..f8b30cb507a23 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -225,6 +225,8 @@ 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) }) .1; @@ -289,7 +291,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() { @@ -315,7 +317,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) => { @@ -327,7 +329,8 @@ 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)), + // 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 c7114480d8bdf..771ebf2057f9a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -210,6 +210,14 @@ 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) } + } + + /// 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, @@ -233,6 +241,34 @@ 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, + 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); @@ -505,24 +541,15 @@ 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 { - 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); + // 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()) } 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 8d782a618fc07..d7b42481e1aa1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1488,6 +1488,26 @@ 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 { + 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>, @@ -1508,6 +1528,8 @@ 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); let trait_def_id = trait_ref_self.def_id(); @@ -1581,6 +1603,9 @@ 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 // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. 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_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 009d15a932f7a..cc7c5231aca58 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -661,6 +661,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; } @@ -991,7 +1064,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; @@ -1048,6 +1124,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); 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/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_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..d77fb1cc91e82 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; @@ -110,8 +109,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 +213,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. + /// + /// Note that this does not evaluate the constant. + 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() - } - + /// 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_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..d914b7576dc49 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,54 @@ 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 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; + Some(scalar.to_bits(size)) + } + + 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)) + } +} + +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..018fcc66aeed4 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(..) => { @@ -1786,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_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..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 @@ -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), } } @@ -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; 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_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_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/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/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/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..]) } } 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")] 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 /// 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) +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5e250d18ce6aa..825e5452f0e6a 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); } @@ -3106,6 +3107,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 1b413dcb07efb..f6a03a386d170 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 } @@ -342,6 +348,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); @@ -360,6 +372,7 @@ impl From for BootstrapCommand { if !cargo.allow_features.is_empty() { cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features); } + cargo.command } } @@ -429,13 +442,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"); @@ -1218,14 +1224,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, } } } 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); 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/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`. 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