diff options
Diffstat (limited to 'compiler')
77 files changed, 1592 insertions, 853 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 096cea945b0..418e1df5857 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1300,14 +1300,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - AssocItemKind::Type(box TyAlias { - generics, - where_clauses, - where_predicates_split, - bounds, - ty, - .. - }) => { + AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => { if ty.is_none() { self.session.emit_err(errors::AssocTypeWithoutBody { span: item.span, @@ -1315,18 +1308,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } self.check_type_no_bounds(bounds, "`impl`s"); - if ty.is_some() { - self.check_gat_where( - item.id, - generics.where_clause.predicates.split_at(*where_predicates_split).0, - *where_clauses, - ); - } } _ => {} } } + if let AssocItemKind::Type(box TyAlias { + generics, + where_clauses, + where_predicates_split, + ty: Some(_), + .. + }) = &item.kind + { + self.check_gat_where( + item.id, + generics.where_clause.predicates.split_at(*where_predicates_split).0, + *where_clauses, + ); + } + if ctxt == AssocCtxt::Trait || self.in_trait_impl { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index b344ab46adb..012075d7114 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -20,7 +20,7 @@ struct UseFactsExtractor<'me, 'tcx> { } // A Visitor to walk through the MIR and extract point-wise facts -impl UseFactsExtractor<'_, '_> { +impl<'tcx> UseFactsExtractor<'_, 'tcx> { fn location_to_index(&self, location: Location) -> LocationIndex { self.location_table.mid_index(location) } @@ -45,7 +45,7 @@ impl UseFactsExtractor<'_, '_> { self.path_accessed_at_base.push((path, self.location_to_index(location))); } - fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> { + fn place_to_mpi(&self, place: &Place<'tcx>) -> Option<MovePathIndex> { match self.move_data.rev_lookup.find(place.as_ref()) { LookupResult::Exact(mpi) => Some(mpi), LookupResult::Parent(mmpi) => mmpi, diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index a2db59bd6c4..4d879fbdcb7 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -290,7 +290,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } }; let llval = unsafe { - llvm::LLVMRustConstInBoundsGEP2( + llvm::LLVMConstInBoundsGEP2( self.type_i8(), self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)), &self.const_usize(offset.bytes()), @@ -320,7 +320,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { - llvm::LLVMRustConstInBoundsGEP2( + llvm::LLVMConstInBoundsGEP2( self.type_i8(), self.const_bitcast(base_addr, self.type_i8p()), &self.const_usize(offset.bytes()), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3ad546b61e9..e1dfc1b2dd6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1155,7 +1155,7 @@ extern "C" { pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value; // Constant expressions - pub fn LLVMRustConstInBoundsGEP2<'a>( + pub fn LLVMConstInBoundsGEP2<'a>( ty: &'a Type, ConstantVal: &'a Value, ConstantIndices: *const &'a Value, diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 00e6acb5c1a..1f827a2375d 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -12,7 +12,6 @@ use object::{ use snap::write::FrameEncoder; -use object::elf::NT_GNU_PROPERTY_TYPE_0; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::fs::METADATA_FILENAME; @@ -124,7 +123,7 @@ fn add_gnu_property_note( let mut data: Vec<u8> = Vec::new(); let n_namsz: u32 = 4; // Size of the n_name field let n_descsz: u32 = 16; // Size of the n_desc field - let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor + let n_type: u32 = object::elf::NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor let header_values = [n_namsz, n_descsz, n_type]; header_values.iter().for_each(|v| { data.extend_from_slice(&match endianness { @@ -134,8 +133,8 @@ fn add_gnu_property_note( }); data.extend_from_slice(b"GNU\0"); // Owner of the program property note let pr_type: u32 = match architecture { - Architecture::X86_64 => 0xc0000002, - Architecture::Aarch64 => 0xc0000000, + Architecture::X86_64 => object::elf::GNU_PROPERTY_X86_FEATURE_1_AND, + Architecture::Aarch64 => object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND, _ => unreachable!(), }; let pr_datasz: u32 = 4; //size of the pr_data field @@ -243,8 +242,16 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, _ => elf::EF_MIPS_ARCH_32R2, }; - // The only ABI LLVM supports for 32-bit MIPS CPUs is o32. - let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch; + + let mut e_flags = elf::EF_MIPS_CPIC | arch; + + // If the ABI is explicitly given, use it or default to O32. + match sess.target.options.llvm_abiname.to_lowercase().as_str() { + "n32" => e_flags |= elf::EF_MIPS_ABI2, + "o32" => e_flags |= elf::EF_MIPS_ABI_O32, + _ => e_flags |= elf::EF_MIPS_ABI_O32, + }; + if sess.target.options.relocation_model != RelocModel::Static { e_flags |= elf::EF_MIPS_PIC; } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index f9f645af41f..a20f0276b3e 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::errors::{LongRunning, LongRunningWarn}; use crate::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx, + self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, Scalar, }; use crate::{errors, fluent_generated as fluent}; @@ -201,7 +201,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { fn hook_special_const_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], + args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option<mir::BasicBlock>, ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { @@ -210,6 +210,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { if Some(def_id) == self.tcx.lang_items().panic_display() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { + let args = self.copy_fn_args(args)?; // &str or &&str assert!(args.len() == 1); @@ -236,8 +237,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { return Ok(Some(new_instance)); } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { + let args = self.copy_fn_args(args)?; // For align_offset, we replace the function call if the pointer has no address. - match self.align_offset(instance, args, dest, ret)? { + match self.align_offset(instance, &args, dest, ret)? { ControlFlow::Continue(()) => return Ok(Some(instance)), ControlFlow::Break(()) => return Ok(None), } @@ -293,7 +295,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { self.eval_fn_call( FnVal::Instance(instance), (CallAbi::Rust, fn_abi), - &[addr, align], + &[FnArg::Copy(addr), FnArg::Copy(align)], /* with_caller_location = */ false, dest, ret, @@ -427,7 +429,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, _abi: CallAbi, - args: &[OpTy<'tcx>], + args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option<mir::BasicBlock>, _unwind: mir::UnwindAction, // unwinding is not supported in consts diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 36606ff69a6..5e5ad31d8c2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -682,11 +682,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); - // Clobber previous return place contents, nobody is supposed to be able to see them any more - // This also checks dereferenceable, but not align. We rely on all constructed places being - // sufficiently aligned (in particular we rely on `deref_operand` checking alignment). - self.write_uninit(return_place)?; - // first push a stack frame so we have access to the local substs + // First push a stack frame so we have access to the local substs let pre_frame = Frame { body, loc: Right(body.span), // Span used for errors caused during preamble. @@ -805,6 +801,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_ub_custom!(fluent::const_eval_unwind_past_top); } + M::before_stack_pop(self, self.frame())?; + // Copy return value. Must of course happen *before* we deallocate the locals. let copy_ret_result = if !unwinding { let op = self diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7b11ad33091..107e5bec614 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -30,7 +30,7 @@ use super::{ use crate::const_eval; use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer}; -pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< +pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< 'mir, 'tcx, MemoryKind = T, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index b448e3a24c6..e101785b6e2 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::const_eval::CheckAlignment; use super::{ - AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, + AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, }; @@ -84,7 +84,7 @@ pub trait AllocMap<K: Hash + Eq, V> { /// Methods of this trait signifies a point where CTFE evaluation would fail /// and some use case dependent behaviour can instead be applied. -pub trait Machine<'mir, 'tcx>: Sized { +pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Additional memory kinds a machine wishes to distinguish from the builtin ones type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; @@ -182,7 +182,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, abi: CallAbi, - args: &[OpTy<'tcx, Self::Provenance>], + args: &[FnArg<'tcx, Self::Provenance>], destination: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, @@ -194,7 +194,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Self::ExtraFnVal, abi: CallAbi, - args: &[OpTy<'tcx, Self::Provenance>], + args: &[FnArg<'tcx, Self::Provenance>], destination: &PlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, @@ -418,6 +418,18 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } + /// Called on places used for in-place function argument and return value handling. + /// + /// These places need to be protected to make sure the program cannot tell whether the + /// argument/return value was actually copied or passed in-place.. + fn protect_in_place_function_argument( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + place: &PlaceTy<'tcx, Self::Provenance>, + ) -> InterpResult<'tcx> { + // Without an aliasing model, all we can do is put `Uninit` into the place. + ecx.write_uninit(place) + } + /// Called immediately before a new stack frame gets pushed. fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -439,6 +451,14 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } + /// Called just before the return value is copied to the caller-provided return place. + fn before_stack_pop( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _frame: &Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Called immediately after a stack frame got popped, but before jumping back to the caller. /// The `locals` have already been destroyed! fn after_stack_pop( @@ -484,7 +504,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _ecx: &mut InterpCx<$mir, $tcx, Self>, fn_val: !, _abi: CallAbi, - _args: &[OpTy<$tcx>], + _args: &[FnArg<$tcx>], _destination: &PlaceTy<$tcx, Self::Provenance>, _target: Option<mir::BasicBlock>, _unwind: mir::UnwindAction, diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 898d62361ab..f657f954f9c 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -26,6 +26,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; +pub use self::terminator::FnArg; pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::visitor::{MutValueVisitor, Value, ValueVisitor}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 5f89d652fab..6727937363e 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -575,14 +575,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(op) } - /// Evaluate a bunch of operands at once - pub(super) fn eval_operands( - &self, - ops: &[mir::Operand<'tcx>], - ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> { - ops.iter().map(|op| self.eval_operand(op, None)).collect() - } - fn eval_ty_constant( &self, val: ty::Const<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index ca1106384fd..c2fb61753fe 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -328,7 +328,8 @@ where }; let mplace = MemPlace { ptr: ptr.to_pointer(self)?, meta }; - // When deref'ing a pointer, the *static* alignment given by the type is what matters. + // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; + // we hence can't call `size_and_align_of` since that asserts more validity than we want. let align = layout.align.abi; Ok(MPlaceTy { mplace, layout, align }) } @@ -354,34 +355,37 @@ where #[inline] pub(super) fn get_place_alloc( &self, - place: &MPlaceTy<'tcx, M::Provenance>, + mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { - assert!(place.layout.is_sized()); - assert!(!place.meta.has_meta()); - let size = place.layout.size; - self.get_ptr_alloc(place.ptr, size, place.align) + let (size, _align) = self + .size_and_align_of_mplace(&mplace)? + .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); + // Due to packed places, only `mplace.align` matters. + self.get_ptr_alloc(mplace.ptr, size, mplace.align) } #[inline] pub(super) fn get_place_alloc_mut( &mut self, - place: &MPlaceTy<'tcx, M::Provenance>, + mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { - assert!(place.layout.is_sized()); - assert!(!place.meta.has_meta()); - let size = place.layout.size; - self.get_ptr_alloc_mut(place.ptr, size, place.align) + let (size, _align) = self + .size_and_align_of_mplace(&mplace)? + .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); + // Due to packed places, only `mplace.align` matters. + self.get_ptr_alloc_mut(mplace.ptr, size, mplace.align) } /// Check if this mplace is dereferenceable and sufficiently aligned. pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - let (size, align) = self + let (size, _align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - assert!(mplace.align <= align, "dynamic alignment less strict than static one?"); - let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE }; + // Due to packed places, only `mplace.align` matters. + let align = + if M::enforce_alignment(self).should_check() { mplace.align } else { Align::ONE }; self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?; Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 15823a5975e..97d7a68e190 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; +use either::Either; use rustc_ast::ast::InlineAsmOptions; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::Instance; use rustc_middle::{ mir, @@ -12,12 +13,63 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo use rustc_target::spec::abi::Abi; use super::{ - FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand, - PlaceTy, Scalar, StackPopCleanup, + AllocId, FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, + Operand, PlaceTy, Provenance, Scalar, StackPopCleanup, }; use crate::fluent_generated as fluent; +/// An argment passed to a function. +#[derive(Clone, Debug)] +pub enum FnArg<'tcx, Prov: Provenance = AllocId> { + /// Pass a copy of the given operand. + Copy(OpTy<'tcx, Prov>), + /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and + /// make the place inaccessible for the duration of the function call. + InPlace(PlaceTy<'tcx, Prov>), +} + +impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> { + pub fn layout(&self) -> &TyAndLayout<'tcx> { + match self { + FnArg::Copy(op) => &op.layout, + FnArg::InPlace(place) => &place.layout, + } + } +} + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the + /// original memory occurs. + pub fn copy_fn_arg( + &self, + arg: &FnArg<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + match arg { + FnArg::Copy(op) => Ok(op.clone()), + FnArg::InPlace(place) => self.place_to_op(&place), + } + } + + /// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the + /// original memory occurs. + pub fn copy_fn_args( + &self, + args: &[FnArg<'tcx, M::Provenance>], + ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> { + args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect() + } + + pub fn fn_arg_field( + &mut self, + arg: &FnArg<'tcx, M::Provenance>, + field: usize, + ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { + Ok(match arg { + FnArg::Copy(op) => FnArg::Copy(self.operand_field(op, field)?), + FnArg::InPlace(place) => FnArg::InPlace(self.place_field(place, field)?), + }) + } + pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, @@ -68,14 +120,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; - let args = self.eval_operands(args)?; + let args = self.eval_fn_call_arguments(args)?; let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = - self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty)); + self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty)); let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { ty::FnPtr(_sig) => { @@ -185,6 +237,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + /// Evaluate the arguments of a function call + pub(super) fn eval_fn_call_arguments( + &mut self, + ops: &[mir::Operand<'tcx>], + ) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> { + ops.iter() + .map(|op| { + Ok(match op { + mir::Operand::Move(place) => FnArg::InPlace(self.eval_place(*place)?), + _ => FnArg::Copy(self.eval_operand(op, None)?), + }) + }) + .collect() + } + fn check_argument_compat( caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, @@ -275,7 +342,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn pass_argument<'x, 'y>( &mut self, caller_args: &mut impl Iterator< - Item = (&'x OpTy<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), + Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_arg: &PlaceTy<'tcx, M::Provenance>, @@ -295,21 +362,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Now, check if !Self::check_argument_compat(caller_abi, callee_abi) { let callee_ty = format!("{}", callee_arg.layout.ty); - let caller_ty = format!("{}", caller_arg.layout.ty); + let caller_ty = format!("{}", caller_arg.layout().ty); throw_ub_custom!( fluent::const_eval_incompatible_types, callee_ty = callee_ty, caller_ty = caller_ty, ) } + // We work with a copy of the argument for now; if this is in-place argument passing, we + // will later protect the source it comes from. This means the callee cannot observe if we + // did in-place of by-copy argument passing, except for pointer equality tests. + let caller_arg_copy = self.copy_fn_arg(&caller_arg)?; // Special handling for unsized parameters. - if caller_arg.layout.is_unsized() { + if caller_arg_copy.layout.is_unsized() { // `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way. - assert_eq!(caller_arg.layout.ty, callee_arg.layout.ty); + assert_eq!(caller_arg_copy.layout.ty, callee_arg.layout.ty); // We have to properly pre-allocate the memory for the callee. - // So let's tear down some wrappers. + // So let's tear down some abstractions. // This all has to be in memory, there are no immediate unsized values. - let src = caller_arg.assert_mem_place(); + let src = caller_arg_copy.assert_mem_place(); // The destination cannot be one of these "spread args". let (dest_frame, dest_local) = callee_arg.assert_local(); // We are just initializing things, so there can't be anything here yet. @@ -331,7 +402,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This // is true for all `copy_op`, but there are a lot of special cases for argument passing // specifically.) - self.copy_op(&caller_arg, callee_arg, /*allow_transmute*/ true) + self.copy_op(&caller_arg_copy, callee_arg, /*allow_transmute*/ true)?; + // If this was an in-place pass, protect the place it comes from for the duration of the call. + if let FnArg::InPlace(place) = caller_arg { + M::protect_in_place_function_argument(self, place)?; + } + Ok(()) } /// Call this function -- pushing the stack frame and initializing the arguments. @@ -346,7 +422,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), - args: &[OpTy<'tcx, M::Provenance>], + args: &[FnArg<'tcx, M::Provenance>], with_caller_location: bool, destination: &PlaceTy<'tcx, M::Provenance>, target: Option<mir::BasicBlock>, @@ -372,8 +448,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(def_id) => { assert!(self.tcx.is_intrinsic(def_id)); - // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. - M::call_intrinsic(self, instance, args, destination, target, unwind) + // FIXME: Should `InPlace` arguments be reset to uninit? + M::call_intrinsic( + self, + instance, + &self.copy_fn_args(args)?, + destination, + target, + unwind, + ) } ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) @@ -428,7 +511,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { "caller ABI: {:?}, args: {:#?}", caller_abi, args.iter() - .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) + .map(|arg| ( + arg.layout().ty, + match arg { + FnArg::Copy(op) => format!("copy({:?})", *op), + FnArg::InPlace(place) => format!("in-place({:?})", *place), + } + )) .collect::<Vec<_>>() ); trace!( @@ -449,7 +538,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // last incoming argument. These two iterators do not have the same type, // so to keep the code paths uniform we accept an allocation // (for RustCall ABI only). - let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> = + let caller_args: Cow<'_, [FnArg<'tcx, M::Provenance>]> = if caller_abi == Abi::RustCall && !args.is_empty() { // Untuple let (untuple_arg, args) = args.split_last().unwrap(); @@ -458,11 +547,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { args.iter() .map(|a| Ok(a.clone())) .chain( - (0..untuple_arg.layout.fields.count()) - .map(|i| self.operand_field(untuple_arg, i)), + (0..untuple_arg.layout().fields.count()) + .map(|i| self.fn_arg_field(untuple_arg, i)), ) - .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::Provenance>>>>( - )?, + .collect::<InterpResult<'_, Vec<_>>>()?, ) } else { // Plain arg passing @@ -523,6 +611,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_ty = caller_ty, ) } + // Ensure the return place is aligned and dereferenceable, and protect it for + // in-place return value passing. + if let Either::Left(mplace) = destination.as_mplace_or_local() { + self.check_mplace(mplace)?; + } else { + // Nothing to do for locals, they are always properly allocated and aligned. + } + M::protect_in_place_function_argument(self, destination)?; }; match res { Err(err) => { @@ -538,7 +634,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively // unwrap those newtypes until we are there. - let mut receiver = args[0].clone(); + // An `InPlace` does nothing here, we keep the original receiver intact. We can't + // really pass the argument in-place anyway, and we are constructing a new + // `Immediate` receiver. + let mut receiver = self.copy_fn_arg(&args[0])?; let receiver_place = loop { match receiver.layout.ty.kind() { ty::Ref(..) | ty::RawPtr(..) => { @@ -648,11 +747,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Adjust receiver argument. Layout can be any (thin) ptr. - args[0] = ImmTy::from_immediate( - Scalar::from_maybe_pointer(adjusted_receiver, self).into(), - self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?, - ) - .into(); + args[0] = FnArg::Copy( + ImmTy::from_immediate( + Scalar::from_maybe_pointer(adjusted_receiver, self).into(), + self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?, + ) + .into(), + ); trace!("Patched receiver operand to {:#?}", args[0]); // recurse with concrete function self.eval_fn_call( @@ -710,7 +811,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_fn_call( FnVal::Instance(instance), (Abi::Rust, fn_abi), - &[arg.into()], + &[FnArg::Copy(arg.into())], false, &ret.into(), Some(target), diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 7a14459399c..879ae198f7e 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -13,7 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy}; /// A thing that we can project into, and that has a layout. /// This wouldn't have to depend on `Machine` but with the current type inference, /// that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { +pub trait Value<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; @@ -54,7 +54,7 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { /// A thing that we can project into given *mutable* access to `ecx`, and that has a layout. /// This wouldn't have to depend on `Machine` but with the current type inference, /// that's just more convenient to work with (avoids repeating all the `Machine` bounds). -pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized { +pub trait ValueMut<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9352fe3147e..2e26ce111f0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1453,13 +1453,13 @@ mod signal_handler { /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the /// process, print a stack trace and then exit. pub(super) fn install() { + use std::alloc::{alloc, Layout}; + unsafe { - const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024; + let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; let mut alt_stack: libc::stack_t = std::mem::zeroed(); - alt_stack.ss_sp = - std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap()) - as *mut libc::c_void; - alt_stack.ss_size = ALT_STACK_SIZE; + alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast(); + alt_stack.ss_size = alt_stack_size; libc::sigaltstack(&alt_stack, std::ptr::null_mut()); let mut sa: libc::sigaction = std::mem::zeroed(); @@ -1469,6 +1469,23 @@ mod signal_handler { libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut()); } } + + /// Modern kernels on modern hardware can have dynamic signal stack sizes. + #[cfg(any(target_os = "linux", target_os = "android"))] + fn min_sigstack_size() -> usize { + const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51; + let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; + // If getauxval couldn't find the entry, it returns 0, + // so take the higher of the "constant" and auxval. + // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ + libc::MINSIGSTKSZ.max(dynamic_sigstksz as _) + } + + /// Not all OS support hardware where this is needed. + #[cfg(not(any(target_os = "linux", target_os = "android")))] + fn min_sigstack_size() -> usize { + libc::MINSIGSTKSZ + } } #[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))] diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 30bf8c2ad10..3a4eb90f7f9 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -109,8 +109,6 @@ pub enum DefKind { InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, - /// A return-position `impl Trait` in a trait definition - ImplTraitPlaceholder, Field, /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, @@ -143,7 +141,6 @@ impl DefKind { DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct", DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct", DefKind::OpaqueTy => "opaque type", - DefKind::ImplTraitPlaceholder => "opaque type in trait", DefKind::TyAlias => "type alias", DefKind::TraitAlias => "trait alias", DefKind::AssocTy => "associated type", @@ -227,8 +224,7 @@ impl DefKind { | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm - | DefKind::Impl { .. } - | DefKind::ImplTraitPlaceholder => None, + | DefKind::Impl { .. } => None, } } @@ -262,7 +258,6 @@ impl DefKind { | DefKind::Use | DefKind::ForeignMod | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Impl { .. } | DefKind::Field | DefKind::TyParam diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 961deac544a..0d65ddb5642 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -36,7 +36,6 @@ pub enum Target { GlobalAsm, TyAlias, OpaqueTy, - ImplTraitPlaceholder, Enum, Variant, Struct, @@ -80,13 +79,7 @@ impl Target { ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, - ItemKind::OpaqueTy(ref opaque) => { - if opaque.in_trait { - Target::ImplTraitPlaceholder - } else { - Target::OpaqueTy - } - } + ItemKind::OpaqueTy(..) => Target::OpaqueTy, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, ItemKind::Union(..) => Target::Union, @@ -110,7 +103,6 @@ impl Target { DefKind::GlobalAsm => Target::GlobalAsm, DefKind::TyAlias => Target::TyAlias, DefKind::OpaqueTy => Target::OpaqueTy, - DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, DefKind::Union => Target::Union, @@ -165,7 +157,6 @@ impl Target { Target::GlobalAsm => "global asm", Target::TyAlias => "type alias", Target::OpaqueTy => "opaque type", - Target::ImplTraitPlaceholder => "opaque type in trait", Target::Enum => "enum", Target::Variant => "enum variant", Target::Struct => "struct", diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 3d698462840..db3d41ed247 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2128,7 +2128,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let span = path.span; match path.res { - Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => { + Res::Def(DefKind::OpaqueTy, did) => { // Check for desugared `impl Trait`. assert!(tcx.is_type_alias_impl_trait(did)); let item_segment = path.segments.split_last().unwrap(); @@ -2439,7 +2439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. - let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() { + let def_id = if in_trait { tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id() } else { local_def_id.to_def_id() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 120545c8e5d..91c33b09082 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -302,16 +302,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), - in_trait, .. }) = item.kind { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - Ty::new_projection(tcx, def_id.to_def_id(), substs) - } else { - Ty::new_opaque(tcx, def_id.to_def_id(), substs) - }; + let opaque_identity_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs); let mut visitor = ProhibitOpaqueVisitor { opaque_identity_ty, parent_count: tcx.generics_of(def_id).parent_count as u32, @@ -576,17 +571,6 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_opaque(tcx, id); } } - DefKind::ImplTraitPlaceholder => { - let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id()); - // Only check the validity of this opaque type if the function has a default body - if let hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), - .. - }) = tcx.hir().get_by_def_id(parent.expect_local()) - { - check_opaque(tcx, id); - } - } DefKind::TyAlias => { let pty_ty = tcx.type_of(id.owner_id).subst_identity(); let generics = tcx.generics_of(id.owner_id); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 57f74172ed0..d6f33869a03 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -113,16 +113,12 @@ pub(super) fn explicit_item_bounds( .. }) => associated_type_bounds(tcx, def_id, bounds, *span), hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }), + kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }), span, .. }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - Ty::new_projection(tcx, def_id.to_def_id(), substs) - } else { - Ty::new_opaque(tcx, def_id.to_def_id(), substs) - }; + let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs); opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 5526dd4b007..d654b0be620 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -109,20 +109,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) vec![] } } - ty::AssocKind::Fn => { - if !tcx.lower_impl_trait_in_trait_to_assoc_ty() - && item.defaultness(tcx).has_value() - && tcx.impl_method_has_trait_impl_trait_tys(item.def_id) - && let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id) - { - table.values().copied().flat_map(|ty| { - cgp::parameters_for(&ty.subst_identity(), true) - }).collect() - } else { - vec![] - } - } - ty::AssocKind::Const => vec![], + ty::AssocKind::Fn | ty::AssocKind::Const => vec![], } }) .collect(); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 066e7449189..c703cb03515 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -56,7 +56,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } - DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { + DefKind::OpaqueTy => { return variance_of_opaque(tcx, item_def_id); } _ => {} @@ -115,14 +115,6 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc { self.visit_opaque(*def_id, substs) } - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary - // at all for RPITITs. - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if self.tcx.is_impl_trait_in_trait(*def_id) - && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() => - { - self.visit_opaque(*def_id, substs) - } _ => t.super_visit_with(self), } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6f82ffcfe4a..862430f5eb1 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -141,7 +141,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> { - &*tcx.typeck(def_id).used_trait_imports + &tcx.typeck(def_id).used_trait_imports } fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e52cea1889f..c59e9e315b1 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -12,7 +12,6 @@ pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; use crate::FnCtxt; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -190,11 +189,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); - for import_id in &pick.import_ids { + for &import_id in &pick.import_ids { debug!("used_trait_import: {:?}", import_id); - Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports) - .unwrap() - .insert(*import_id); + self.typeck_results.borrow_mut().used_trait_imports.insert(import_id); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None); @@ -567,10 +564,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?pick); { let mut typeck_results = self.typeck_results.borrow_mut(); - let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); for import_id in pick.import_ids { debug!(used_trait_import=?import_id); - used_trait_imports.insert(import_id); + typeck_results.used_trait_imports.insert(import_id); } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 42f4531c0ef..69c8cc8c590 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -335,8 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_vars_with_obligations(expected); - + let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches // the `Some(5)` which is not of type Ref. @@ -353,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Preserve the reference type. We'll need it later during THIR lowering. pat_adjustments.push(expected); - expected = inner_ty; + expected = self.try_structurally_resolve_type(pat.span, inner_ty); def_bm = ty::BindByReference(match def_bm { // If default binding mode is by value, make it `ref` or `ref mut` // (depending on whether we observe `&` or `&mut`). @@ -627,6 +626,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { local_ty } + /// When a variable is bound several times in a `PatKind::Or`, it'll resolve all of the + /// subsequent bindings of the same name to the first usage. Verify that all of these + /// bindings have the same type by comparing them all against the type of that first pat. fn check_binding_alt_eq_ty( &self, ba: hir::BindingAnnotation, @@ -638,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let var_ty = self.local_ty(span, var_id); if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); - let var_ty = self.resolve_vars_with_obligations(var_ty); + let var_ty = self.resolve_vars_if_possible(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); err.span_label(hir.span(var_id), msg); let in_match = hir.parent_iter(var_id).any(|(_, n)| { @@ -656,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, span, var_ty, - self.resolve_vars_with_obligations(ty), + self.resolve_vars_if_possible(ty), ba, ); err.emit(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bb75ecc6adb..a90a41f5d70 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -162,10 +162,18 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte let mut infcx_inner = infcx.inner.borrow_mut(); let ty_vars = infcx_inner.type_variables(); let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind && !var_origin.span.from_expansion() { - Some(name) + let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); + let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); + let generic_param_def = generics.param_at(idx as usize, infcx.tcx); + if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind + { + None + } else { + Some(name) + } } else { None } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 1422bdc9ea2..b0e7cf23cae 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -464,52 +464,53 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, ) -> Option<TypeErrorAdditionalDiags> { let hir = self.tcx.hir(); - if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && - let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_sig, _, body_id), .. - }) = node { - let body = hir.body(*body_id); - - /// Find the if expression with given span - struct IfVisitor { - pub result: bool, - pub found_if: bool, - pub err_span: Span, - } + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) { + let body = hir.body(body_id); + + /// Find the if expression with given span + struct IfVisitor { + pub result: bool, + pub found_if: bool, + pub err_span: Span, + } - impl<'v> Visitor<'v> for IfVisitor { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - if self.result { return; } - match ex.kind { - hir::ExprKind::If(cond, _, _) => { - self.found_if = true; - walk_expr(self, cond); - self.found_if = false; + impl<'v> Visitor<'v> for IfVisitor { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.result { + return; + } + match ex.kind { + hir::ExprKind::If(cond, _, _) => { + self.found_if = true; + walk_expr(self, cond); + self.found_if = false; + } + _ => walk_expr(self, ex), } - _ => walk_expr(self, ex), } - } - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if let hir::StmtKind::Local(hir::Local { - span, pat: hir::Pat{..}, ty: None, init: Some(_), .. - }) = &ex.kind - && self.found_if - && span.eq(&self.err_span) { - self.result = true; + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + if let hir::StmtKind::Local(hir::Local { + span, pat: hir::Pat{..}, ty: None, init: Some(_), .. + }) = &ex.kind + && self.found_if + && span.eq(&self.err_span) { + self.result = true; + } + walk_stmt(self, ex); } - walk_stmt(self, ex); - } - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - hir::intravisit::walk_body(self, body); + fn visit_body(&mut self, body: &'v hir::Body<'v>) { + hir::intravisit::walk_body(self, body); + } } - } - let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; - visitor.visit_body(&body); - if visitor.result { - return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()}); + let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; + visitor.visit_body(&body); + if visitor.result { + return Some(TypeErrorAdditionalDiags::AddLetForLetChains { + span: span.shrink_to_lo(), + }); } } None diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fca32b73d1d..a123effd0f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -332,6 +332,39 @@ pub struct InferCtxt<'tcx> { next_trait_solver: bool, } +impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> { + fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> { + use InferTy::*; + match ty { + // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved + // ty infers will give you the universe of the var it resolved to not the universe + // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then + // try to print out `?0.1` it will just print `?0`. + TyVar(ty_vid) => match self.probe_ty_var(ty_vid) { + Err(universe) => Some(universe), + Ok(_) => None, + }, + IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => None, + } + } + + fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> { + use ty::InferConst::*; + match ct { + // Same issue as with `universe_of_ty` + Var(ct_vid) => match self.probe_const_var(ct_vid) { + Err(universe) => Some(universe), + Ok(_) => None, + }, + Fresh(_) => None, + } + } + + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { + Some(self.universe_of_region_vid(lt)) + } +} + /// See the `error_reporting` module for more details. #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub enum ValuePairs<'tcx> { @@ -1068,6 +1101,11 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().universe(r) } + /// Return the universe that the region variable `r` was created in. + pub fn universe_of_region_vid(&self, vid: ty::RegionVid) -> ty::UniverseIndex { + self.inner.borrow_mut().unwrap_region_constraints().var_universe(vid) + } + /// Number of region variables created so far. pub fn num_region_vars(&self) -> usize { self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 34b7e09576a..2c92277b50d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -215,6 +215,9 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} +lint_fn_null_check = function pointers are not nullable, so checking them for null will always return false + .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value + lint_for_loops_over_fallibles = for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent diff --git a/compiler/rustc_lint/src/fn_null_check.rs b/compiler/rustc_lint/src/fn_null_check.rs new file mode 100644 index 00000000000..e3b33463ccf --- /dev/null +++ b/compiler/rustc_lint/src/fn_null_check.rs @@ -0,0 +1,112 @@ +use crate::{lints::FnNullCheckDiag, LateContext, LateLintPass, LintContext}; +use rustc_ast::LitKind; +use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; + +declare_lint! { + /// The `incorrect_fn_null_checks` lint checks for expression that checks if a + /// function pointer is null. + /// + /// ### Example + /// + /// ```rust + /// # fn test() {} + /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */ + /// # test; + /// + /// if (fn_ptr as *const ()).is_null() { /* ... */ } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Function pointers are assumed to be non-null, checking them for null will always + /// return false. + INCORRECT_FN_NULL_CHECKS, + Warn, + "incorrect checking of null function pointer" +} + +declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]); + +fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let mut expr = expr.peel_blocks(); + let mut had_at_least_one_cast = false; + while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind + && let TyKind::Ptr(_) = cast_ty.kind { + expr = cast_expr.peel_blocks(); + had_at_least_one_cast = true; + } + had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn() +} + +impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + match expr.kind { + // Catching: + // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>) + ExprKind::Call(path, [arg]) + if let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_const_is_null | sym::ptr_is_null) + ) + && is_fn_ptr_cast(cx, arg) => + { + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + } + + // Catching: + // (fn_ptr as *<const/mut> <ty>).is_null() + ExprKind::MethodCall(_, receiver, _, _) + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_const_is_null | sym::ptr_is_null) + ) + && is_fn_ptr_cast(cx, receiver) => + { + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + } + + ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => { + let to_check: &Expr<'_>; + if is_fn_ptr_cast(cx, left) { + to_check = right; + } else if is_fn_ptr_cast(cx, right) { + to_check = left; + } else { + return; + } + + match to_check.kind { + // Catching: + // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>) + ExprKind::Cast(cast_expr, _) + if let ExprKind::Lit(spanned) = cast_expr.kind + && let LitKind::Int(v, _) = spanned.node && v == 0 => + { + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + }, + + // Catching: + // (fn_ptr as *<const/mut> <ty>) == std::ptr::null() + ExprKind::Call(path, []) + if let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => + { + cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag) + }, + + _ => {}, + } + } + _ => {} + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 5e3f057d428..beb38dbb94c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -58,6 +58,7 @@ mod early; mod enum_intrinsics_non_enums; mod errors; mod expect; +mod fn_null_check; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; @@ -102,6 +103,7 @@ use cast_ref_to_mut::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; +use fn_null_check::*; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; @@ -225,6 +227,7 @@ late_lint_methods!( // Depends on types used in type definitions MissingCopyImplementations: MissingCopyImplementations, // Depends on referenced function signatures in expressions + IncorrectFnNullChecks: IncorrectFnNullChecks, MutableTransmutes: MutableTransmutes, TypeAliasBounds: TypeAliasBounds, TrivialConstraints: TrivialConstraints, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0613ef2c5e9..1dea758bb29 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -613,6 +613,12 @@ pub struct ExpectationNote { pub rationale: Symbol, } +// fn_null_check.rs +#[derive(LintDiagnostic)] +#[diag(lint_fn_null_check)] +#[help] +pub struct FnNullCheckDiag; + // for_loops_over_fallibles.rs #[derive(LintDiagnostic)] #[diag(lint_for_loops_over_fallibles)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 87c542dc2e2..a0f2e9aed81 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4084,7 +4084,7 @@ declare_lint! { /// /// ### Explanation /// - /// The preferred location for where clauses on associated types in impls + /// The preferred location for where clauses on associated types /// is after the type. However, for most of generic associated types development, /// it was only accepted before the equals. To provide a transition period and /// further evaluate this change, both are currently accepted. At some point in diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index bb7510b3a53..ab5fa961b95 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1616,17 +1616,6 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMSetLinkage(V, fromRust(RustLinkage)); } -// FIXME: replace with LLVMConstInBoundsGEP2 when bumped minimal version to llvm-14 -extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty, - LLVMValueRef ConstantVal, - LLVMValueRef *ConstantIndices, - unsigned NumIndices) { - ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices), - NumIndices); - Constant *Val = unwrap<Constant>(ConstantVal); - return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList)); -} - extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) { auto C = unwrap<llvm::ConstantInt>(CV); if (C->getBitWidth() > 64) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 541c19c3561..01dd35b0e5b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -824,7 +824,6 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::Impl { .. } | DefKind::Closure @@ -867,7 +866,6 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Generator => false, @@ -902,7 +900,6 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm @@ -939,7 +936,6 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure @@ -966,7 +962,6 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::ForeignMod | DefKind::TyAlias | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Enum | DefKind::Union | DefKind::Impl { .. } @@ -1033,7 +1028,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Enum | DefKind::Variant | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn => true, @@ -1083,7 +1077,6 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Impl { .. } | DefKind::Field | DefKind::TyParam @@ -1134,19 +1127,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> } } - DefKind::ImplTraitPlaceholder => { - let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id()); - let assoc_item = tcx.associated_item(parent_def_id); - match assoc_item.container { - // Always encode an RPIT in an impl fn, since it always has a body - ty::AssocItemContainer::ImplContainer => true, - ty::AssocItemContainer::TraitContainer => { - // Encode an RPIT for a trait only if the trait has a default body - assoc_item.defaultness(tcx).has_value() - } - } - } - DefKind::AssocTy => { let assoc_item = tcx.associated_item(def_id); match assoc_item.container { @@ -1192,7 +1172,6 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool { | DefKind::Ctor(..) | DefKind::TyAlias | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::ForeignTy | DefKind::Impl { .. } | DefKind::AssocConst @@ -1235,7 +1214,6 @@ fn should_encode_constness(def_kind: DefKind) -> bool { | DefKind::TyAlias | DefKind::OpaqueTy | DefKind::Impl { of_trait: false } - | DefKind::ImplTraitPlaceholder | DefKind::ForeignTy | DefKind::Generator | DefKind::ConstParam @@ -1268,7 +1246,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::Static(..) | DefKind::TyAlias | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::ForeignTy | DefKind::Impl { .. } | DefKind::AssocFn @@ -1289,11 +1266,8 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -// We only encode impl trait in trait when using `lower-impl-trait-in-trait-to-assoc-ty` unstable -// option. fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - if tcx.lower_impl_trait_in_trait_to_assoc_ty() - && let Some(assoc_item) = tcx.opt_associated_item(def_id) + if let Some(assoc_item) = tcx.opt_associated_item(def_id) && assoc_item.container == ty::AssocItemContainer::TraitContainer && assoc_item.kind == ty::AssocKind::Fn { @@ -1447,9 +1421,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .is_type_alias_impl_trait .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); } - if let DefKind::ImplTraitPlaceholder = def_kind { - self.encode_explicit_item_bounds(def_id); - } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index f002d7f97b9..a4313d79ab1 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -142,7 +142,6 @@ fixed_size_enum! { ( AnonConst ) ( InlineConst ) ( OpaqueTy ) - ( ImplTraitPlaceholder ) ( Field ) ( LifetimeParam ) ( GlobalAsm ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5f2eb890c4e..6bb8e632dbe 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -195,13 +195,7 @@ impl<'hir> Map<'hir> { ItemKind::Fn(..) => DefKind::Fn, ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, - ItemKind::OpaqueTy(ref opaque) => { - if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { - DefKind::ImplTraitPlaceholder - } else { - DefKind::OpaqueTy - } - } + ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, ItemKind::TyAlias(..) => DefKind::TyAlias, ItemKind::Enum(..) => DefKind::Enum, ItemKind::Struct(..) => DefKind::Struct, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 7f1d3820341..8c8efc36a2f 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1050,10 +1050,6 @@ pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; /// there may be other effects: if the type has a validity constraint loading the place might be UB /// if the validity constraint is not met. /// -/// **Needs clarification:** Ralf proposes that loading a place not have side-effects. -/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this -/// something we can even decide without knowing more about Rust's memory model? -/// /// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri /// currently implements it, but it seems like this may be something to check against in the /// validator. @@ -1071,6 +1067,16 @@ pub enum Operand<'tcx> { /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this /// place without first re-initializing it. /// + /// **Needs clarification:** The operational impact of `Move` is unclear. Currently (both in + /// Miri and codegen) it has no effect at all unless it appears in an argument to `Call`; for + /// `Call` it allows the argument to be passed to the callee "in-place", i.e. the callee might + /// just get a reference to this place instead of a full copy. Miri implements this with a + /// combination of aliasing model "protectors" and putting `uninit` into the place. Ralf + /// proposes that we don't want these semantics for `Move` in regular assignments, because + /// loading a place should not have side-effects, and the aliasing model "protectors" are + /// inherently tied to a function call. Are these the semantics we want for MIR? Is this + /// something we can even decide without knowing more about Rust's memory model? + /// /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 Move(Place<'tcx>), diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index a6bf7491118..5f2b6d42bf8 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; /// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, @@ -35,7 +35,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { Binop(mir::BinOp, Const<'tcx>, Const<'tcx>), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 035e978f64c..6990fbbb634 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1036,7 +1036,9 @@ impl<'tcx> TyCtxt<'tcx> { scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); - let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) else { + let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = + self.hir().fn_decl_by_hir_id(hir_id) + else { return vec![]; }; @@ -2002,16 +2004,8 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool { - self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty - } - pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { - if self.lower_impl_trait_in_trait_to_assoc_ty() { - self.opt_rpitit_info(def_id).is_some() - } else { - self.def_kind(def_id) == DefKind::ImplTraitPlaceholder - } + self.opt_rpitit_info(def_id).is_some() } /// Named module children from all kinds of items, including imports. diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 71911a5a618..7a32cfb1085 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,6 +1,7 @@ use crate::arena::Arena; use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; +use rustc_type_ir::{InferCtxtLike, OptWithInfcx}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; @@ -119,6 +120,14 @@ impl<T: fmt::Debug> fmt::Debug for List<T> { (**self).fmt(f) } } +impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + fmt::Debug::fmt(&this.map(|this| this.as_slice()), f) + } +} impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> { #[inline] @@ -202,6 +211,8 @@ unsafe impl<T: Sync> Sync for List<T> {} // We need this since `List` uses extern type `OpaqueListContents`. #[cfg(parallel_compiler)] use rustc_data_structures::sync::DynSync; + +use super::TyCtxt; #[cfg(parallel_compiler)] unsafe impl<T: DynSync> DynSync for List<T> {} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index aa8bfd3178c..519bdb01623 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -53,6 +53,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use subst::*; pub use vtable::*; @@ -2688,7 +2689,6 @@ impl<'tcx> TyCtxt<'tcx> { | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id, None => { while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { - debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); def_id = self.parent(def_id); } def_id @@ -2720,26 +2720,9 @@ impl<'tcx> TyCtxt<'tcx> { let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; - if self.lower_impl_trait_in_trait_to_assoc_ty() { - return !self - .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) - .is_empty(); - } - - // FIXME(RPITIT): This does a somewhat manual walk through the signature - // of the trait fn to look for any RPITITs, but that's kinda doing a lot - // of work. We can probably remove this when we refactor RPITITs to be - // associated types. - self.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, data) = ty.kind() - && self.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder - { - true - } else { - false - } - }) + return !self + .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) + .is_empty(); } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 5741832c980..54dedf31d9f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -567,15 +567,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // Alias tend to mostly already be handled downstream due to normalization. (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This if can be removed - // and the assert uncommented once the new desugaring is stable. - if a_kind == b_kind { - let alias_ty = relation.relate(a_data, b_data)?; - // assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) - } else { - Err(TypeError::Sorts(expected_found(relation, a, b))) - } + let alias_ty = relation.relate(a_data, b_data)?; + assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7220d133f68..c82ce9112fc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,13 +11,15 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_index::{Idx, IndexVec}; use rustc_target::abi::TyAndLayout; -use rustc_type_ir::ConstKind; +use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; -use std::fmt; +use std::fmt::{self, Debug}; use std::ops::ControlFlow; use std::rc::Rc; use std::sync::Arc; +use super::{GenericArg, GenericArgKind, Region}; + impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { @@ -89,7 +91,16 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self; + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + let sig = this.data; + let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig; write!(f, "{}", unsafety.prefix_str())?; match abi { @@ -98,15 +109,15 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { }; write!(f, "fn(")?; - let inputs = self.inputs(); + let inputs = sig.inputs(); match inputs.len() { 0 if *c_variadic => write!(f, "...)")?, 0 => write!(f, ")")?, _ => { - for ty in &self.inputs()[0..(self.inputs().len() - 1)] { - write!(f, "{ty:?}, ")?; + for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] { + write!(f, "{:?}, ", &this.wrap(ty))?; } - write!(f, "{:?}", self.inputs().last().unwrap())?; + write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?; if *c_variadic { write!(f, "...")?; } @@ -114,9 +125,9 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { } } - match self.output().kind() { + match sig.output().kind() { ty::Tuple(list) if list.is_empty() => Ok(()), - _ => write!(f, " -> {:?}", self.output()), + _ => write!(f, " -> {:?}", &this.wrap(sig.output())), } } } @@ -133,6 +144,14 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { } } +impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + this.data.fmt(f) + } +} impl<'tcx> fmt::Debug for Ty<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { with_no_trimmed_paths!(fmt::Display::fmt(self, f)) @@ -217,9 +236,17 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { impl<'tcx> fmt::Debug for AliasTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { f.debug_struct("AliasTy") - .field("substs", &self.substs) - .field("def_id", &self.def_id) + .field("substs", &this.map(|data| data.substs)) + .field("def_id", &this.data.def_id) .finish() } } @@ -232,13 +259,93 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { } } } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + use ty::InferConst::*; + match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) { + None => write!(f, "{:?}", this.data), + Some(universe) => match *this.data { + Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()), + Fresh(_) => { + unreachable!() + } + }, + } + } +} + +impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data { + ty::Expr::Binop(op, lhs, rhs) => { + write!(f, "({op:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + } + ty::Expr::UnOp(op, rhs) => write!(f, "({op:?}: {:?})", &this.wrap(rhs)), + ty::Expr::FunctionCall(func, args) => { + write!(f, "{:?}(", &this.wrap(func))?; + for arg in args.as_slice().iter().rev().skip(1).rev() { + write!(f, "{:?}, ", &this.wrap(arg))?; + } + if let Some(arg) = args.last() { + write!(f, "{:?}", &this.wrap(arg))?; + } + + write!(f, ")") + } + ty::Expr::Cast(cast_kind, lhs, rhs) => { + write!(f, "({cast_kind:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + } + } + } +} + +impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("UnevaluatedConst") + .field("def", &this.data.def) + .field("substs", &this.wrap(this.data.substs)) + .finish() + } +} impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { // This reflects what `Const` looked liked before `Interned` was // introduced. We print it like this to avoid having to update expected // output in a lot of tests. - write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind()) + write!( + f, + "Const {{ ty: {:?}, kind: {:?} }}", + &this.map(|data| data.ty()), + &this.map(|data| data.kind()) + ) } } @@ -261,6 +368,66 @@ impl<T: fmt::Debug> fmt::Debug for ty::Placeholder<T> { } } +impl<'tcx> fmt::Debug for GenericArg<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.unpack() { + GenericArgKind::Lifetime(lt) => lt.fmt(f), + GenericArgKind::Type(ty) => ty.fmt(f), + GenericArgKind::Const(ct) => ct.fmt(f), + } + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data.unpack() { + GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)), + GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)), + GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)), + } + } +} + +impl<'tcx> fmt::Debug for Region<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + write!(f, "{:?}", &this.map(|data| data.kind())) + } +} + +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) { + Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()), + None => write!(f, "{:?}", this.data), + } + } +} + +impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { + fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( + this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_tuple("Binder") + .field(&this.map(|data| data.as_ref().skip_binder())) + .field(&this.data.bound_vars()) + .finish() + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 94746fbdc19..9f4515b95e7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -35,9 +35,12 @@ use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::CollectAndApply; +use rustc_type_ir::ConstKind as IrConstKind; +use rustc_type_ir::DebugWithInfcx; +use rustc_type_ir::DynKind; +use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; -use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind}; -use rustc_type_ir::{DynKind, RegionKind as IrRegionKind}; use super::GenericParamDefKind; @@ -694,6 +697,15 @@ pub enum ExistentialPredicate<'tcx> { AutoTrait(DefId), } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> { + fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>( + this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + fmt::Debug::fmt(&this.data, f) + } +} + impl<'tcx> ExistentialPredicate<'tcx> { /// Compares via an ordering that will not change if modules are reordered or other changes are /// made to the tree. In particular, this ordering is preserved across incremental compilations. @@ -1237,7 +1249,7 @@ impl<'tcx> AliasTy<'tcx> { pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind { match tcx.def_kind(self.def_id) { DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent, - DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection, + DefKind::AssocTy => ty::Projection, DefKind::OpaqueTy => ty::Opaque, DefKind::TyAlias => ty::Weak, kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), @@ -1265,9 +1277,6 @@ impl<'tcx> AliasTy<'tcx> { pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { match tcx.def_kind(self.def_id) { DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - DefKind::ImplTraitPlaceholder => { - tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id)) - } kind => bug!("expected a projection AliasTy; found {kind:?}"), } } @@ -1574,12 +1583,6 @@ impl<'tcx> Deref for Region<'tcx> { } } -impl<'tcx> fmt::Debug for Region<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind()) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] #[derive(HashStable)] pub struct EarlyBoundRegion { @@ -1970,7 +1973,6 @@ impl<'tcx> Ty<'tcx> { (kind, tcx.def_kind(alias_ty.def_id)), (ty::Opaque, DefKind::OpaqueTy) | (ty::Projection | ty::Inherent, DefKind::AssocTy) - | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) | (ty::Weak, DefKind::TyAlias) ); Ty::new(tcx, Alias(kind, alias_ty)) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 4d5f5b8658c..e1a58b97557 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -17,7 +17,6 @@ use smallvec::SmallVec; use core::intrinsics; use std::cmp::Ordering; -use std::fmt; use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; @@ -80,16 +79,6 @@ impl<'tcx> GenericArgKind<'tcx> { } } -impl<'tcx> fmt::Debug for GenericArg<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.fmt(f), - GenericArgKind::Type(ty) => ty.fmt(f), - GenericArgKind::Const(ct) => ct.fmt(f), - } - } -} - impl<'tcx> Ord for GenericArg<'tcx> { fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering { self.unpack().cmp(&other.unpack()) diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 8cbffa14850..e85afeb4b6e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -7,11 +7,8 @@ use crate::{ GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, }, }; -use rustc_data_structures::{ - fx::{FxHashMap, FxIndexMap}, - sync::Lrc, - unord::{UnordItems, UnordSet}, -}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::unord::{UnordItems, UnordSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::{ @@ -145,7 +142,7 @@ pub struct TypeckResults<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc<UnordSet<LocalDefId>>, + pub used_trait_imports: UnordSet<LocalDefId>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorGuaranteed)`. @@ -273,7 +270,7 @@ impl<'tcx> TypeckResults<'tcx> { liberated_fn_sigs: Default::default(), fru_field_types: Default::default(), coercion_casts: Default::default(), - used_trait_imports: Lrc::new(Default::default()), + used_trait_imports: Default::default(), tainted_by_errors: None, concrete_opaque_types: Default::default(), closure_min_captures: Default::default(), diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 98cec1c6760..cb74bea724a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -731,11 +731,11 @@ fn switch_on_enum_discriminant<'mir, 'tcx>( struct OnMutBorrow<F>(F); -impl<F> Visitor<'_> for OnMutBorrow<F> +impl<'tcx, F> Visitor<'tcx> for OnMutBorrow<F> where - F: FnMut(&mir::Place<'_>), + F: FnMut(&mir::Place<'tcx>), { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { // FIXME: Does `&raw const foo` allow mutation? See #90413. match rvalue { mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place) @@ -756,7 +756,7 @@ where fn for_each_mut_borrow<'tcx>( mir: &impl MirVisitable<'tcx>, location: Location, - f: impl FnMut(&mir::Place<'_>), + f: impl FnMut(&mir::Place<'tcx>), ) { let mut vis = OnMutBorrow(f); diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index d43446bc5b2..900d438f8d5 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -43,6 +43,7 @@ pub mod impls; pub mod move_paths; pub mod rustc_peek; pub mod storage; +pub mod un_derefer; pub mod value_analysis; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index dc7e9ab3ce6..5052de99184 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -4,7 +4,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use smallvec::{smallvec, SmallVec}; -use std::iter; use std::mem; use super::abs_domain::Lift; @@ -40,22 +39,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { locals: body .local_decls .iter_enumerated() - .filter(|(_, l)| !l.is_deref_temp()) - .map(|(i, _)| { - ( - i, + .map(|(i, l)| { + if l.is_deref_temp() { + MovePathIndex::MAX + } else { Self::new_move_path( &mut move_paths, &mut path_map, &mut init_path_map, None, Place::from(i), - ), - ) + ) + } }) .collect(), projections: Default::default(), - derefer_sidetable: Default::default(), + un_derefer: Default::default(), }, move_paths, path_map, @@ -100,11 +99,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> { - let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref()); + let data = &mut self.builder.data; debug!("lookup({:?})", place); - let mut base = - self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local); + let mut base = data.rev_lookup.find_local(place.local); // The move path index of the first union that we find. Once this is // some we stop creating child move paths, since moves from unions @@ -113,55 +111,60 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // from `*(u.f: &_)` isn't allowed. let mut union_path = None; - for place in deref_chain.into_iter().chain(iter::once(place)) { - for (place_ref, elem) in place.as_ref().iter_projections() { - let body = self.builder.body; - let tcx = self.builder.tcx; - let place_ty = place_ref.ty(body, tcx).ty; - match place_ty.kind() { - ty::Ref(..) | ty::RawPtr(..) => { - return Err(MoveError::cannot_move_out_of( - self.loc, - BorrowedContent { - target_place: place_ref.project_deeper(&[elem], tcx), - }, - )); - } - ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfTypeWithDestructor { container_ty: place_ty }, - )); - } - ty::Adt(adt, _) if adt.is_union() => { - union_path.get_or_insert(base); - } - ty::Slice(_) => { + for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) { + let body = self.builder.body; + let tcx = self.builder.tcx; + let place_ty = place_ref.ty(body, tcx).ty; + match place_ty.kind() { + ty::Ref(..) | ty::RawPtr(..) => { + return Err(MoveError::cannot_move_out_of( + self.loc, + BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) }, + )); + } + ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfTypeWithDestructor { container_ty: place_ty }, + )); + } + ty::Adt(adt, _) if adt.is_union() => { + union_path.get_or_insert(base); + } + ty::Slice(_) => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, + is_index: matches!(elem, ProjectionElem::Index(..)), + }, + )); + } + + ty::Array(..) => { + if let ProjectionElem::Index(..) = elem { return Err(MoveError::cannot_move_out_of( self.loc, - InteriorOfSliceOrArray { - ty: place_ty, - is_index: matches!(elem, ProjectionElem::Index(..)), - }, + InteriorOfSliceOrArray { ty: place_ty, is_index: true }, )); } + } - ty::Array(..) => { - if let ProjectionElem::Index(..) = elem { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { ty: place_ty, is_index: true }, - )); - } - } - - _ => {} - }; + _ => {} + }; - if union_path.is_none() { - base = self - .add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx)); - } + if union_path.is_none() { + // inlined from add_move_path because of a borrowck conflict with the iterator + base = + *data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| { + MoveDataBuilder::new_move_path( + &mut data.move_paths, + &mut data.path_map, + &mut data.init_path_map, + Some(base), + place_ref.project_deeper(&[elem], tcx), + ) + }) } } @@ -282,10 +285,14 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match &stmt.kind { StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { - assert!(place.projection.is_empty()); - if self.builder.body.local_decls[place.local].is_deref_temp() { - self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed); - } + let local = place.as_local().unwrap(); + assert!(self.builder.body.local_decls[local].is_deref_temp()); + + let rev_lookup = &mut self.builder.data.rev_lookup; + + rev_lookup.un_derefer.insert(local, reffed.as_ref()); + let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local; + rev_lookup.locals[local] = rev_lookup.locals[base_local]; } StatementKind::Assign(box (place, rval)) => { self.create_move_path(*place); @@ -306,7 +313,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { // DerefTemp locals (results of CopyForDeref) don't actually move anything. - if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) { + if !self.builder.body.local_decls[*local].is_deref_temp() { self.gather_move(Place::from(*local)); } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index aa901f66d3f..0c7aa6676ec 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -1,5 +1,6 @@ use crate::move_paths::builder::MoveDat; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use crate::un_derefer::UnDerefer; +use rustc_data_structures::fx::FxHashMap; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::*; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; @@ -290,7 +291,7 @@ impl Init { /// Tables mapping from a place to its MovePathIndex. #[derive(Debug)] pub struct MovePathLookup<'tcx> { - locals: FxIndexMap<Local, MovePathIndex>, + locals: IndexVec<Local, MovePathIndex>, /// projections are made from a base-place and a projection /// elem. The base-place will have a unique MovePathIndex; we use @@ -300,8 +301,7 @@ pub struct MovePathLookup<'tcx> { /// elem to the associated MovePathIndex. projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>, - /// Maps `DerefTemp` locals to the `Place`s assigned to them. - derefer_sidetable: FxHashMap<Local, Place<'tcx>>, + un_derefer: UnDerefer<'tcx>, } mod builder; @@ -317,54 +317,23 @@ impl<'tcx> MovePathLookup<'tcx> { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place: PlaceRef<'_>) -> LookupResult { - let deref_chain = self.deref_chain(place); + pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult { + let mut result = self.find_local(place.local); - let local = match deref_chain.first() { - Some(place) => place.local, - None => place.local, - }; - - let mut result = *self.locals.get(&local).unwrap_or_else(|| { - bug!("base local ({local:?}) of deref_chain should not be a deref temp") - }); - - // this needs to be a closure because `place` has a different lifetime than `prefix`'s places - let mut subpaths_for_place = |place: PlaceRef<'_>| { - for elem in place.projection.iter() { - if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { - result = subpath; - } else { - return Some(result); - } - } - None - }; - - for place in deref_chain { - if let Some(result) = subpaths_for_place(place.as_ref()) { + for (_, elem) in self.un_derefer.iter_projections(place) { + if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + result = subpath; + } else { return LookupResult::Parent(Some(result)); } } - if let Some(result) = subpaths_for_place(place) { - return LookupResult::Parent(Some(result)); - } - LookupResult::Exact(result) } + #[inline] pub fn find_local(&self, local: Local) -> MovePathIndex { - let deref_chain = self.deref_chain(Place::from(local).as_ref()); - - let local = match deref_chain.last() { - Some(place) => place.local, - None => local, - }; - - *self.locals.get(&local).unwrap_or_else(|| { - bug!("base local ({local:?}) of deref_chain should not be a deref temp") - }) + self.locals[local] } /// An enumerated iterator of `local`s and their associated @@ -372,22 +341,7 @@ impl<'tcx> MovePathLookup<'tcx> { pub fn iter_locals_enumerated( &self, ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ { - self.locals.iter().map(|(&l, &idx)| (l, idx)) - } - - /// Returns the chain of places behind `DerefTemp` locals in `place` - pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> { - let mut prefix = Vec::new(); - let mut local = place.local; - - while let Some(&reffed) = self.derefer_sidetable.get(&local) { - prefix.insert(0, reffed); - local = reffed.local; - } - - debug!("deref_chain({place:?}) = {prefix:?}"); - - prefix + self.locals.iter_enumerated().map(|(l, &idx)| (l, idx)) } } diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs new file mode 100644 index 00000000000..874d50ffd0e --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -0,0 +1,100 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::mir::*; + +/// Used for reverting changes made by `DerefSeparator` +#[derive(Default, Debug)] +pub struct UnDerefer<'tcx> { + deref_chains: FxHashMap<Local, Vec<PlaceRef<'tcx>>>, +} + +impl<'tcx> UnDerefer<'tcx> { + #[inline] + pub fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) { + let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default(); + chain.push(reffed); + self.deref_chains.insert(local, chain); + } + + /// Returns the chain of places behind `DerefTemp` locals + #[inline] + pub fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] { + self.deref_chains.get(&local).map(Vec::as_slice).unwrap_or_default() + } + + /// Iterates over the projections of a place and its deref chain. + /// + /// See [`PlaceRef::iter_projections`] + #[inline] + pub fn iter_projections( + &self, + place: PlaceRef<'tcx>, + ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + '_ { + ProjectionIter::new(self.deref_chain(place.local), place) + } +} + +/// The iterator returned by [`UnDerefer::iter_projections`]. +struct ProjectionIter<'a, 'tcx> { + places: SlicePlusOne<'a, PlaceRef<'tcx>>, + proj_idx: usize, +} + +impl<'a, 'tcx> ProjectionIter<'a, 'tcx> { + #[inline] + fn new(deref_chain: &'a [PlaceRef<'tcx>], place: PlaceRef<'tcx>) -> Self { + // just return an empty iterator for a bare local + let last = if place.as_local().is_none() { + Some(place) + } else { + debug_assert!(deref_chain.is_empty()); + None + }; + + ProjectionIter { places: SlicePlusOne { slice: deref_chain, last }, proj_idx: 0 } + } +} + +impl<'tcx> Iterator for ProjectionIter<'_, 'tcx> { + type Item = (PlaceRef<'tcx>, PlaceElem<'tcx>); + + #[inline] + fn next(&mut self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { + let place = self.places.read()?; + + // the projection should never be empty except for a bare local which is handled in new + let partial_place = + PlaceRef { local: place.local, projection: &place.projection[..self.proj_idx] }; + let elem = place.projection[self.proj_idx]; + + if self.proj_idx == place.projection.len() - 1 { + self.proj_idx = 0; + self.places.advance(); + } else { + self.proj_idx += 1; + } + + Some((partial_place, elem)) + } +} + +struct SlicePlusOne<'a, T> { + slice: &'a [T], + last: Option<T>, +} + +impl<T: Copy> SlicePlusOne<'_, T> { + #[inline] + fn read(&self) -> Option<T> { + self.slice.first().copied().or(self.last) + } + + #[inline] + fn advance(&mut self) { + match self.slice { + [_, ref remainder @ ..] => { + self.slice = remainder; + } + [] => self.last = None, + } + } +} diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 2f2c7357b00..f3ac679f97b 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -22,8 +22,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::MirPass; use rustc_const_eval::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, ConstValue, Frame, ImmTy, Immediate, - InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, + self, compile_time_machine, AllocId, ConstAllocation, ConstValue, FnArg, Frame, ImmTy, + Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, StackPopCleanup, }; @@ -185,7 +185,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, _abi: CallAbi, - _args: &[OpTy<'tcx>], + _args: &[FnArg<'tcx>], _destination: &PlaceTy<'tcx>, _target: Option<BasicBlock>, _unwind: UnwindAction, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 78fb196358f..5b6cbb5577c 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -532,7 +532,7 @@ impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> { struct DummyMachine; -impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine { +impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine { rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>); type MemoryKind = !; const PANIC_ON_ALLOC_FAIL: bool = true; @@ -557,7 +557,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, _abi: rustc_target::spec::abi::Abi, - _args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>], + _args: &[rustc_const_eval::interpret::FnArg<'tcx, Self::Provenance>], _destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>, _target: Option<BasicBlock>, _unwind: UnwindAction, diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 88a3e028527..aa2ce65e4cc 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -163,7 +163,6 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 073760f394e..f48900c3c52 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -694,7 +694,6 @@ impl CheckAttrVisitor<'_> { | Target::GlobalAsm | Target::TyAlias | Target::OpaqueTy - | Target::ImplTraitPlaceholder | Target::Enum | Target::Variant | Target::Struct diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4fcee9396ed..fe23506b878 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -136,19 +136,7 @@ where fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> { let tcx = self.def_id_visitor.tcx(); - let (trait_ref, assoc_substs) = if tcx.def_kind(projection.def_id) - != DefKind::ImplTraitPlaceholder - { - projection.trait_ref_and_own_substs(tcx) - } else { - // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys - let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id); - let trait_generics = tcx.generics_of(def_id); - ( - ty::TraitRef::new(tcx, def_id, projection.substs.truncate_to(tcx, trait_generics)), - &projection.substs[trait_generics.count()..], - ) - }; + let (trait_ref, assoc_substs) = projection.trait_ref_and_own_substs(tcx); self.visit_trait(trait_ref)?; if V::SHALLOW { ControlFlow::Continue(()) @@ -651,7 +639,6 @@ impl<'tcx> EmbargoVisitor<'tcx> { | DefKind::ForeignTy | DefKind::Fn | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::AssocFn | DefKind::Trait | DefKind::TyParam diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e6ceedddfa1..ff63e4e33cb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -949,7 +949,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { | DefKind::TyAlias | DefKind::ForeignTy | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder | DefKind::TraitAlias | DefKind::AssocTy, _, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 90cb312edd2..f6c7aecf8b0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_errors = |this: &mut Self, res: Option<Res>| { if this.should_report_errs() { let (err, candidates) = - this.smart_resolve_report_errors(path, path, path_span, source, res); + this.smart_resolve_report_errors(path, None, path_span, source, res); let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); @@ -3555,14 +3555,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Before we start looking for candidates, we have to get our hands // on the type user is trying to perform invocation on; basically: // we're transforming `HashMap::new` into just `HashMap`. - let prefix_path = match path.split_last() { - Some((_, path)) if !path.is_empty() => path, + let (following_seg, prefix_path) = match path.split_last() { + Some((last, path)) if !path.is_empty() => (Some(last), path), _ => return Some(parent_err), }; let (mut err, candidates) = this.smart_resolve_report_errors( prefix_path, - path, + following_seg, path_span, PathSource::Type, None, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c0e3f1aaf01..78ef72a7e34 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -332,15 +332,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { pub(crate) fn smart_resolve_partial_mod_path_errors( &mut self, prefix_path: &[Segment], - path: &[Segment], + following_seg: Option<&Segment>, ) -> Vec<ImportSuggestion> { - let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 { - path.get(prefix_path.len()) - } else { - None - }; if let Some(segment) = prefix_path.last() && - let Some(next_seg) = next_seg { + let Some(following_seg) = following_seg + { let candidates = self.r.lookup_import_candidates( segment.ident, Namespace::TypeNS, @@ -353,9 +349,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter(|candidate| { if let Some(def_id) = candidate.did && let Some(module) = self.r.get_module(def_id) { - self.r.resolutions(module).borrow().iter().any(|(key, _r)| { - key.ident.name == next_seg.ident.name - }) + Some(def_id) != self.parent_scope.module.opt_def_id() && + self.r.resolutions(module).borrow().iter().any(|(key, _r)| { + key.ident.name == following_seg.ident.name + }) } else { false } @@ -371,7 +368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { pub(crate) fn smart_resolve_report_errors( &mut self, path: &[Segment], - full_path: &[Segment], + following_seg: Option<&Segment>, span: Span, source: PathSource<'_>, res: Option<Res>, @@ -412,8 +409,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { return (err, Vec::new()); } - let (found, candidates) = - self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error); + let (found, candidates) = self.try_lookup_name_relaxed( + &mut err, + source, + path, + following_seg, + span, + res, + &base_error, + ); if found { return (err, candidates); } @@ -422,7 +426,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // if we have suggested using pattern matching, then don't add needless suggestions // for typos. - fallback |= self.suggest_typo(&mut err, source, path, span, &base_error); + fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error); if fallback { // Fallback label. @@ -519,7 +523,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], - full_path: &[Segment], + following_seg: Option<&Segment>, span: Span, res: Option<Res>, base_error: &BaseError, @@ -590,8 +594,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } // Try finding a suitable replacement. - let typo_sugg = - self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion(); + let typo_sugg = self + .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected) + .to_opt_suggestion(); if path.len() == 1 && self.self_type_is_available() { if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call()) @@ -690,7 +695,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } if candidates.is_empty() { - candidates = self.smart_resolve_partial_mod_path_errors(path, full_path); + candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg); } return (false, candidates); @@ -776,12 +781,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], + following_seg: Option<&Segment>, span: Span, base_error: &BaseError, ) -> bool { let is_expected = &|res| source.is_expected(res); let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + let typo_sugg = + self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected); let is_in_same_file = &|sp1, sp2| { let source_map = self.r.tcx.sess.source_map(); let file1 = source_map.span_to_filename(sp1); @@ -1715,6 +1722,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn lookup_typo_candidate( &mut self, path: &[Segment], + following_seg: Option<&Segment>, ns: Namespace, filter_fn: &impl Fn(Res) -> bool, ) -> TypoCandidate { @@ -1793,6 +1801,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } + // if next_seg is present, let's filter everything that does not continue the path + if let Some(following_seg) = following_seg { + names.retain(|suggestion| match suggestion.res { + Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => { + // FIXME: this is not totally accurate, but mostly works + suggestion.candidate != following_seg.ident.name + } + Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else( + || false, + |module| { + self.r + .resolutions(module) + .borrow() + .iter() + .any(|(key, _)| key.ident.name == following_seg.ident.name) + }, + ), + _ => true, + }); + } let name = path[path.len() - 1].ident.name; // Make sure error reporting is deterministic. names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7840a0ecf0b..87d67c099ce 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1583,9 +1583,6 @@ options! { "what location details should be tracked when using caller_location, either \ `none`, or a comma separated list of location details, for which \ valid options are `file`, `line`, and `column` (default: `file,line,column`)"), - lower_impl_trait_in_trait_to_assoc_ty: bool = (false, parse_bool, [TRACKED], - "modify the lowering strategy for `impl Trait` in traits so that they are lowered to \ - generic associated types"), ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index a6e6de5f785..80d4e7ed02f 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,14 +4,18 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_hir = { path = "../rustc_hir" } +# Use optional dependencies for rustc_* in order to support building this crate separately. +rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } +rustc_target = { path = "../rustc_target", optional = true } tracing = "0.1" scoped-tls = "1.0" [features] default = [ + "rustc_hir", "rustc_middle", "rustc_span", + "rustc_target", ] diff --git a/compiler/rustc_smir/rust-toolchain.toml b/compiler/rustc_smir/rust-toolchain.toml index 157dfd620ee..d75e8e33b1c 100644 --- a/compiler/rustc_smir/rust-toolchain.toml +++ b/compiler/rustc_smir/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-02-28" +channel = "nightly-2023-06-14" components = [ "rustfmt", "rustc-dev" ] diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index fb03633b99b..8450bb73119 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -13,6 +13,17 @@ #![cfg_attr(not(feature = "default"), feature(rustc_private))] #![feature(local_key_cell_methods)] #![feature(ptr_metadata)] +#![feature(type_alias_impl_trait)] // Used to define opaque types. + +// Declare extern rustc_* crates to enable building this crate separately from the compiler. +#[cfg(not(feature = "default"))] +extern crate rustc_hir; +#[cfg(not(feature = "default"))] +extern crate rustc_middle; +#[cfg(not(feature = "default"))] +extern crate rustc_span; +#[cfg(not(feature = "default"))] +extern crate rustc_target; pub mod rustc_internal; pub mod stable_mir; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 609a04d263c..87e0b211556 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -3,6 +3,9 @@ //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! until stable MIR is complete. +use std::fmt::Debug; +use std::string::ToString; + use crate::{ rustc_smir::Tables, stable_mir::{self, with}, @@ -49,3 +52,10 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f); } + +/// A type that provides internal information but that can still be used for debug purpose. +pub type Opaque = impl Debug + ToString + Clone; + +pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque { + format!("{value:?}") +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 85d5bb00c4e..f22c620021e 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,11 +7,13 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. +use crate::rustc_internal::{self, opaque}; use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::stable_mir::{self, Context}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_target::abi::FieldIdx; use tracing::debug; impl<'tcx> Context for Tables<'tcx> { @@ -137,11 +139,21 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate { stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local } } -pub trait Stable { +/// Trait used to convert between an internal MIR type to a Stable MIR type. +pub(crate) trait Stable { + /// The stable representation of the type implementing Stable. type T; + /// Converts an object to the equivalent Stable MIR representation. fn stable(&self) -> Self::T; } +impl Stable for DefId { + type T = stable_mir::CrateItem; + fn stable(&self) -> Self::T { + rustc_internal::crate_item(*self) + } +} + impl<'tcx> Stable for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; fn stable(&self) -> Self::T { @@ -173,12 +185,18 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> { match self { Use(op) => stable_mir::mir::Rvalue::Use(op.stable()), Repeat(_, _) => todo!(), - Ref(_, _, _) => todo!(), - ThreadLocalRef(_) => todo!(), - AddressOf(_, _) => todo!(), - Len(_) => todo!(), + Ref(region, kind, place) => { + stable_mir::mir::Rvalue::Ref(opaque(region), kind.stable(), place.stable()) + } + ThreadLocalRef(def_id) => stable_mir::mir::Rvalue::ThreadLocalRef(def_id.stable()), + AddressOf(mutability, place) => { + stable_mir::mir::Rvalue::AddressOf(mutability.stable(), place.stable()) + } + Len(place) => stable_mir::mir::Rvalue::Len(place.stable()), Cast(_, _, _) => todo!(), - BinaryOp(_, _) => todo!(), + BinaryOp(bin_op, ops) => { + stable_mir::mir::Rvalue::BinaryOp(bin_op.stable(), ops.0.stable(), ops.1.stable()) + } CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( bin_op.stable(), ops.0.stable(), @@ -186,14 +204,119 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> { ), NullaryOp(_, _) => todo!(), UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()), - Discriminant(_) => todo!(), + Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable()), Aggregate(_, _) => todo!(), ShallowInitBox(_, _) => todo!(), - CopyForDeref(_) => todo!(), + CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable()), + } + } +} + +impl Stable for mir::Mutability { + type T = stable_mir::mir::Mutability; + fn stable(&self) -> Self::T { + use mir::Mutability::*; + match *self { + Not => stable_mir::mir::Mutability::Not, + Mut => stable_mir::mir::Mutability::Mut, + } + } +} + +impl Stable for mir::BorrowKind { + type T = stable_mir::mir::BorrowKind; + fn stable(&self) -> Self::T { + use mir::BorrowKind::*; + match *self { + Shared => stable_mir::mir::BorrowKind::Shared, + Shallow => stable_mir::mir::BorrowKind::Shallow, + Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable() }, + } + } +} + +impl Stable for mir::MutBorrowKind { + type T = stable_mir::mir::MutBorrowKind; + fn stable(&self) -> Self::T { + use mir::MutBorrowKind::*; + match *self { + Default => stable_mir::mir::MutBorrowKind::Default, + TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow, + ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture, + } + } +} + +impl<'tcx> Stable for mir::NullOp<'tcx> { + type T = stable_mir::mir::NullOp; + fn stable(&self) -> Self::T { + use mir::NullOp::*; + match self { + SizeOf => stable_mir::mir::NullOp::SizeOf, + AlignOf => stable_mir::mir::NullOp::AlignOf, + OffsetOf(indices) => { + stable_mir::mir::NullOp::OffsetOf(indices.iter().map(|idx| idx.stable()).collect()) + } + } + } +} + +impl Stable for mir::CastKind { + type T = stable_mir::mir::CastKind; + fn stable(&self) -> Self::T { + use mir::CastKind::*; + match self { + PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress, + PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress, + PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable()), + DynStar => stable_mir::mir::CastKind::DynStar, + IntToInt => stable_mir::mir::CastKind::IntToInt, + FloatToInt => stable_mir::mir::CastKind::FloatToInt, + FloatToFloat => stable_mir::mir::CastKind::FloatToFloat, + IntToFloat => stable_mir::mir::CastKind::IntToFloat, + PtrToPtr => stable_mir::mir::CastKind::PtrToPtr, + FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr, + Transmute => stable_mir::mir::CastKind::Transmute, } } } +impl Stable for ty::adjustment::PointerCoercion { + type T = stable_mir::mir::PointerCoercion; + fn stable(&self) -> Self::T { + use ty::adjustment::PointerCoercion; + match self { + PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer, + PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer, + PointerCoercion::ClosureFnPointer(unsafety) => { + stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable()) + } + PointerCoercion::MutToConstPointer => { + stable_mir::mir::PointerCoercion::MutToConstPointer + } + PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer, + PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize, + } + } +} + +impl Stable for rustc_hir::Unsafety { + type T = stable_mir::mir::Safety; + fn stable(&self) -> Self::T { + match self { + rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe, + rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal, + } + } +} + +impl Stable for FieldIdx { + type T = usize; + fn stable(&self) -> Self::T { + self.as_usize() + } +} + impl<'tcx> Stable for mir::Operand<'tcx> { type T = stable_mir::mir::Operand; fn stable(&self) -> Self::T { @@ -229,34 +352,38 @@ impl Stable for mir::UnwindAction { } } -fn rustc_assert_msg_to_msg<'tcx>( - assert_message: &rustc_middle::mir::AssertMessage<'tcx>, -) -> stable_mir::mir::AssertMessage { - use rustc_middle::mir::AssertKind; - match assert_message { - AssertKind::BoundsCheck { len, index } => { - stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() } - } - AssertKind::Overflow(bin_op, op1, op2) => { - stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable()) - } - AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), - AssertKind::DivisionByZero(op) => { - stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) - } - AssertKind::RemainderByZero(op) => { - stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) - } - AssertKind::ResumedAfterReturn(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) - } - AssertKind::ResumedAfterPanic(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) - } - AssertKind::MisalignedPointerDereference { required, found } => { - stable_mir::mir::AssertMessage::MisalignedPointerDereference { - required: required.stable(), - found: found.stable(), +impl<'tcx> Stable for mir::AssertMessage<'tcx> { + type T = stable_mir::mir::AssertMessage; + fn stable(&self) -> Self::T { + use rustc_middle::mir::AssertKind; + match self { + AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { + len: len.stable(), + index: index.stable(), + }, + AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( + bin_op.stable(), + op1.stable(), + op2.stable(), + ), + AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), + AssertKind::DivisionByZero(op) => { + stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) + } + AssertKind::RemainderByZero(op) => { + stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) + } + AssertKind::ResumedAfterReturn(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) + } + AssertKind::ResumedAfterPanic(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) + } + AssertKind::MisalignedPointerDereference { required, found } => { + stable_mir::mir::AssertMessage::MisalignedPointerDereference { + required: required.stable(), + found: found.stable(), + } } } } @@ -381,7 +508,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> { Assert { cond, expected, msg, target, unwind } => Terminator::Assert { cond: cond.stable(), expected: *expected, - msg: rustc_assert_msg_to_msg(msg), + msg: msg.stable(), target: target.as_usize(), unwind: unwind.stable(), }, diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 468e915d1a0..fa3b0d6c559 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -1,4 +1,5 @@ -use crate::stable_mir::ty::Ty; +use crate::rustc_internal::Opaque; +use crate::stable_mir::{self, ty::Ty}; #[derive(Clone, Debug)] pub struct Body { @@ -136,12 +137,98 @@ pub enum Statement { Nop, } +type Region = Opaque; + // FIXME this is incomplete #[derive(Clone, Debug)] pub enum Rvalue { - Use(Operand), + /// Creates a pointer with the indicated mutability to the place. + /// + /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like + /// `&raw v` or `addr_of!(v)`. + AddressOf(Mutability, Place), + + /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second + /// parameter may be a `usize` as well. + /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + /// matching, up to the usual caveat of the lifetimes in function pointers. + /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + /// truncated as needed. + /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + /// types and return a value of that type. + /// * The remaining operations accept signed integers, unsigned integers, or floats with + /// matching types and return a value of that type. + BinaryOp(BinOp, Operand, Operand), + + /// Performs essentially all of the casts that can be performed via `as`. + /// + /// This allows for casts from/to a variety of types. + Cast(CastKind, Operand, Ty), + + /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. + /// + /// For addition, subtraction, and multiplication on integers the error condition is set when + /// the infinite precision result would not be equal to the actual result. CheckedBinaryOp(BinOp, Operand, Operand), + + /// A CopyForDeref is equivalent to a read from a place. + /// When such a read happens, it is guaranteed that the only use of the returned value is a + /// deref operation, immediately followed by one or more projections. + CopyForDeref(Place), + + /// Computes the discriminant of the place, returning it as an integer of type + /// [`discriminant_ty`]. Returns zero for types without discriminant. + /// + /// The validity requirements for the underlying value are undecided for this rvalue, see + /// [#91095]. Note too that the value of the discriminant is not the same thing as the + /// variant index; use [`discriminant_for_variant`] to convert. + /// + /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty + /// [#91095]: https://github.com/rust-lang/rust/issues/91095 + /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant + Discriminant(Place), + + /// Yields the length of the place, as a `usize`. + /// + /// If the type of the place is an array, this is the array length. For slices (`[T]`, not + /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is + /// ill-formed for places of other types. + Len(Place), + + /// Creates a reference to the place. + Ref(Region, BorrowKind, Place), + + /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. + /// + /// This is different from a normal transmute because dataflow analysis will treat the box as + /// initialized but its content as uninitialized. Like other pointer casts, this in general + /// affects alias analysis. + ShallowInitBox(Operand, Ty), + + /// Creates a pointer/reference to the given thread local. + /// + /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a + /// `*const T`, and if neither of those apply a `&T`. + /// + /// **Note:** This is a runtime operation that actually executes code and is in this sense more + /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to + /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. + /// + /// **Needs clarification**: Are there weird additional semantics here related to the runtime + /// nature of this operation? + ThreadLocalRef(stable_mir::CrateItem), + + /// Exactly like `BinaryOp`, but less operands. + /// + /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; + /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds + /// return a value with the same type as their operand. UnaryOp(UnOp, Operand), + + /// Yields the operand unchanged + Use(Operand), } #[derive(Clone, Debug)] @@ -157,8 +244,98 @@ pub struct Place { pub projection: String, } +type FieldIdx = usize; + #[derive(Clone, Debug)] pub struct SwitchTarget { pub value: u128, pub target: usize, } + +#[derive(Clone, Debug)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, + + /// Data is mutable and not aliasable. + Mut { + /// `true` if this borrow arose from method-call auto-ref + kind: MutBorrowKind, + }, +} + +#[derive(Clone, Debug)] +pub enum MutBorrowKind { + Default, + TwoPhaseBorrow, + ClosureCapture, +} + +#[derive(Clone, Debug)] +pub enum Mutability { + Not, + Mut, +} + +#[derive(Clone, Debug)] +pub enum Safety { + Unsafe, + Normal, +} + +#[derive(Clone, Debug)] +pub enum PointerCoercion { + /// Go from a fn-item type to a fn-pointer type. + ReifyFnPointer, + + /// Go from a safe fn pointer to an unsafe fn pointer. + UnsafeFnPointer, + + /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. + /// It cannot convert a closure that requires unsafe. + ClosureFnPointer(Safety), + + /// Go from a mut raw pointer to a const raw pointer. + MutToConstPointer, + + /// Go from `*const [T; N]` to `*const T` + ArrayToPointer, + + /// Unsize a pointer/reference value, e.g., `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + /// This will do things like convert thin pointers to fat + /// pointers, or convert structs containing thin pointers to + /// structs containing fat pointers, or convert between fat + /// pointers. + Unsize, +} + +#[derive(Clone, Debug)] +pub enum CastKind { + PointerExposeAddress, + PointerFromExposedAddress, + PointerCoercion(PointerCoercion), + DynStar, + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, +} + +#[derive(Clone, Debug)] +pub enum NullOp { + /// Returns the size of a value of that type. + SizeOf, + /// Returns the minimum alignment of a type. + AlignOf, + /// Returns the offset of a field. + OffsetOf(Vec<FieldIdx>), +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5c6d43e50ea..d655276a991 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1152,8 +1152,10 @@ symbols! { profiler_runtime, ptr, ptr_cast_mut, + ptr_const_is_null, ptr_from_ref, ptr_guaranteed_cmp, + ptr_is_null, ptr_mask, ptr_null, ptr_null_mut, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f342180590f..4dc06d2bfac 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1640,6 +1640,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) .into(), }; + // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice + // to deeply normalize this type. let normalized_term = ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a10bca31ff1..4ccfb54ff7c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -131,8 +131,6 @@ enum ProjectionCandidate<'tcx> { /// From an "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), - - ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>), } enum ProjectionCandidateSet<'tcx> { @@ -1472,8 +1470,6 @@ fn project<'cx, 'tcx>( let mut candidates = ProjectionCandidateSet::None; - assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates); - // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. @@ -1499,7 +1495,7 @@ fn project<'cx, 'tcx>( ProjectionCandidateSet::None => { let tcx = selcx.tcx(); let term = match tcx.def_kind(obligation.predicate.def_id) { - DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection( + DefKind::AssocTy => Ty::new_projection( tcx, obligation.predicate.def_id, obligation.predicate.substs, @@ -1530,47 +1526,6 @@ fn project<'cx, 'tcx>( } } -/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the -/// corresponding trait ref. If this yields an `impl`, then we're able to project -/// to a concrete type, since we have an `impl`'s method to provide the RPITIT. -fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionCandidateSet<'tcx>, -) { - let tcx = selcx.tcx(); - if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); - - let trait_def_id = tcx.parent(trait_fn_def_id); - let trait_substs = - obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id)); - let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs); - - let _ = selcx.infcx.commit_if_ok(|_| { - match selcx.select(&obligation.with(tcx, trait_predicate)) { - Ok(Some(super::ImplSource::UserDefined(data))) => { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); - Ok(()) - } - Ok(None) => { - candidate_set.mark_ambiguous(); - Err(()) - } - Ok(Some(_)) => { - // Don't know enough about the impl to provide a useful signature - Err(()) - } - Err(e) => { - debug!(error = ?e, "selection error"); - candidate_set.mark_error(e); - Err(()) - } - } - }); - } -} - /// The first thing we have to do is scan through the parameter /// environment to see whether there are any projection predicates /// there that can answer this question. @@ -1739,11 +1694,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { - // Can't assemble candidate from impl for RPITIT - if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - return; - } - // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let trait_ref = obligation.predicate.trait_ref(selcx.tcx()); @@ -2012,9 +1962,6 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } - ProjectionCandidate::ImplTraitInTrait(data) => { - confirm_impl_trait_in_trait_candidate(selcx, obligation, data) - } }; // When checking for cycle during evaluation, we compare predicates with @@ -2240,8 +2187,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let ty::Closure(_, substs) = - selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() + let ty::Closure(_, substs) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() else { unreachable!() }; @@ -2419,103 +2365,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( } } -fn confirm_impl_trait_in_trait_candidate<'tcx>( - selcx: &mut SelectionContext<'_, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let mut obligations = data.nested; - - let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); - let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) { - Ok(assoc_ty) => assoc_ty, - Err(guar) => return Progress::error(tcx, guar), - }; - // We don't support specialization for RPITITs anyways... yet. - // Also don't try to project to an RPITIT that has no value - if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() { - return Progress { term: Ty::new_misc_error(tcx).into(), obligations }; - } - - // Use the default `impl Trait` for the trait, e.g., for a default trait body - if leaf_def.item.container == ty::AssocItemContainer::TraitContainer { - return Progress { - term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs) - .into(), - obligations, - }; - } - - // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque}, - // since `data.substs` are the impl substs. - let impl_fn_substs = - obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs); - let impl_fn_substs = translate_substs( - selcx.infcx, - obligation.param_env, - data.impl_def_id, - impl_fn_substs, - leaf_def.defining_node, - ); - - if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) { - let err = Ty::new_error_with_message( - tcx, - obligation.cause.span, - "impl method and trait method have different parameters", - ); - return Progress { term: err.into(), obligations }; - } - - let impl_fn_def_id = leaf_def.item.def_id; - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - super::ItemObligation(impl_fn_def_id), - ); - let predicates = normalize_with_depth_to( - selcx, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs), - &mut obligations, - ); - obligations.extend(predicates.into_iter().map(|(pred, span)| { - Obligation::with_depth( - tcx, - ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - if span.is_dummy() { - super::ItemObligation(impl_fn_def_id) - } else { - super::BindingObligation(impl_fn_def_id, span) - }, - ), - obligation.recursion_depth + 1, - obligation.param_env, - pred, - ) - })); - - let ty = normalize_with_depth_to( - selcx, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else( - |guar| Ty::new_error(tcx, guar), - |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs), - ), - &mut obligations, - ); - - Progress { term: ty.into(), obligations } -} - // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. fn assoc_ty_own_obligations<'cx, 'tcx>( diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 897e7aad48b..7e22ef89ed3 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -24,70 +24,54 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => { - if tcx.lower_impl_trait_in_trait_to_assoc_ty() { - // We collect RPITITs for each trait method's return type and create a - // corresponding associated item using associated_types_for_impl_traits_in_associated_fn - // query. - tcx.arena.alloc_from_iter( - trait_item_refs - .iter() - .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()) - .chain( - trait_item_refs - .iter() - .filter(|trait_item_ref| { - matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. }) - }) - .flat_map(|trait_item_ref| { - let trait_fn_def_id = - trait_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_types_for_impl_traits_in_associated_fn( - trait_fn_def_id, - ) - }) - .map(|def_id| *def_id), - ), - ) - } else { - tcx.arena.alloc_from_iter( - trait_item_refs - .iter() - .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), - ) - } + // We collect RPITITs for each trait method's return type and create a + // corresponding associated item using associated_types_for_impl_traits_in_associated_fn + // query. + tcx.arena.alloc_from_iter( + trait_item_refs + .iter() + .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()) + .chain( + trait_item_refs + .iter() + .filter(|trait_item_ref| { + matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|trait_item_ref| { + let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_types_for_impl_traits_in_associated_fn( + trait_fn_def_id, + ) + }) + .map(|def_id| *def_id), + ), + ) } hir::ItemKind::Impl(ref impl_) => { - if tcx.lower_impl_trait_in_trait_to_assoc_ty() { - // We collect RPITITs for each trait method's return type, on the impl side too and - // create a corresponding associated item using - // associated_types_for_impl_traits_in_associated_fn query. - tcx.arena.alloc_from_iter( - impl_ - .items - .iter() - .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()) - .chain(impl_.of_trait.iter().flat_map(|_| { - impl_ - .items - .iter() - .filter(|impl_item_ref| { - matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. }) - }) - .flat_map(|impl_item_ref| { - let impl_fn_def_id = - impl_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_types_for_impl_traits_in_associated_fn( - impl_fn_def_id, - ) - }) - .map(|def_id| *def_id) - })), - ) - } else { - tcx.arena.alloc_from_iter( - impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), - ) - } + // We collect RPITITs for each trait method's return type, on the impl side too and + // create a corresponding associated item using + // associated_types_for_impl_traits_in_associated_fn query. + tcx.arena.alloc_from_iter( + impl_ + .items + .iter() + .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()) + .chain(impl_.of_trait.iter().flat_map(|_| { + impl_ + .items + .iter() + .filter(|impl_item_ref| { + matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|impl_item_ref| { + let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_types_for_impl_traits_in_associated_fn( + impl_fn_def_id, + ) + }) + .map(|def_id| *def_id) + })), + ) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 10dec9a7a32..2822595a8a7 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -75,7 +75,6 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' | DefKind::ForeignMod | DefKind::AnonConst | DefKind::InlineConst - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 570c3b245cd..87dfacc4c2d 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -318,7 +318,6 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::ExternCrate | DefKind::Use | DefKind::ForeignMod - | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 6e5c50492c6..43e3c99fb57 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -282,11 +282,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { // If we're lowering to associated item, install the opaque type which is just // the `type_of` of the trait's associated item. If we're using the old lowering // strategy, then just reinterpret the associated type like an opaque :^) - let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { - self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs) - } else { - Ty::new_alias(self.tcx,ty::Opaque, shifted_alias_ty) - }; + let default_ty = self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs); self.predicates.push( ty::Binder::bind_with_vars( @@ -408,9 +404,7 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32 }; // The last field of the structure has to exist and contain type/const parameters. - let Some((tail_field, prefix_fields)) = - def.non_enum_variant().fields.raw.split_last() else - { + let Some((tail_field, prefix_fields)) = def.non_enum_variant().fields.raw.split_last() else { return BitSet::new_empty(num_params); }; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 878a6b784ed..9ca26d18ae1 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -31,6 +31,7 @@ mod macros; mod structural_impls; pub use codec::*; +pub use structural_impls::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use sty::*; pub use ty_info::*; @@ -39,41 +40,41 @@ pub trait HashStableContext {} pub trait Interner: Sized { type AdtDef: Clone + Debug + Hash + Ord; - type SubstsRef: Clone + Debug + Hash + Ord; + type SubstsRef: Clone + DebugWithInfcx<Self> + Hash + Ord; type DefId: Clone + Debug + Hash + Ord; type Binder<T>; - type Ty: Clone + Debug + Hash + Ord; - type Const: Clone + Debug + Hash + Ord; - type Region: Clone + Debug + Hash + Ord; + type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Const: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Region: Clone + DebugWithInfcx<Self> + Hash + Ord; type Predicate; type TypeAndMut: Clone + Debug + Hash + Ord; type Mutability: Clone + Debug + Hash + Ord; type Movability: Clone + Debug + Hash + Ord; - type PolyFnSig: Clone + Debug + Hash + Ord; - type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord; - type BinderListTy: Clone + Debug + Hash + Ord; + type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord; + type ListBinderExistentialPredicate: Clone + DebugWithInfcx<Self> + Hash + Ord; + type BinderListTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ListTy: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; - type AliasTy: Clone + Debug + Hash + Ord; + type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; type PlaceholderType: Clone + Debug + Hash + Ord; + type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord; type ErrorGuaranteed: Clone + Debug + Hash + Ord; type PredicateKind: Clone + Debug + Hash + PartialEq + Eq; type AllocId: Clone + Debug + Hash + Ord; - type InferConst: Clone + Debug + Hash + Ord; - type AliasConst: Clone + Debug + Hash + Ord; + type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord; + type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderConst: Clone + Debug + Hash + Ord; type ParamConst: Clone + Debug + Hash + Ord; type BoundConst: Clone + Debug + Hash + Ord; - type InferTy: Clone + Debug + Hash + Ord; type ValueConst: Clone + Debug + Hash + Ord; - type ExprConst: Clone + Debug + Hash + Ord; + type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord; type EarlyBoundRegion: Clone + Debug + Hash + Ord; type BoundRegion: Clone + Debug + Hash + Ord; type FreeRegion: Clone + Debug + Hash + Ord; - type RegionVid: Clone + Debug + Hash + Ord; + type RegionVid: Clone + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability); @@ -775,20 +776,6 @@ impl fmt::Debug for FloatVid { } } -impl fmt::Debug for InferTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InferTy::*; - match *self { - TyVar(ref v) => v.fmt(f), - IntVar(ref v) => v.fmt(f), - FloatVar(ref v) => v.fmt(f), - FreshTy(v) => write!(f, "FreshTy({v:?})"), - FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"), - FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"), - } - } -} - impl fmt::Debug for Variance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 1e42175f6e3..1a2d6d64eb0 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -4,12 +4,13 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy}; +use crate::{ConstKind, FloatTy, InferTy, IntTy, Interner, UintTy, UniverseIndex}; use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use core::fmt; +use std::marker::PhantomData; use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// @@ -165,6 +166,116 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix } } +/////////////////////////////////////////////////// +// Debug impls + +pub trait InferCtxtLike<I: Interner> { + fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>; + fn universe_of_lt(&self, lt: I::RegionVid) -> Option<UniverseIndex>; + fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>; +} + +impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible { + fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> { + match *self {} + } + fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> { + match *self {} + } + fn universe_of_lt(&self, _lt: <I as Interner>::RegionVid) -> Option<UniverseIndex> { + match *self {} + } +} + +pub trait DebugWithInfcx<I: Interner>: fmt::Debug { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result; +} + +impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f) + } +} +impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + match f.alternate() { + true => { + write!(f, "[\n")?; + for element in this.data.iter() { + write!(f, "{:?},\n", &this.wrap(element))?; + } + write!(f, "]") + } + false => { + write!(f, "[")?; + if this.data.len() > 0 { + for element in &this.data[..(this.data.len() - 1)] { + write!(f, "{:?}, ", &this.wrap(element))?; + } + if let Some(element) = this.data.last() { + write!(f, "{:?}", &this.wrap(element))?; + } + } + write!(f, "]") + } + } + } +} + +pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> { + pub data: T, + pub infcx: Option<&'a InfCtx>, + _interner: PhantomData<I>, +} + +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {} +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> { + fn clone(&self) -> Self { + Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner } + } +} + +impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> { + pub fn new_no_ctx(data: T) -> Self { + Self { data, infcx: None, _interner: PhantomData } + } +} + +impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> { + pub fn new(data: T, infcx: &'a InfCtx) -> Self { + Self { data, infcx: Some(infcx), _interner: PhantomData } + } + + pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> { + OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData } + } + + pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> { + OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData } + } + + pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> { + OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData } + } +} + +impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug + for OptWithInfcx<'_, I, InfCtx, T> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DebugWithInfcx::fmt(self.as_ref(), f) + } +} + impl fmt::Debug for IntTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name_str()) @@ -183,20 +294,60 @@ impl fmt::Debug for FloatTy { } } +impl fmt::Debug for InferTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InferTy::*; + match *self { + TyVar(ref v) => v.fmt(f), + IntVar(ref v) => v.fmt(f), + FloatVar(ref v) => v.fmt(f), + FreshTy(v) => write!(f, "FreshTy({v:?})"), + FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"), + FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"), + } + } +} +impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + use InferTy::*; + match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) { + None => write!(f, "{:?}", this.data), + Some(universe) => match *this.data { + TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()), + IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => { + unreachable!() + } + }, + } + } +} + impl<I: Interner> fmt::Debug for ConstKind<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} +impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { use ConstKind::*; - match self { + + match this.data { Param(param) => write!(f, "{param:?}"), - Infer(var) => write!(f, "{var:?}"), + Infer(var) => write!(f, "{:?}", &this.wrap(var)), Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()), Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => { - write!(f, "{uv:?}") + write!(f, "{:?}", &this.wrap(uv)) } Value(valtree) => write!(f, "{valtree:?}"), Error(_) => write!(f, "{{const error}}"), - Expr(expr) => write!(f, "{expr:?}"), + Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), } } } diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index b696f9b9b59..416e8a3d2d2 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -3,7 +3,6 @@ use std::cmp::Ordering; use std::{fmt, hash}; -use crate::DebruijnIndex; use crate::FloatTy; use crate::HashStableContext; use crate::IntTy; @@ -11,6 +10,7 @@ use crate::Interner; use crate::TyDecoder; use crate::TyEncoder; use crate::UintTy; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; use self::RegionKind::*; use self::TyKind::*; @@ -503,42 +503,48 @@ impl<I: Interner> hash::Hash for TyKind<I> { } } -// This is manually implemented because a derive would require `I: Debug` -impl<I: Interner> fmt::Debug for TyKind<I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { +impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> fmt::Result { + match this.data { Bool => write!(f, "bool"), Char => write!(f, "char"), Int(i) => write!(f, "{i:?}"), Uint(u) => write!(f, "{u:?}"), Float(float) => write!(f, "{float:?}"), - Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s), + Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, &this.wrap(s)), Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), Str => write!(f, "str"), - Array(t, c) => write!(f, "[{t:?}; {c:?}]"), - Slice(t) => write!(f, "[{t:?}]"), + Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), + Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), RawPtr(p) => { let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone()); match I::mutability_is_mut(mutbl) { true => write!(f, "*mut "), false => write!(f, "*const "), }?; - write!(f, "{ty:?}") + write!(f, "{:?}", &this.wrap(ty)) } Ref(r, t, m) => match I::mutability_is_mut(m.clone()) { - true => write!(f, "&{r:?} mut {t:?}"), - false => write!(f, "&{r:?} {t:?}"), + true => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)), + false => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)), }, - FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s), - FnPtr(s) => write!(f, "{s:?}"), + FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, &this.wrap(s)), + FnPtr(s) => write!(f, "{:?}", &this.wrap(s)), Dynamic(p, r, repr) => match repr { - DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"), - DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"), + DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)), + DynKind::DynStar => { + write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r)) + } }, - Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), - Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), - GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), - GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), + Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)), + Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, &this.wrap(s), m), + GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", &this.wrap(g)), + GeneratorWitnessMIR(d, s) => { + f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, &this.wrap(s)) + } Never => write!(f, "!"), Tuple(t) => { let mut iter = t.clone().into_iter(); @@ -547,28 +553,34 @@ impl<I: Interner> fmt::Debug for TyKind<I> { match iter.next() { None => return write!(f, ")"), - Some(ty) => write!(f, "{ty:?}")?, + Some(ty) => write!(f, "{:?}", &this.wrap(ty))?, }; match iter.next() { None => return write!(f, ",)"), - Some(ty) => write!(f, "{ty:?})")?, + Some(ty) => write!(f, "{:?})", &this.wrap(ty))?, } for ty in iter { - write!(f, ", {ty:?}")?; + write!(f, ", {:?}", &this.wrap(ty))?; } write!(f, ")") } - Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), + Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, &this.wrap(a)), Param(p) => write!(f, "{p:?}"), Bound(d, b) => crate::debug_bound_var(f, *d, b), Placeholder(p) => write!(f, "{p:?}"), - Infer(t) => write!(f, "{t:?}"), + Infer(t) => write!(f, "{:?}", this.wrap(t)), TyKind::Error(_) => write!(f, "{{type error}}"), } } } +// This is manually implemented because a derive would require `I: Debug` +impl<I: Interner> fmt::Debug for TyKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} // This is manually implemented because a derive would require `I: Encodable` impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I> @@ -1356,21 +1368,23 @@ impl<I: Interner> hash::Hash for RegionKind<I> { } } -// This is manually implemented because a derive would require `I: Debug` -impl<I: Interner> fmt::Debug for RegionKind<I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { +impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { + fn fmt<InfCtx: InferCtxtLike<I>>( + this: OptWithInfcx<'_, I, InfCtx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match this.data { ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"), ReLateBound(binder_id, bound_region) => { write!(f, "ReLateBound({binder_id:?}, {bound_region:?})") } - ReFree(fr) => fr.fmt(f), + ReFree(fr) => write!(f, "{fr:?}"), ReStatic => f.write_str("ReStatic"), - ReVar(vid) => vid.fmt(f), + ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)), RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"), @@ -1380,6 +1394,11 @@ impl<I: Interner> fmt::Debug for RegionKind<I> { } } } +impl<I: Interner> fmt::Debug for RegionKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + OptWithInfcx::new_no_ctx(self).fmt(f) + } +} // This is manually implemented because a derive would require `I: Encodable` impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I> |
